Fix for UBSan build
[platform/upstream/doxygen.git] / src / index.cpp
1 /******************************************************************************
2  *
3  * $Id: index.cpp,v 1.63 2001/03/19 19:27:40 root Exp $
4  *
5  * Copyright (C) 1997-2012 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby 
9  * granted. No representations are made about the suitability of this software 
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17
18 /** @file
19  *  @brief This file contains functions for the various index pages.
20  */
21
22 #include <stdlib.h>
23
24 #include <qtextstream.h>
25 #include <qdatetime.h>
26 #include <qdir.h>
27 #include <qregexp.h>
28
29 #include "message.h"
30 #include "index.h"
31 #include "doxygen.h"
32 #include "config.h"
33 #include "filedef.h"
34 #include "outputlist.h"
35 #include "util.h"
36 #include "groupdef.h"
37 #include "language.h"
38 #include "htmlgen.h"
39 #include "htmlhelp.h"
40 #include "ftvhelp.h"
41 #include "dot.h"
42 #include "pagedef.h"
43 #include "dirdef.h"
44 #include "vhdldocgen.h"
45 #include "layout.h"
46
47 #define MAX_ITEMS_BEFORE_MULTIPAGE_INDEX 200
48 #define MAX_ITEMS_BEFORE_QUICK_INDEX 30
49
50
51 int annotatedClasses;
52 int annotatedClassesPrinted;
53 int hierarchyClasses;
54 int documentedFiles;
55 int documentedGroups;
56 int documentedNamespaces;
57 int indexedPages;
58 int documentedClassMembers[CMHL_Total];
59 int documentedFileMembers[FMHL_Total];
60 int documentedNamespaceMembers[NMHL_Total];
61 int documentedHtmlFiles;
62 int documentedPages;
63 int documentedDirs;
64
65 static int countClassHierarchy();
66 static void countFiles(int &htmlFiles,int &files);
67 static int countGroups();
68 static int countDirs();
69 static int countNamespaces();
70 static int countAnnotatedClasses(int *cp);
71 static void countRelatedPages(int &docPages,int &indexPages);
72
73 void countDataStructures()
74 {
75   annotatedClasses           = countAnnotatedClasses(&annotatedClassesPrinted); // "classes" + "annotated"
76   hierarchyClasses           = countClassHierarchy();   // "hierarchy"
77   countFiles(documentedHtmlFiles,documentedFiles);      // "files"
78   countRelatedPages(documentedPages,indexedPages);      // "pages"
79   documentedGroups           = countGroups();           // "modules"
80   documentedNamespaces       = countNamespaces();       // "namespaces"
81   documentedDirs             = countDirs();             // "dirs"
82   // "globals"
83   // "namespacemembers"
84   // "functions"
85 }
86
87 static void startIndexHierarchy(OutputList &ol,int level)
88 {
89   ol.pushGeneratorState();
90   ol.disable(OutputGenerator::Man);
91   ol.disable(OutputGenerator::Html);
92   if (level<6) ol.startIndexList();
93   ol.enableAll();
94   ol.disable(OutputGenerator::Latex);
95   ol.disable(OutputGenerator::RTF);
96   ol.startItemList();
97   ol.popGeneratorState();
98 }
99
100 static void endIndexHierarchy(OutputList &ol,int level)
101 {
102   ol.pushGeneratorState();
103   ol.disable(OutputGenerator::Man);
104   ol.disable(OutputGenerator::Html);
105   if (level<6) ol.endIndexList();
106   ol.enableAll();
107   ol.disable(OutputGenerator::Latex);
108   ol.disable(OutputGenerator::RTF);
109   ol.endItemList();
110   ol.popGeneratorState();
111 }
112
113 //----------------------------------------------------------------------------
114
115 class MemberIndexList : public QList<MemberDef>
116 {
117   public:
118     MemberIndexList() : QList<MemberDef>() {}
119     ~MemberIndexList() {}
120     int compareItems(GCI item1, GCI item2)
121     {
122       MemberDef *md1=(MemberDef *)item1;
123       MemberDef *md2=(MemberDef *)item2;
124       return stricmp(md1->name(),md2->name());
125     }
126 };
127
128 #define MEMBER_INDEX_ENTRIES 256
129
130 static MemberIndexList g_memberIndexLetterUsed[CMHL_Total][MEMBER_INDEX_ENTRIES];
131 static MemberIndexList g_fileIndexLetterUsed[FMHL_Total][MEMBER_INDEX_ENTRIES];
132 static MemberIndexList g_namespaceIndexLetterUsed[NMHL_Total][MEMBER_INDEX_ENTRIES];
133
134 //static bool g_classIndexLetterUsed[CHL_Total][256];
135
136 const int maxItemsBeforeQuickIndex = MAX_ITEMS_BEFORE_QUICK_INDEX;
137
138 //----------------------------------------------------------------------------
139
140 //----------------------------------------------------------------------------
141
142 static void startQuickIndexList(OutputList &ol,bool letterTabs=FALSE)
143 {
144   bool fancyTabs = TRUE;
145   if (fancyTabs)
146   {
147     if (letterTabs)
148     {
149       ol.writeString("  <div id=\"navrow4\" class=\"tabs3\">\n"); 
150     }
151     else
152     {
153       ol.writeString("  <div id=\"navrow3\" class=\"tabs2\">\n"); 
154     }
155     ol.writeString("    <ul class=\"tablist\">\n"); 
156   }
157   else
158   {
159     ol.writeString("  <div class=\"qindex\">"); 
160   }
161 }
162
163 static void endQuickIndexList(OutputList &ol)
164 {
165   bool fancyTabs = TRUE;
166   if (fancyTabs)
167   {
168     ol.writeString("    </ul>\n");
169   }
170   ol.writeString("  </div>\n");
171 }
172
173 static void startQuickIndexItem(OutputList &ol,const char *l,
174                                 bool hl,bool compact,bool &first)
175 {
176   bool fancyTabs = TRUE;
177   if (!first && compact && !fancyTabs) ol.writeString(" | ");
178   first=FALSE;
179   if (fancyTabs)
180   {
181     ol.writeString("      <li"); 
182     if (hl) ol.writeString(" class=\"current\"");
183     ol.writeString("><a ");
184   }
185   else
186   {
187     if (!compact) ol.writeString("<li>");
188     if (hl && compact)
189     {
190       ol.writeString("<a class=\"qindexHL\" ");
191     }
192     else
193     {
194       ol.writeString("<a class=\"qindex\" ");
195     }
196   }
197   ol.writeString("href=\""); 
198   ol.writeString(l);
199   ol.writeString("\">");
200   if (fancyTabs)
201   {
202     ol.writeString("<span>");
203   }
204 }
205
206 static void endQuickIndexItem(OutputList &ol)
207 {
208   bool fancyTabs=TRUE;
209   if (fancyTabs) ol.writeString("</span>");
210   ol.writeString("</a>");
211   if (fancyTabs) ol.writeString("</li>\n");
212 }
213
214 // don't make this static as it is called from a template function and some
215 // old compilers don't support calls to static functions from a template.
216 QCString fixSpaces(const QCString &s)
217 {
218   return substitute(s," ","&#160;");
219 }
220
221 void startTitle(OutputList &ol,const char *fileName,Definition *def)
222 {
223   ol.startHeaderSection();
224   if (def) def->writeSummaryLinks(ol);
225   ol.startTitleHead(fileName);
226   ol.pushGeneratorState();
227   ol.disable(OutputGenerator::Man);
228 }
229
230 void endTitle(OutputList &ol,const char *fileName,const char *name)
231 {
232   ol.popGeneratorState();
233   ol.endTitleHead(fileName,name);
234   ol.endHeaderSection();
235 }
236
237 void startFile(OutputList &ol,const char *name,const char *manName,
238                const char *title,HighlightedItem hli,bool additionalIndices,
239                const char *altSidebarName)
240 {
241   static bool disableIndex     = Config_getBool("DISABLE_INDEX");
242   ol.startFile(name,manName,title);
243   ol.startQuickIndices();
244   if (!disableIndex)
245   {
246     ol.writeQuickLinks(TRUE,hli,name);
247   }
248   if (!additionalIndices)
249   {
250     ol.endQuickIndices();
251   }
252   ol.writeSplitBar(altSidebarName ? altSidebarName : name);
253   ol.writeSearchInfo();
254 }
255
256 void endFile(OutputList &ol,bool skipNavIndex,bool skipEndContents,
257              const QCString &navPath)
258 {
259   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
260   ol.pushGeneratorState();
261   ol.disableAllBut(OutputGenerator::Html);
262   if (!skipNavIndex)
263   {
264     if (!skipEndContents) ol.endContents();
265     if (generateTreeView)
266     {
267       ol.writeString("</div><!-- doc-content -->\n");
268     }
269   }
270   ol.writeFooter(navPath); // write the footer
271   ol.popGeneratorState();
272   ol.endFile();
273 }
274
275 void endFileWithNavPath(Definition *d,OutputList &ol)
276 {
277   static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
278   QCString navPath;
279   if (generateTreeView)
280   {
281     ol.pushGeneratorState();
282     ol.disableAllBut(OutputGenerator::Html);
283     ol.writeString("</div><!-- doc-content -->\n");
284     ol.popGeneratorState();
285     navPath = d->navigationPathAsString();
286   }
287   endFile(ol,generateTreeView,TRUE,navPath);
288 }
289
290 //----------------------------------------------------------------------
291 template<class T> 
292 void addMembersToIndex(T *def,LayoutDocManager::LayoutPart part,
293                        const QCString &name,const QCString &anchor,
294                        bool addToIndex=TRUE,bool preventSeparateIndex=FALSE)
295 {
296   bool hasMembers = def->getMemberLists().count()>0 || def->getMemberGroupSDict()!=0;
297   Doxygen::indexList.addContentsItem(hasMembers,name,
298                                      def->getReference(),def->getOutputFileBase(),anchor,
299                                      hasMembers && !preventSeparateIndex,
300                                      addToIndex,
301                                      def);
302   int numClasses=0;
303   ClassSDict *classes = def->getClassSDict();
304   if (classes)
305   {
306      ClassDef *cd;
307      ClassSDict::Iterator it(*classes);
308      for (;(cd=it.current());++it)
309      {
310        if (cd->isLinkable()) numClasses++;
311      }
312   }
313   //printf("addMembersToIndex(def=%s hasMembers=%d numClasses=%d)\n",def->name().data(),hasMembers,numClasses);
314   if (hasMembers || numClasses>0)
315   {
316     Doxygen::indexList.incContentsDepth();
317     QListIterator<LayoutDocEntry> eli(LayoutDocManager::instance().docEntries(part));
318     LayoutDocEntry *lde;
319     for (eli.toFirst();(lde=eli.current());++eli)
320     {
321       if (lde->kind()==LayoutDocEntry::MemberDef)
322       {
323         LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde;
324         MemberList *ml = def->getMemberList(lmd->type);
325         if (ml)
326         {
327           MemberListIterator mi(*ml);
328           MemberDef *md;
329           for (mi.toFirst();(md=mi.current());++mi)
330           {
331             LockingPtr<MemberList> enumList = md->enumFieldList();
332             bool isDir = enumList!=0 && md->isEnumerate();
333             bool isAnonymous = md->name().find('@')!=-1;
334             if (!isAnonymous)
335             {
336               if (md->getOuterScope()==def)
337               {
338                 Doxygen::indexList.addContentsItem(isDir,
339                   md->name(),md->getReference(),md->getOutputFileBase(),md->anchor(),FALSE,addToIndex);
340               }
341               else // inherited member
342               {
343                 Doxygen::indexList.addContentsItem(isDir,
344                   md->name(),def->getReference(),def->getOutputFileBase(),md->anchor(),FALSE,addToIndex);
345               }
346             }
347             if (isDir)
348             {
349               if (!isAnonymous)
350               {
351                 Doxygen::indexList.incContentsDepth();
352               }
353               MemberListIterator emli(*enumList);
354               MemberDef *emd;
355               for (emli.toFirst();(emd=emli.current());++emli)
356               {
357                 if (emd->getOuterScope()==def)
358                 {
359                   Doxygen::indexList.addContentsItem(FALSE,
360                       emd->name(),emd->getReference(),emd->getOutputFileBase(),emd->anchor(),FALSE,addToIndex);
361                 }
362                 else // inherited member
363                 {
364                   Doxygen::indexList.addContentsItem(FALSE,
365                       emd->name(),def->getReference(),def->getOutputFileBase(),emd->anchor(),FALSE,addToIndex);
366                 }
367               }
368               if (!isAnonymous)
369               {
370                 Doxygen::indexList.decContentsDepth();
371               }
372             }
373           }
374         }
375       }
376       else if (lde->kind()==LayoutDocEntry::NamespaceClasses || 
377                lde->kind()==LayoutDocEntry::FileClasses || 
378                lde->kind()==LayoutDocEntry::ClassNestedClasses
379               )
380       {
381         if (classes)
382         {
383           ClassDef *cd;
384           ClassSDict::Iterator it(*classes);
385           for (;(cd=it.current());++it)
386           {
387             if (cd->isLinkable() && (cd->partOfGroups()==0 || def->definitionType()==Definition::TypeGroup))
388             {
389               bool isNestedClass = def->definitionType()==Definition::TypeClass;
390               addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(FALSE),cd->anchor(),
391                                 addToIndex && isNestedClass,
392                                 preventSeparateIndex || cd->isEmbeddedInOuterScope());
393             }
394           }
395         }
396       }
397     }
398
399     Doxygen::indexList.decContentsDepth();
400   }
401 }
402
403 //----------------------------------------------------------------------------
404
405 static bool classHasVisibleChildren(ClassDef *cd)
406 {
407   BaseClassList *bcl;
408
409   if (cd->getLanguage()==SrcLangExt_VHDL) // reverse baseClass/subClass relation
410   {
411     if (cd->baseClasses()==0) return FALSE;
412     bcl=cd->baseClasses();
413   }
414   else 
415   {
416     if (cd->subClasses()==0) return FALSE;
417     bcl=cd->subClasses();
418   }
419
420   BaseClassListIterator bcli(*bcl);
421   for ( ; bcli.current() ; ++bcli)
422   {
423     if (bcli.current()->classDef->isVisibleInHierarchy())
424     {
425       return TRUE;
426     }
427   }
428   return FALSE;
429 }
430
431 //----------------------------------------------------------------------------
432 /*! Generates HTML Help tree of classes */
433
434 static void writeClassTree(OutputList &ol,BaseClassList *bcl,bool hideSuper,int level,FTVHelp* ftv,bool addToIndex)
435 {
436   if (bcl==0) return;
437   BaseClassListIterator bcli(*bcl);
438   bool started=FALSE;
439   for ( ; bcli.current() ; ++bcli)
440   {
441     ClassDef *cd=bcli.current()->classDef;
442     if (cd->getLanguage()==SrcLangExt_VHDL && (VhdlDocGen::VhdlClasses)cd->protection()!=VhdlDocGen::ENTITYCLASS)
443     {
444       continue;
445     }
446
447     bool b;
448     if (cd->getLanguage()==SrcLangExt_VHDL)
449     {
450       b=hasVisibleRoot(cd->subClasses());
451     }
452     else
453     {
454       b=hasVisibleRoot(cd->baseClasses());
455     }
456
457     if (cd->isVisibleInHierarchy() && b) // hasVisibleRoot(cd->baseClasses()))
458     {
459       if (!started)
460       {
461         startIndexHierarchy(ol,level);
462         if (addToIndex)
463         {
464           Doxygen::indexList.incContentsDepth();
465         }
466         if (ftv)
467         {
468           ftv->incContentsDepth();
469         }
470         started=TRUE;
471       }
472       ol.startIndexListItem();
473       //printf("Passed...\n");
474       bool hasChildren = !cd->visited && !hideSuper && classHasVisibleChildren(cd);
475       //printf("tree4: Has children %s: %d\n",cd->name().data(),hasChildren);
476       if (cd->isLinkable())
477       {
478         //printf("Writing class %s\n",cd->displayName().data());
479         ol.startIndexItem(cd->getReference(),cd->getOutputFileBase());
480         ol.parseText(cd->displayName());
481         ol.endIndexItem(cd->getReference(),cd->getOutputFileBase());
482         if (cd->isReference()) 
483         { 
484           ol.startTypewriter(); 
485           ol.docify(" [external]");
486           ol.endTypewriter();
487         }
488         if (addToIndex)
489         {
490           Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor());
491         }
492         if (ftv)
493         {
494           if (cd->getLanguage()==SrcLangExt_VHDL)
495           {
496             ftv->addContentsItem(hasChildren,bcli.current()->usedName,cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE,cd);
497           }
498           else
499           {
500             ftv->addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE,cd);
501           }
502         }
503       }
504       else
505       {
506         ol.startIndexItem(0,0);
507         ol.parseText(cd->name());
508         ol.endIndexItem(0,0);
509         if (addToIndex)
510         {
511           Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),0,0,0);
512         }
513         if (ftv)
514         {
515           ftv->addContentsItem(hasChildren,cd->displayName(),0,0,0,FALSE,FALSE,cd);
516         }
517       }
518       if (hasChildren)
519       {
520         //printf("Class %s at %p visited=%d\n",cd->name().data(),cd,cd->visited);
521         bool wasVisited=cd->visited;
522         cd->visited=TRUE;
523         if (cd->getLanguage()==SrcLangExt_VHDL) 
524         {
525           writeClassTree(ol,cd->baseClasses(),wasVisited,level+1,ftv,addToIndex);
526         }
527         else       
528         {
529           writeClassTree(ol,cd->subClasses(),wasVisited,level+1,ftv,addToIndex);
530         }
531       }
532       ol.endIndexListItem();
533     }
534   }
535   if (started) 
536   {
537     endIndexHierarchy(ol,level);
538     if (addToIndex)
539     {
540       Doxygen::indexList.decContentsDepth();
541     }
542     if (ftv)
543     {
544       ftv->decContentsDepth();
545     }
546   }
547 }
548
549 //----------------------------------------------------------------------------
550
551 static bool classVisibleInIndex(ClassDef *cd)
552 {
553   static bool allExternals = Config_getBool("ALLEXTERNALS");
554   return (allExternals && cd->isLinkable()) || cd->isLinkableInProject();
555 }
556
557 //----------------------------------------------------------------------------
558
559 static bool dirHasVisibleChildren(DirDef *dd)
560 {
561   if (dd->hasDocumentation()) return TRUE;
562
563   QListIterator<FileDef> fli(*dd->getFiles());
564   FileDef *fd;
565   for (fli.toFirst();(fd=fli.current());++fli)
566   {
567     bool genSourceFile;
568     if (fileVisibleInIndex(fd,genSourceFile))
569     {
570       return TRUE;
571     }
572     if (genSourceFile)
573     {
574       return TRUE;
575     }
576   }
577
578   QListIterator<DirDef> dli(dd->subDirs());
579   DirDef *subdd;
580   for (dli.toFirst();(subdd=dli.current());++dli)
581   {
582     if (dirHasVisibleChildren(subdd))
583     {
584       return TRUE;
585     }
586   }
587   return FALSE;
588 }
589
590 //----------------------------------------------------------------------------
591 static void writeDirTreeNode(OutputList &ol, DirDef *dd, int level, FTVHelp* ftv,bool addToIndex)
592 {
593   if (level>20)
594   {
595     warn(dd->getDefFileName(),dd->getDefLine(),
596         "warning: maximum nesting level exceeded for directory %s: "
597         "check for possible recursive directory relation!\n",dd->name().data()
598         );
599     return;
600   }
601
602   if (!dirHasVisibleChildren(dd))
603   {
604     return;
605   }
606
607   static bool tocExpand = TRUE; //Config_getBool("TOC_EXPAND");
608   bool isDir = dd->subDirs().count()>0 || // there are subdirs
609                (tocExpand &&              // or toc expand and
610                 dd->getFiles() && dd->getFiles()->count()>0 // there are files
611                );
612   //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
613   if (addToIndex)
614   {
615     Doxygen::indexList.addContentsItem(isDir,dd->shortName(),dd->getReference(),dd->getOutputFileBase(),0,TRUE,TRUE); 
616     Doxygen::indexList.incContentsDepth();
617   }
618   if (ftv)
619   {
620     ftv->addContentsItem(isDir,dd->shortName(),dd->getReference(),
621                          dd->getOutputFileBase(),0,FALSE,TRUE,dd); 
622     ftv->incContentsDepth();
623   }
624
625   ol.startIndexListItem();
626   ol.startIndexItem(dd->getReference(),dd->getOutputFileBase());
627   ol.parseText(dd->shortName());
628   ol.endIndexItem(dd->getReference(),dd->getOutputFileBase());
629   if (dd->isReference()) 
630   { 
631     ol.startTypewriter(); 
632     ol.docify(" [external]");
633     ol.endTypewriter();
634   }
635
636   // write sub directories
637   if (dd->subDirs().count()>0)
638   {
639     startIndexHierarchy(ol,level+1);
640     QListIterator<DirDef> dli(dd->subDirs());
641     DirDef *subdd = 0;
642     for (dli.toFirst();(subdd=dli.current());++dli)
643     {
644       writeDirTreeNode(ol,subdd,level+1,ftv,addToIndex);
645     }
646     endIndexHierarchy(ol,level+1); 
647   }
648
649   FileList *fileList=dd->getFiles();
650   int fileCount=0;
651   if (fileList && fileList->count()>0)
652   { 
653     FileDef *fd=fileList->first();
654     while (fd)
655     {
656       //static bool allExternals = Config_getBool("ALLEXTERNALS");
657       //if ((allExternals && fd->isLinkable()) || fd->isLinkableInProject())
658       //{
659       //  fileCount++;
660       //}
661       bool genSourceFile;
662       if (fileVisibleInIndex(fd,genSourceFile))
663       {
664         fileCount++;
665       }
666       else if (genSourceFile)
667       {
668         fileCount++;
669       }
670       fd=fileList->next();
671     }
672     if (fileCount>0)
673     {
674       startIndexHierarchy(ol,level+1);
675       fd=fileList->first();
676       while (fd)
677       {
678         bool doc,src;
679         doc = fileVisibleInIndex(fd,src);
680         QCString reference;
681         QCString outputBase;
682         if (doc) 
683         {
684           reference  = fd->getReference();
685           outputBase = fd->getOutputFileBase();
686         }
687         if (doc || src)
688         {
689           ol.startIndexListItem();
690           ol.startIndexItem(reference,outputBase);
691           ol.parseText(fd->displayName());
692           ol.endIndexItem(reference,outputBase);
693           ol.endIndexListItem();
694           if (ftv && (src || doc))
695           {
696             ftv->addContentsItem(FALSE,
697                 fd->displayName(),
698                 reference,outputBase,
699                 0,FALSE,FALSE,fd); 
700           }
701         }
702         fd=fileList->next();
703       }
704       endIndexHierarchy(ol,level+1); 
705     }
706   }
707
708   if (tocExpand && addToIndex)
709   {
710     // write files of this directory
711     if (fileCount>0)
712     {
713       FileDef *fd=fileList->first();
714       while (fd)
715       {
716         //static bool allExternals = Config_getBool("ALLEXTERNALS");
717         //if ((allExternals && fd->isLinkable()) || fd->isLinkableInProject())
718         bool doc,src;
719         doc = fileVisibleInIndex(fd,src);
720         if (doc)
721         {
722           addMembersToIndex(fd,LayoutDocManager::File,fd->displayName(),QCString(),TRUE);
723         }
724         else if (src)
725         {
726           Doxygen::indexList.addContentsItem(
727                FALSE, convertToHtml(fd->name(),TRUE), 0, 
728                fd->getSourceFileBase(), 0, FALSE, TRUE, fd);
729         }
730         fd=fileList->next();
731       }
732     }
733   }
734   ol.endIndexListItem();
735
736   if (addToIndex)
737   {
738     Doxygen::indexList.decContentsDepth();
739   }
740   if (ftv)
741   {
742     ftv->decContentsDepth();
743   }
744 }
745
746 static void writeDirHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex)
747 {
748   if (ftv)
749   {
750     ol.pushGeneratorState(); 
751     ol.disable(OutputGenerator::Html);
752   }
753   static bool fullPathNames = Config_getBool("FULL_PATH_NAMES");
754   startIndexHierarchy(ol,0);
755   if (fullPathNames)
756   {
757     SDict<DirDef>::Iterator dli(*Doxygen::directories);
758     DirDef *dd;
759     for (dli.toFirst();(dd=dli.current());++dli)
760     {
761       if (dd->getOuterScope()==Doxygen::globalScope) 
762       {
763         writeDirTreeNode(ol,dd,0,ftv,addToIndex);
764       }
765     }
766   }
767   if (ftv)
768   {
769     FileNameListIterator fnli(*Doxygen::inputNameList); 
770     FileName *fn;
771     for (fnli.toFirst();(fn=fnli.current());++fnli)
772     {
773       FileNameIterator fni(*fn);
774       FileDef *fd;
775       for (;(fd=fni.current());++fni)
776       {
777         static bool fullPathNames = Config_getBool("FULL_PATH_NAMES");
778         if (!fullPathNames || fd->getDirDef()==0) // top level file
779         {
780           bool doc,src;
781           doc = fileVisibleInIndex(fd,src);
782           QCString reference, outputBase;
783           if (doc)
784           {
785             reference = fd->getReference();
786             outputBase = fd->getOutputFileBase();
787           }
788           if (doc || src)
789           {
790             ftv->addContentsItem(FALSE,fd->displayName(),          
791                                  reference, outputBase, 0,         
792                                  FALSE,FALSE,fd);
793           }
794           if (addToIndex)
795           {
796             if (doc)
797             {
798               addMembersToIndex(fd,LayoutDocManager::File,fd->displayName(),QCString(),TRUE);
799             }
800             else if (src)
801             {
802               Doxygen::indexList.addContentsItem(
803                   FALSE, convertToHtml(fd->name(),TRUE), 0, 
804                   fd->getSourceFileBase(), 0, FALSE, TRUE, fd);
805             }
806           }
807         }
808       }
809     }
810   }
811   endIndexHierarchy(ol,0); 
812   if (ftv)
813   {
814     ol.popGeneratorState(); 
815   }
816 }
817
818
819 //----------------------------------------------------------------------------
820
821 static void writeClassTreeForList(OutputList &ol,ClassSDict *cl,bool &started,FTVHelp* ftv,bool addToIndex)
822 {
823   ClassSDict::Iterator cli(*cl);
824   for (;cli.current(); ++cli)
825   {
826     ClassDef *cd=cli.current();
827     //printf("class %s hasVisibleRoot=%d isVisibleInHierarchy=%d\n",
828     //             cd->name().data(),
829     //              hasVisibleRoot(cd->baseClasses()),
830     //              cd->isVisibleInHierarchy()
831     //      );
832     bool b;
833     if (cd->getLanguage()==SrcLangExt_VHDL)
834     {
835       if (!(VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS)      
836       {
837         continue;
838       }
839       b=!hasVisibleRoot(cd->subClasses());
840     }
841     else
842     {
843       b=!hasVisibleRoot(cd->baseClasses());
844     }
845
846     if (b)  //filter on root classes
847     {
848       if (cd->isVisibleInHierarchy()) // should it be visible
849       {
850         if (!started)
851         {
852           startIndexHierarchy(ol,0);
853           if (addToIndex)
854           {
855             Doxygen::indexList.incContentsDepth();
856           }
857           started=TRUE;
858         }
859         ol.startIndexListItem();
860         bool hasChildren = !cd->visited && classHasVisibleChildren(cd); 
861         //printf("list: Has children %s: %d\n",cd->name().data(),hasChildren);
862         if (cd->isLinkable())
863         {
864           //printf("Writing class %s isLinkable()=%d isLinkableInProject()=%d cd->templateMaster()=%p\n",
865           //    cd->displayName().data(),cd->isLinkable(),cd->isLinkableInProject(),cd->templateMaster());
866           ol.startIndexItem(cd->getReference(),cd->getOutputFileBase());
867           ol.parseText(cd->displayName());
868           ol.endIndexItem(cd->getReference(),cd->getOutputFileBase());
869           if (cd->isReference()) 
870           {
871             ol.startTypewriter(); 
872             ol.docify(" [external]");
873             ol.endTypewriter();
874           }
875           if (addToIndex)
876           {
877             if (cd->getLanguage()!=SrcLangExt_VHDL) // prevents double insertion in Design Unit List
878                   Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE);
879           }
880           if (ftv)
881           {
882             ftv->addContentsItem(hasChildren,cd->displayName(),cd->getReference(),cd->getOutputFileBase(),cd->anchor(),FALSE,FALSE,cd); 
883           }
884         }
885         else
886         {
887           ol.startIndexItem(0,0);
888           ol.parseText(cd->displayName());
889           ol.endIndexItem(0,0);
890           if (addToIndex)
891           {
892             Doxygen::indexList.addContentsItem(hasChildren,cd->displayName(),0,0,0,FALSE,FALSE);
893           }
894           if (ftv)
895           {
896             ftv->addContentsItem(hasChildren,cd->displayName(),0,0,0,FALSE,FALSE,cd); 
897           }
898         }
899         if (cd->getLanguage()==SrcLangExt_VHDL && hasChildren) 
900         {
901           writeClassTree(ol,cd->baseClasses(),cd->visited,1,ftv,addToIndex);
902           cd->visited=TRUE;
903         }
904         else if (hasChildren)
905         {
906           writeClassTree(ol,cd->subClasses(),cd->visited,1,ftv,addToIndex);
907           cd->visited=TRUE;
908         }
909         ol.endIndexListItem();
910       }
911     }
912   }
913 }
914
915 static void writeClassHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex)
916 {
917   initClassHierarchy(Doxygen::classSDict);
918   initClassHierarchy(Doxygen::hiddenClasses);
919   if (ftv)
920   {
921     ol.pushGeneratorState(); 
922     ol.disable(OutputGenerator::Html);
923   }
924   bool started=FALSE;
925   writeClassTreeForList(ol,Doxygen::classSDict,started,ftv,addToIndex);
926   writeClassTreeForList(ol,Doxygen::hiddenClasses,started,ftv,addToIndex);
927   if (started) 
928   {
929     endIndexHierarchy(ol,0);
930     if (addToIndex)
931     {
932       Doxygen::indexList.decContentsDepth();
933     }
934   }
935   if (ftv)
936   {
937     ol.popGeneratorState(); 
938   }
939 }
940
941 //----------------------------------------------------------------------------
942
943 static int countClassesInTreeList(const ClassSDict &cl)
944 {
945   int count=0;
946   ClassSDict::Iterator cli(cl);
947   for (;cli.current(); ++cli)
948   {
949     ClassDef *cd=cli.current();
950     if (!hasVisibleRoot(cd->baseClasses())) // filter on root classes
951     {
952       if (cd->isVisibleInHierarchy()) // should it be visible
953       {
954         if (cd->subClasses()) // should have sub classes
955         {
956           count++;
957         }
958       }
959     }
960   }
961   return count;
962 }
963
964 static int countClassHierarchy()
965 {
966   int count=0;
967   initClassHierarchy(Doxygen::classSDict);
968   initClassHierarchy(Doxygen::hiddenClasses);
969   count+=countClassesInTreeList(*Doxygen::classSDict);
970   count+=countClassesInTreeList(*Doxygen::hiddenClasses);
971   return count;
972 }
973
974 //----------------------------------------------------------------------------
975
976 static void writeHierarchicalIndex(OutputList &ol)
977 {
978   if (hierarchyClasses==0) return;
979   ol.pushGeneratorState();
980   //1.{
981   ol.disable(OutputGenerator::Man);
982
983   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassHierarchy);
984   QCString title = lne ? lne->title() : theTranslator->trClassHierarchy();
985   bool addToIndex = lne==0 || lne->visible();
986
987   startFile(ol,"hierarchy",0, title, HLI_Hierarchy);
988   startTitle(ol,0);
989   ol.parseText(title);
990   endTitle(ol,0,0);
991   ol.startContents();
992   ol.startTextBlock();
993
994   if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
995   {
996     ol.disable(OutputGenerator::Latex);
997     ol.disable(OutputGenerator::RTF);
998     ol.startParagraph();
999     ol.startTextLink("inherits",0);
1000     ol.parseText(theTranslator->trGotoGraphicalHierarchy());
1001     ol.endTextLink();
1002     ol.endParagraph();
1003     ol.enable(OutputGenerator::Latex);
1004     ol.enable(OutputGenerator::RTF);
1005   }
1006   ol.parseText(lne ? lne->intro() : theTranslator->trClassHierarchyDescription());
1007   ol.endTextBlock();
1008
1009   // ---------------
1010   // Static class hierarchy for Latex/RTF
1011   // ---------------
1012   ol.pushGeneratorState();
1013   //2.{
1014   ol.disable(OutputGenerator::Html);
1015   Doxygen::indexList.disable();
1016
1017   writeClassHierarchy(ol,0,addToIndex);
1018
1019   Doxygen::indexList.enable();
1020   ol.popGeneratorState();
1021   //2.}
1022
1023   // ---------------
1024   // Dynamic class hierarchical index for HTML
1025   // ---------------
1026   ol.pushGeneratorState(); 
1027   //2.{
1028   ol.disableAllBut(OutputGenerator::Html);
1029
1030   {
1031     if (addToIndex)
1032     {
1033       Doxygen::indexList.addContentsItem(TRUE,title,0,"hierarchy",0,TRUE,TRUE); 
1034     }
1035     FTVHelp* ftv = new FTVHelp(FALSE);
1036     writeClassHierarchy(ol,ftv,addToIndex);
1037     QGString outStr;
1038     FTextStream t(&outStr);
1039     ftv->generateTreeViewInline(t);
1040     ol.pushGeneratorState(); 
1041     ol.disableAllBut(OutputGenerator::Html);
1042     ol.writeString(outStr);
1043     ol.popGeneratorState();
1044     delete ftv;
1045   }
1046   ol.popGeneratorState();
1047   //2.}
1048   // ------
1049
1050   endFile(ol);
1051   ol.popGeneratorState();
1052   //1.}
1053 }
1054
1055 //----------------------------------------------------------------------------
1056
1057 static void writeGraphicalClassHierarchy(OutputList &ol)
1058 {
1059   if (hierarchyClasses==0) return;
1060   ol.disableAllBut(OutputGenerator::Html);
1061   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassHierarchy);
1062   QCString title = lne ? lne->title() : theTranslator->trClassHierarchy();
1063   startFile(ol,"inherits",0,title,HLI_Hierarchy,FALSE,"hierarchy");
1064   startTitle(ol,0);
1065   ol.parseText(title);
1066   endTitle(ol,0,0);
1067   ol.startContents();
1068   ol.startTextBlock();
1069   ol.startParagraph();
1070   ol.startTextLink("hierarchy",0);
1071   ol.parseText(theTranslator->trGotoTextualHierarchy());
1072   ol.endTextLink();
1073   ol.endParagraph();
1074   ol.endTextBlock();
1075   DotGfxHierarchyTable g;
1076   ol.writeGraphicalHierarchy(g);
1077   endFile(ol);
1078   ol.enableAll();
1079 }
1080
1081 //----------------------------------------------------------------------------
1082
1083 static void countFiles(int &htmlFiles,int &files)
1084 {
1085   htmlFiles=0;
1086   files=0;
1087   FileNameListIterator fnli(*Doxygen::inputNameList);
1088   FileName *fn;
1089   for (;(fn=fnli.current());++fnli)
1090   {
1091     FileNameIterator fni(*fn);
1092     FileDef *fd;
1093     for (;(fd=fni.current());++fni)
1094     {
1095       bool doc,src;
1096       doc = fileVisibleInIndex(fd,src);
1097       if (doc || src)
1098       {
1099         htmlFiles++;
1100       }
1101       if (doc)
1102       {
1103         files++;
1104       }
1105     }
1106   }
1107 }
1108
1109 //----------------------------------------------------------------------------
1110
1111 static void writeFileIndex(OutputList &ol)
1112 {
1113   if (documentedHtmlFiles==0) return;
1114
1115   ol.pushGeneratorState();
1116   ol.disable(OutputGenerator::Man);
1117   if (documentedFiles==0) ol.disableAllBut(OutputGenerator::Html);
1118
1119   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileList);
1120   if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Files); // fall back
1121   QCString title = lne ? lne->title() : theTranslator->trFileList();
1122   bool addToIndex = lne==0 || lne->visible();
1123
1124   startFile(ol,"files",0,title,HLI_Files);
1125   startTitle(ol,0);
1126   //if (!Config_getString("PROJECT_NAME").isEmpty()) 
1127   //{
1128   //  title.prepend(Config_getString("PROJECT_NAME")+" ");
1129   //}
1130   ol.parseText(title);
1131   endTitle(ol,0,0);
1132   ol.startContents();
1133   ol.startTextBlock();
1134
1135   if (addToIndex)
1136   {
1137     Doxygen::indexList.addContentsItem(TRUE,title,0,"files",0,TRUE,TRUE); 
1138     Doxygen::indexList.incContentsDepth();
1139   }
1140
1141   ol.parseText(lne ? lne->intro() : theTranslator->trFileListDescription(Config_getBool("EXTRACT_ALL")));
1142   ol.endTextBlock();
1143
1144   // ---------------
1145   // Flat file index
1146   // ---------------
1147
1148   // 1. {
1149   ol.pushGeneratorState();
1150   ol.disable(OutputGenerator::Html);
1151
1152   OutputNameDict outputNameDict(1009);
1153   OutputNameList outputNameList;
1154   outputNameList.setAutoDelete(TRUE);
1155   
1156   if (Config_getBool("FULL_PATH_NAMES"))
1157   {
1158     // re-sort input files in (dir,file) output order instead of (file,dir) input order 
1159     FileName *fn=Doxygen::inputNameList->first();
1160     while (fn)
1161     {
1162       FileDef *fd=fn->first();
1163       while (fd)
1164       {
1165         QCString path=fd->getPath();
1166         if (path.isEmpty()) path="[external]";
1167         FileList *fl = outputNameDict.find(path);
1168         if (fl)
1169         {
1170           fl->inSort(fd);
1171           //printf("+ inserting %s---%s\n",fd->getPath().data(),fd->name().data());
1172         }
1173         else
1174         {
1175           //printf("o inserting %s---%s\n",fd->getPath().data(),fd->name().data());
1176           fl = new FileList(path);
1177           fl->inSort(fd);
1178           outputNameList.inSort(fl);
1179           outputNameDict.insert(path,fl);
1180         }
1181         fd=fn->next();
1182       }
1183       fn=Doxygen::inputNameList->next();
1184     }
1185   }
1186   
1187   ol.startIndexList();
1188   FileList *fl=0;
1189   if (Config_getBool("FULL_PATH_NAMES"))
1190   {
1191     fl = outputNameList.first();
1192   }
1193   else
1194   {
1195     fl = Doxygen::inputNameList->first();
1196   }
1197   while (fl)
1198   {
1199     FileDef *fd=fl->first();
1200     while (fd)
1201     {
1202       //printf("Found filedef %s\n",fd->name().data());
1203       bool doc = fd->isLinkableInProject();
1204       bool src = fd->generateSourceFile();
1205       bool nameOk = !fd->isDocumentationFile();
1206       if (nameOk && (doc || src) && 
1207               !fd->isReference())
1208       {
1209         QCString path;
1210         if (Config_getBool("FULL_PATH_NAMES")) 
1211         {
1212           path=stripFromPath(fd->getPath().copy());
1213         }
1214         QCString fullName=fd->name();
1215         if (!path.isEmpty()) 
1216         {
1217           if (path.at(path.length()-1)!='/') fullName.prepend("/");
1218           fullName.prepend(path);
1219         }
1220
1221         ol.startIndexKey();
1222         ol.docify(path);
1223         if (doc)
1224         {
1225           ol.writeObjectLink(0,fd->getOutputFileBase(),0,fd->name());
1226           //if (addToIndex)
1227           //{
1228           //  addMembersToIndex(fd,LayoutDocManager::File,fullName,QCString());
1229           //}
1230         }
1231         else
1232         {
1233           ol.startBold();
1234           ol.docify(fd->name());
1235           ol.endBold();
1236           //if (addToIndex)
1237           //{
1238           //  Doxygen::indexList.addContentsItem(FALSE,fullName,0,0,0);
1239           //}
1240         }
1241         if (src)
1242         {
1243           ol.pushGeneratorState();
1244           ol.disableAllBut(OutputGenerator::Html);
1245           ol.docify(" ");
1246           ol.startTextLink(fd->includeName(),0);
1247           ol.docify("[");
1248           ol.parseText(theTranslator->trCode());
1249           ol.docify("]");
1250           ol.endTextLink();
1251           ol.popGeneratorState();
1252         }
1253         ol.endIndexKey();
1254         bool hasBrief = !fd->briefDescription().isEmpty();
1255         ol.startIndexValue(hasBrief);
1256         if (hasBrief)
1257         {
1258           //ol.docify(" (");
1259           ol.parseDoc(
1260               fd->briefFile(),fd->briefLine(),
1261               fd,0,
1262               fd->briefDescription(TRUE),
1263               FALSE, // index words
1264               FALSE, // isExample
1265               0,     // example name
1266               TRUE,  // single line
1267               TRUE   // link from index
1268              );
1269           //ol.docify(")");
1270         }
1271         ol.endIndexValue(fd->getOutputFileBase(),hasBrief);
1272         //ol.popGeneratorState();
1273         // --------------------------------------------------------
1274       }
1275       fd=fl->next();
1276     }
1277     if (Config_getBool("FULL_PATH_NAMES"))
1278     {
1279       fl=outputNameList.next();
1280     }
1281     else
1282     {
1283       fl=Doxygen::inputNameList->next();
1284     }
1285   }
1286   ol.endIndexList();
1287
1288   // 1. }
1289   ol.popGeneratorState();
1290
1291   // ---------------
1292   // Hierarchical file index for HTML
1293   // ---------------
1294   ol.pushGeneratorState(); 
1295   ol.disableAllBut(OutputGenerator::Html);
1296
1297   FTVHelp* ftv = new FTVHelp(FALSE);
1298   writeDirHierarchy(ol,ftv,addToIndex);
1299   QGString outStr;
1300   FTextStream t(&outStr);
1301   ftv->generateTreeViewInline(t);
1302   ol.writeString(outStr);
1303   delete ftv;
1304
1305   ol.popGeneratorState();
1306   // ------
1307
1308   if (addToIndex)
1309   {
1310     Doxygen::indexList.decContentsDepth();
1311   }
1312
1313   endFile(ol);
1314   ol.popGeneratorState();
1315 }
1316
1317 //----------------------------------------------------------------------------
1318 static int countNamespaces()
1319 {
1320   int count=0;
1321   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
1322   NamespaceDef *nd;
1323   for (;(nd=nli.current());++nli)
1324   {
1325     if (nd->isLinkableInProject()) count++;
1326   }
1327   return count;
1328 }
1329
1330 //----------------------------------------------------------------------------
1331
1332 void writeClassTree(ClassSDict *clDict,FTVHelp *ftv,bool addToIndex,bool globalOnly)
1333 {
1334   if (clDict)
1335   {
1336     ClassSDict::Iterator cli(*clDict);
1337     ClassDef *cd;
1338     for (;(cd=cli.current());++cli)
1339     {
1340       if (cd->getLanguage()==SrcLangExt_VHDL) 
1341       {
1342         if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKAGECLASS || 
1343             (VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKBODYCLASS
1344            )// no architecture
1345         {
1346           continue;
1347         }
1348         if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ARCHITECTURECLASS)
1349         {
1350           QCString n=cd->name();
1351           cd->setClassName(n.data());
1352         }         
1353       }
1354
1355       if (!globalOnly || 
1356            cd->getOuterScope()==0 || 
1357            cd->getOuterScope()==Doxygen::globalScope 
1358          ) 
1359       {
1360         int count=0;
1361         if (cd->getClassSDict())
1362         {
1363           ClassSDict::Iterator ccit(*cd->getClassSDict());
1364           ClassDef *ccd;
1365           for (;(ccd=ccit.current());++ccit)
1366           {
1367             if (ccd->isLinkableInProject() && ccd->templateMaster()==0) 
1368             {
1369               count++;
1370             }
1371           }
1372         }
1373         if (classVisibleInIndex(cd) && cd->templateMaster()==0) 
1374         { 
1375           ftv->addContentsItem(count>0,cd->displayName(FALSE),cd->getReference(),
1376               cd->getOutputFileBase(),cd->anchor(),FALSE,TRUE,cd); 
1377           if (addToIndex && 
1378               cd->partOfGroups()==0 &&
1379               (cd->getOuterScope()==0 || 
1380                cd->getOuterScope()->definitionType()!=Definition::TypeClass
1381               )
1382              )
1383           {
1384             addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(FALSE),cd->anchor());
1385           }
1386           if (count>0)
1387           {
1388             ftv->incContentsDepth();
1389             writeClassTree(cd->getClassSDict(),ftv,addToIndex,FALSE);
1390             ftv->decContentsDepth();
1391           }
1392         }
1393       }
1394     }
1395   }
1396 }
1397
1398 static bool containsVisibleChild(NamespaceDef *nd,bool includeClasses)
1399 {
1400   if (nd->getNamespaceSDict())
1401   {
1402     NamespaceSDict::Iterator cnli(*nd->getNamespaceSDict());
1403     NamespaceDef *cnd;
1404     for (cnli.toFirst();(cnd=cnli.current());++cnli)
1405     {
1406       if (cnd->isLinkable() && cnd->localName().find('@')==-1)
1407       {
1408         return TRUE;
1409       }
1410       else if (containsVisibleChild(cnd,includeClasses))
1411       {
1412         return TRUE;
1413       }
1414     }
1415   }
1416   if (includeClasses && nd->getClassSDict())
1417   {
1418     ClassSDict::Iterator cli(*nd->getClassSDict());
1419     ClassDef *cd;
1420     for (;(cd=cli.current());++cli)
1421     {
1422       if (cd->isLinkableInProject() && cd->templateMaster()==0) 
1423       { 
1424         return TRUE;
1425       }
1426     }
1427   }
1428   return FALSE;
1429 }
1430
1431 static void writeNamespaceTree(NamespaceSDict *nsDict,FTVHelp *ftv,
1432                                bool rootOnly,bool showClasses,bool addToIndex)
1433 {
1434   if (nsDict)
1435   {
1436     NamespaceSDict::Iterator nli(*nsDict);
1437     NamespaceDef *nd;
1438     for (nli.toFirst();(nd=nli.current());++nli)
1439     {
1440       if (nd->localName().find('@')==-1 && 
1441           (!rootOnly || nd->getOuterScope()==Doxygen::globalScope))
1442       {
1443
1444         bool hasChildren = containsVisibleChild(nd,showClasses);
1445         
1446         QCString ref; 
1447         QCString file; 
1448         if (nd->isLinkableInProject())
1449         {
1450           ref = nd->getReference();
1451           file = nd->getOutputFileBase();
1452           if (nd->getLanguage()==SrcLangExt_VHDL) // UGLY HACK
1453           {
1454             file=file.replace(0,strlen("namespace"),"class");
1455           }
1456         }
1457
1458         if (nd->isLinkable() || hasChildren)
1459         {
1460           ftv->addContentsItem(hasChildren,nd->localName(),ref,file,0,FALSE,TRUE,nd); 
1461
1462           if (addToIndex)
1463           {
1464             Doxygen::indexList.addContentsItem(hasChildren,nd->localName(),ref,file,QCString(),
1465                 hasChildren && !file.isEmpty(),addToIndex);
1466           }
1467
1468           //printf("*** writeNamespaceTree count=%d addToIndex=%d showClasses=%d classCount=%d\n",
1469           //    count,addToIndex,showClasses,classCount);
1470           if (hasChildren)
1471           {
1472             if (addToIndex) Doxygen::indexList.incContentsDepth();
1473             ftv->incContentsDepth();
1474             writeNamespaceTree(nd->getNamespaceSDict(),ftv,FALSE,showClasses,addToIndex);
1475             if (showClasses) 
1476             {
1477               writeClassTree(nd->getClassSDict(),ftv,addToIndex,FALSE);
1478             }
1479             ftv->decContentsDepth();
1480             if (addToIndex) Doxygen::indexList.decContentsDepth();
1481           }
1482         }
1483       }
1484     }
1485   }
1486 }
1487
1488
1489 static void writeNamespaceIndex(OutputList &ol)
1490 {
1491   if (documentedNamespaces==0) return;
1492   ol.pushGeneratorState();
1493   ol.disable(OutputGenerator::Man);
1494   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceList);
1495   if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Namespaces); // fall back
1496   QCString title = lne ? lne->title() : theTranslator->trNamespaceList();
1497   bool addToIndex = lne==0 || lne->visible();
1498   startFile(ol,"namespaces",0,title,HLI_Namespaces);
1499   startTitle(ol,0);
1500   ol.parseText(title);
1501   endTitle(ol,0,0);
1502   ol.startContents();
1503   ol.startTextBlock();
1504   ol.parseText(lne ? lne->intro() : theTranslator->trNamespaceListDescription(Config_getBool("EXTRACT_ALL")));
1505   ol.endTextBlock();
1506
1507   bool first=TRUE;
1508
1509   // ---------------
1510   // Linear namespace index for Latex/RTF
1511   // ---------------
1512   ol.pushGeneratorState();
1513   ol.disable(OutputGenerator::Html);
1514   
1515   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
1516   NamespaceDef *nd;
1517   for (nli.toFirst();(nd=nli.current());++nli)
1518   {
1519     if (nd->isLinkableInProject())
1520     {
1521       if (first)
1522       {
1523         ol.startIndexList();
1524         first=FALSE;
1525       }
1526       //ol.writeStartAnnoItem("namespace",nd->getOutputFileBase(),0,nd->name());
1527       ol.startIndexKey();
1528       if (nd->getLanguage()==SrcLangExt_VHDL)
1529       {
1530         ol.writeObjectLink(0, nd->getOutputFileBase().replace(0,strlen("namespace"),"class"),0,nd->displayName());
1531       }
1532       else
1533       {
1534         ol.writeObjectLink(0,nd->getOutputFileBase(),0,nd->displayName());
1535       }
1536       ol.endIndexKey();
1537
1538       bool hasBrief = !nd->briefDescription().isEmpty();
1539       ol.startIndexValue(hasBrief);
1540       if (hasBrief)
1541       {
1542         //ol.docify(" (");
1543         ol.parseDoc(
1544                  nd->briefFile(),nd->briefLine(),
1545                  nd,0,
1546                  nd->briefDescription(TRUE),
1547                  FALSE, // index words
1548                  FALSE, // isExample
1549                  0,     // example name
1550                  TRUE,  // single line
1551                  TRUE   // link from index
1552                 );
1553         //ol.docify(")");
1554       }
1555       ol.endIndexValue(nd->getOutputFileBase(),hasBrief);
1556
1557     }
1558   }
1559   if (!first) ol.endIndexList();
1560
1561   ol.popGeneratorState();
1562
1563   // ---------------
1564   // Hierarchical namespace index for HTML
1565   // ---------------
1566   ol.pushGeneratorState(); 
1567   ol.disableAllBut(OutputGenerator::Html);
1568
1569   {
1570     if (addToIndex)
1571     {
1572       Doxygen::indexList.addContentsItem(TRUE,title,0,"namespaces",0,TRUE,TRUE); 
1573       Doxygen::indexList.incContentsDepth();
1574     }
1575     FTVHelp* ftv = new FTVHelp(FALSE);
1576     writeNamespaceTree(Doxygen::namespaceSDict,ftv,TRUE,FALSE,addToIndex);
1577     QGString outStr;
1578     FTextStream t(&outStr);
1579     ftv->generateTreeViewInline(t);
1580     ol.writeString(outStr);
1581     delete ftv;
1582     if (addToIndex)
1583     {
1584       Doxygen::indexList.decContentsDepth();
1585     }
1586   }
1587
1588   ol.popGeneratorState();
1589   // ------
1590
1591   endFile(ol);
1592   ol.popGeneratorState();
1593 }
1594
1595 //----------------------------------------------------------------------------
1596
1597 static int countAnnotatedClasses(int *cp)
1598 {
1599   int count=0;
1600   int countPrinted=0;
1601   ClassSDict::Iterator cli(*Doxygen::classSDict);
1602   ClassDef *cd;
1603   for (;(cd=cli.current());++cli)
1604   {
1605     if (cd->isLinkableInProject() && cd->templateMaster()==0) 
1606     { 
1607       if (!cd->isEmbeddedInOuterScope())
1608       {
1609         countPrinted++;
1610       }
1611       count++; 
1612     }
1613   }
1614   *cp = countPrinted;
1615   return count;
1616 }
1617
1618
1619 static void writeAnnotatedClassList(OutputList &ol)
1620 {
1621   //LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassList);
1622   //bool addToIndex = lne==0 || lne->visible();
1623
1624   ol.startIndexList(); 
1625   ClassSDict::Iterator cli(*Doxygen::classSDict);
1626   ClassDef *cd;
1627   
1628   for (cli.toFirst();(cd=cli.current());++cli)
1629   {
1630     if (cd->getLanguage()==SrcLangExt_VHDL && 
1631         ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKAGECLASS || 
1632          (VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::PACKBODYCLASS)
1633        ) // no architecture
1634     {
1635       continue;
1636     }
1637  
1638     ol.pushGeneratorState();
1639     if (cd->isEmbeddedInOuterScope())
1640     {
1641       ol.disable(OutputGenerator::Latex);
1642       ol.disable(OutputGenerator::RTF);
1643     }
1644     if (cd->isLinkableInProject() && cd->templateMaster()==0)
1645     {
1646       QCString type=cd->compoundTypeString();
1647       ol.startIndexKey();
1648       if (cd->getLanguage()==SrcLangExt_VHDL)
1649       {
1650         QCString prot= VhdlDocGen::getProtectionName((VhdlDocGen::VhdlClasses)cd->protection());
1651         ol.docify(prot.data());
1652         ol.writeString(" ");
1653       }
1654       ol.writeObjectLink(0,cd->getOutputFileBase(),cd->anchor(),cd->displayName());
1655       ol.endIndexKey();
1656       bool hasBrief = !cd->briefDescription().isEmpty();
1657       ol.startIndexValue(hasBrief);
1658       if (hasBrief)
1659       {
1660         ol.parseDoc(
1661                  cd->briefFile(),cd->briefLine(),
1662                  cd,0,
1663                  cd->briefDescription(TRUE),
1664                  FALSE,  // indexWords
1665                  FALSE,  // isExample
1666                  0,     // example name
1667                  TRUE,  // single line
1668                  TRUE   // link from index
1669                 );
1670       }
1671       ol.endIndexValue(cd->getOutputFileBase(),hasBrief);
1672
1673       //if (addToIndex)
1674       //{
1675       //  addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(),cd->anchor());
1676       //}
1677     }
1678     ol.popGeneratorState();
1679   }
1680   ol.endIndexList();
1681 }
1682
1683 static QCString letterToLabel(char startLetter)
1684 {
1685   QCString s(5); 
1686   if (isId(startLetter))
1687   {
1688     s[0]=startLetter; s[1]=0;
1689   }
1690   else
1691   {
1692     const char hex[]="0123456789abcdef";
1693     s[0]='0';
1694     s[1]='x';
1695     s[2]=hex[startLetter>>4];
1696     s[3]=hex[startLetter&0xF];
1697     s[4]=0;
1698   }
1699   return s;
1700 }
1701
1702 //----------------------------------------------------------------------------
1703
1704 /** Special class list where sorting takes IGNORE_PREFIX into account. */
1705 class PrefixIgnoreClassList : public ClassList
1706 {
1707 public:
1708   virtual int compareItems(GCI item1, GCI item2)
1709   {
1710     ClassDef *c1=(ClassDef *)item1;
1711     ClassDef *c2=(ClassDef *)item2;
1712
1713     QCString n1 = c1->className();
1714     QCString n2 = c2->className();
1715     return stricmp (n1.data()+getPrefixIndex(n1), n2.data()+getPrefixIndex(n2));
1716   }
1717 };
1718
1719 /** Class representing a cell in the alphabetical class index. */
1720 class AlphaIndexTableCell
1721 {
1722   public:
1723     AlphaIndexTableCell(int row,int col,uchar letter,ClassDef *cd) : 
1724       m_letter(letter), m_class(cd), m_row(row), m_col(col) 
1725     { //printf("AlphaIndexTableCell(%d,%d,%c,%s)\n",row,col,letter!=0 ? letter: '-',
1726       //       cd!=(ClassDef*)0x8 ? cd->name().data() : "<null>"); 
1727     }
1728
1729     ClassDef *classDef() const { return m_class; }
1730     uchar letter()       const { return m_letter; }
1731     int row()            const { return m_row; }
1732     int column()         const { return m_col; }
1733
1734   private:
1735     uchar m_letter;
1736     ClassDef *m_class;
1737     int m_row;
1738     int m_col;
1739 };
1740
1741 /** Class representing a row in the alphabetical class index. */
1742 class AlphaIndexTableRows : public QList<AlphaIndexTableCell>
1743 {
1744   public:
1745     AlphaIndexTableRows() { setAutoDelete(TRUE); }
1746 };
1747
1748 /** Iterator for the cells in a row of the alphabetical class index. */
1749 class AlphaIndexTableRowsIterator : public QListIterator<AlphaIndexTableCell>
1750 {
1751   public:
1752     AlphaIndexTableRowsIterator(const AlphaIndexTableRows &list) : 
1753       QListIterator<AlphaIndexTableCell>(list) {}
1754 };
1755
1756 /** Class representing the columns in the alphabetical class index. */
1757 class AlphaIndexTableColumns : public QList<AlphaIndexTableRows>
1758 {
1759   public:
1760     AlphaIndexTableColumns() { setAutoDelete(TRUE); }
1761 };
1762
1763 // write an alphabetical index of all class with a header for each letter
1764 static void writeAlphabeticalClassList(OutputList &ol)
1765 {
1766   // What starting letters are used
1767   bool indexLetterUsed[256];
1768   memset (indexLetterUsed, 0, sizeof (indexLetterUsed));
1769
1770   // first count the number of headers
1771   ClassSDict::Iterator cli(*Doxygen::classSDict);
1772   ClassDef *cd;
1773   uint startLetter=0;
1774   int headerItems=0;
1775   for (;(cd=cli.current());++cli)
1776   {
1777     if (cd->isLinkableInProject() && cd->templateMaster()==0)
1778     {
1779       if (cd->getLanguage()==SrcLangExt_VHDL && !((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS ))// no architecture
1780         continue;
1781              
1782       int index = getPrefixIndex(cd->className());
1783       //printf("name=%s index=%d %d\n",cd->className().data(),index,cd->protection());
1784       startLetter=toupper(cd->className().at(index))&0xFF;
1785       indexLetterUsed[startLetter] = true;
1786     }
1787   }
1788
1789   // write quick link index (row of letters)
1790   QCString alphaLinks = "<div class=\"qindex\">";
1791   int l;
1792   for (l=0; l<256; l++)
1793   {
1794     if (indexLetterUsed[l])
1795     {
1796       if (headerItems) alphaLinks += "&#160;|&#160;";
1797       headerItems++;
1798       alphaLinks += (QCString)"<a class=\"qindex\" href=\"#letter_" + 
1799                     (char)l + "\">" + 
1800                     (char)l + "</a>";
1801     }
1802   }
1803   alphaLinks += "</div>\n";
1804   ol.writeString(alphaLinks);
1805
1806
1807   // the number of columns in the table
1808   const int columns = Config_getInt("COLS_IN_ALPHA_INDEX");
1809
1810   int i,j;
1811   int totalItems = headerItems*2 + annotatedClasses;      // number of items in the table (headers span 2 items)
1812   int rows = (totalItems + columns - 1)/columns;          // number of rows in the table
1813
1814   //printf("headerItems=%d totalItems=%d columns=%d rows=%d itemsInLastRow=%d\n",
1815   //    headerItems,totalItems,columns,rows,itemsInLastRow);
1816
1817   // Keep a list of classes for each starting letter
1818   PrefixIgnoreClassList classesByLetter[256];
1819   AlphaIndexTableColumns tableColumns;
1820
1821   // fill the columns with the class list (row elements in each column,
1822   // expect for the columns with number >= itemsInLastRow, which get one
1823   // item less.
1824   //int icount=0;
1825   startLetter=0;
1826   for (cli.toFirst();(cd=cli.current());++cli)
1827   {
1828     if (cd->getLanguage()==SrcLangExt_VHDL && !((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS ))// no architecture
1829       continue;
1830     
1831     if (cd->isLinkableInProject() && cd->templateMaster()==0)
1832     {
1833       int index = getPrefixIndex(cd->className());
1834       startLetter=toupper(cd->className().at(index))&0xFF;
1835       // Do some sorting again, since the classes are sorted by name with 
1836       // prefix, which should be ignored really.
1837       if (cd->getLanguage()==SrcLangExt_VHDL)
1838       {
1839         if ((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS )// no architecture
1840           classesByLetter[startLetter].inSort(cd);
1841       }
1842       else
1843       classesByLetter[startLetter].inSort(cd);
1844     }
1845   }
1846
1847   #define NEXT_ROW()                           \
1848     do                                         \
1849     {                                          \
1850       if (row>maxRows) maxRows=row;            \
1851       if (row>=rows && col<columns)            \
1852       {                                        \
1853         col++;                                 \
1854         row=0;                                 \
1855         tableRows = new AlphaIndexTableRows;   \
1856         tableColumns.append(tableRows);        \
1857       }                                        \
1858     }                                          \
1859     while(0)                                   \
1860
1861   AlphaIndexTableRows *tableRows = new AlphaIndexTableRows;
1862   tableColumns.append(tableRows);
1863   int col=0,row=0,maxRows=0;
1864   for (l=0; l<256; l++)
1865   {
1866     if (classesByLetter[l].count()>0)
1867     {
1868       // add special header cell
1869       tableRows->append(new AlphaIndexTableCell(row,col,(uchar)l,(ClassDef*)0x8));
1870       row++;
1871       tableRows->append(new AlphaIndexTableCell(row,col,0,(ClassDef*)0x8));
1872       row++;
1873       tableRows->append(new AlphaIndexTableCell(row,col,0,classesByLetter[l].at(0)));
1874       row++; 
1875       NEXT_ROW();
1876       for (i=1; i<(int)classesByLetter[l].count(); i++)
1877       {
1878         // add normal cell
1879         tableRows->append(new AlphaIndexTableCell(row,col,0,classesByLetter[l].at(i)));
1880         row++;
1881         NEXT_ROW();
1882       }
1883     }
1884   }
1885
1886   // create row iterators for each column
1887   AlphaIndexTableRowsIterator **colIterators = new AlphaIndexTableRowsIterator*[columns];
1888   for (i=0;i<columns;i++)
1889   {
1890     if (i<(int)tableColumns.count())
1891     {
1892       colIterators[i] = new AlphaIndexTableRowsIterator(*tableColumns.at(i));
1893     }
1894     else // empty column
1895     {
1896       colIterators[i] = 0;
1897     }
1898   }
1899
1900   ol.writeString("<table style=\"margin: 10px; white-space: nowrap;\" align=\"center\" width=\"95%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n");
1901   // generate table
1902   for (i=0;i<=maxRows;i++) // foreach table row
1903   {
1904     //printf("writing row %d\n",i);
1905     //ol.nextTableRow();
1906     ol.writeString("<tr>");
1907     // the last column may contain less items then the others
1908     //int colsInRow = (i<rows-1) ? columns : itemsInLastRow; 
1909     //printf("row [%d]\n",i);
1910     for (j=0;j<columns;j++) // foreach table column
1911     {
1912       if (colIterators[j])
1913       {
1914         AlphaIndexTableCell *cell = colIterators[j]->current();
1915         if (cell)
1916         {
1917           if (cell->row()==i)
1918           {
1919             if (cell->letter()!=0)
1920             {
1921               QCString s = letterToLabel(cell->letter());
1922               ol.writeString("<td rowspan=\"2\" valign=\"bottom\">");
1923               ol.writeString("<a name=\"letter_");
1924               ol.writeString(s);
1925               ol.writeString("\"></a>");
1926               ol.writeString("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
1927                   "<tr>"
1928                   "<td><div class=\"ah\">&#160;&#160;"); 
1929               ol.writeString(s);
1930               ol.writeString(         "&#160;&#160;</div>"
1931                   "</td>"
1932                   "</tr>"
1933                   "</table>\n");
1934             }
1935             else if (cell->classDef()!=(ClassDef*)0x8)
1936             {
1937               cd = cell->classDef();
1938               ol.writeString("<td valign=\"top\">");
1939               QCString namesp,cname;
1940               //if (cd->getNamespaceDef()) namesp=cd->getNamespaceDef()->displayName();
1941               //QCString cname=cd->className();
1942               extractNamespaceName(cd->name(),cname,namesp);
1943               QCString nsDispName;
1944               SrcLangExt lang = cd->getLanguage();
1945               QCString sep = getLanguageSpecificSeparator(lang);
1946               if (sep!="::")
1947               {
1948                 nsDispName=substitute(namesp,"::",sep);
1949                 cname=substitute(cname,"::",sep);
1950               }
1951               else
1952               {
1953                 nsDispName=namesp;
1954               }
1955
1956               ol.writeObjectLink(cd->getReference(),
1957                   cd->getOutputFileBase(),cd->anchor(),cname);
1958               if (!namesp.isEmpty())
1959               {
1960                 ol.docify(" (");
1961                 NamespaceDef *nd = getResolvedNamespace(namesp);
1962                 if (nd && nd->isLinkable())
1963                 {
1964                   ol.writeObjectLink(nd->getReference(),
1965                       nd->getOutputFileBase(),0,nsDispName);
1966                 }
1967                 else
1968                 {
1969                   ol.docify(nsDispName);
1970                 }
1971                 ol.docify(")");
1972               }
1973               ol.writeNonBreakableSpace(3);
1974             }
1975             ++(*colIterators[j]);
1976             if (cell->letter()!=0 || cell->classDef()!=(ClassDef*)0x8)
1977             {
1978               ol.writeString("</td>");
1979             }
1980           }
1981         }
1982         else
1983         {
1984           ol.writeString("<td></td>");
1985         }
1986       }
1987     }
1988     ol.writeString("</tr>\n");
1989   }
1990   ol.writeString("</table>\n");
1991   
1992   ol.writeString(alphaLinks);
1993
1994   // release the temporary memory
1995   for (i=0;i<columns;i++)
1996   {
1997     delete colIterators[i];
1998   }
1999   delete[] colIterators;
2000 }
2001
2002 //----------------------------------------------------------------------------
2003
2004 static void writeAlphabeticalIndex(OutputList &ol)
2005 {
2006   if (annotatedClasses==0) return;
2007   ol.pushGeneratorState();
2008   ol.disableAllBut(OutputGenerator::Html);
2009   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassIndex);
2010   QCString title = lne ? lne->title() : theTranslator->trCompoundIndex();
2011   bool addToIndex = lne==0 || lne->visible();
2012
2013   startFile(ol,"classes",0,title,HLI_Classes); 
2014
2015   startTitle(ol,0);
2016   ol.parseText(title);
2017   endTitle(ol,0,0);
2018
2019   if (addToIndex)
2020   {
2021     Doxygen::indexList.addContentsItem(FALSE,title,0,"classes",0,FALSE,TRUE); 
2022   }
2023
2024   ol.startContents();
2025   writeAlphabeticalClassList(ol);
2026   endFile(ol); // contains ol.endContents()
2027
2028   ol.popGeneratorState();
2029 }
2030
2031 //----------------------------------------------------------------------------
2032
2033 static void writeAnnotatedIndex(OutputList &ol)
2034 {
2035   //printf("writeAnnotatedIndex: count=%d printed=%d\n",
2036   //    annotatedClasses,annotatedClassesPrinted);
2037   if (annotatedClasses==0) return;
2038   
2039   ol.pushGeneratorState();
2040   ol.disable(OutputGenerator::Man);
2041   if (annotatedClassesPrinted==0)
2042   {
2043     ol.disable(OutputGenerator::Latex);
2044     ol.disable(OutputGenerator::RTF);
2045   }
2046   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassList);
2047   if (lne==0) lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Classes); // fall back
2048   QCString title = lne ? lne->title() : theTranslator->trCompoundList();
2049   bool addToIndex = lne==0 || lne->visible();
2050
2051   if (Config_getBool("OPTIMIZE_OUTPUT_VHDL")) 
2052   {
2053     VhdlDocGen::findConstraintFile(lne);
2054   }
2055   
2056   startFile(ol,"annotated",0,title,HLI_Annotated);
2057
2058   startTitle(ol,0);
2059   ol.parseText(title);
2060   endTitle(ol,0,0);
2061
2062   ol.startContents();
2063
2064   ol.startTextBlock();
2065   ol.parseText(lne ? lne->intro() : theTranslator->trCompoundListDescription());
2066   ol.endTextBlock();
2067
2068   // ---------------
2069   // Linear class index for Latex/RTF
2070   // ---------------
2071   ol.pushGeneratorState();
2072   ol.disable(OutputGenerator::Html);
2073   Doxygen::indexList.disable();
2074
2075   writeAnnotatedClassList(ol);
2076
2077   Doxygen::indexList.enable();
2078   ol.popGeneratorState();
2079
2080   // ---------------
2081   // Hierarchical class index for HTML
2082   // ---------------
2083   ol.pushGeneratorState(); 
2084   ol.disableAllBut(OutputGenerator::Html);
2085
2086   {
2087     if (addToIndex)
2088     {
2089       Doxygen::indexList.addContentsItem(TRUE,title,0,"annotated",0,TRUE,TRUE); 
2090       Doxygen::indexList.incContentsDepth();
2091     }
2092     FTVHelp* ftv = new FTVHelp(FALSE);
2093     writeNamespaceTree(Doxygen::namespaceSDict,ftv,TRUE,TRUE,addToIndex);
2094     writeClassTree(Doxygen::classSDict,ftv,addToIndex,TRUE);
2095     QGString outStr;
2096     FTextStream t(&outStr);
2097     ftv->generateTreeViewInline(t);
2098     ol.writeString(outStr);
2099     delete ftv;
2100     if (addToIndex)
2101     {
2102       Doxygen::indexList.decContentsDepth();
2103     }
2104   }
2105
2106   ol.popGeneratorState();
2107   // ------
2108   
2109   endFile(ol); // contains ol.endContents()
2110   ol.popGeneratorState();
2111 }
2112
2113 //----------------------------------------------------------------------------
2114 static void writeClassLinkForMember(OutputList &ol,MemberDef *md,const char *separator,
2115                              QCString &prevClassName)
2116 {
2117   ClassDef *cd=md->getClassDef();
2118   if ( cd && prevClassName!=cd->displayName())
2119   {
2120     ol.docify(separator);
2121     ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(),
2122         cd->displayName());
2123     ol.writeString("\n");
2124     prevClassName = cd->displayName();
2125   }
2126 }
2127
2128 static void writeFileLinkForMember(OutputList &ol,MemberDef *md,const char *separator,
2129                              QCString &prevFileName)
2130 {
2131   FileDef *fd=md->getFileDef();
2132   if (fd && prevFileName!=fd->name())
2133   {
2134     ol.docify(separator);
2135     ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(),
2136         fd->name());
2137     ol.writeString("\n");
2138     prevFileName = fd->name();
2139   }
2140 }
2141
2142 static void writeNamespaceLinkForMember(OutputList &ol,MemberDef *md,const char *separator,
2143                              QCString &prevNamespaceName)
2144 {
2145   NamespaceDef *nd=md->getNamespaceDef();
2146   if (nd && prevNamespaceName!=nd->name())
2147   {
2148     ol.docify(separator);
2149     ol.writeObjectLink(md->getReference(),md->getOutputFileBase(),md->anchor(),
2150         nd->name());
2151     ol.writeString("\n");
2152     prevNamespaceName = nd->name();
2153   }
2154 }
2155
2156 static void writeMemberList(OutputList &ol,bool useSections,int page,
2157                             MemberIndexList memberLists[MEMBER_INDEX_ENTRIES],
2158                             DefinitionIntf::DefType type)
2159 {
2160   int pi;
2161   // page==-1 => write all member indices to one page (used when total members is small)
2162   // page!=-1 => write all member for this page only (used when total member is large)
2163   int startIndex = page==-1 ? 0                      : page;
2164   int endIndex   = page==-1 ? MEMBER_INDEX_ENTRIES-1 : page;
2165   ASSERT((int)type<3);
2166
2167   typedef void (*writeLinkForMember_t)(OutputList &ol,MemberDef *md,const char *separator,
2168                                    QCString &prevNamespaceName);
2169
2170   // each index tab has its own write function
2171   static writeLinkForMember_t writeLinkForMemberMap[3] = 
2172   { 
2173     &writeClassLinkForMember, 
2174     &writeFileLinkForMember,
2175     &writeNamespaceLinkForMember
2176   };
2177   QCString prevName;
2178   QCString prevDefName;
2179   bool first=TRUE;
2180   bool firstSection=TRUE;
2181   bool firstItem=TRUE;
2182   for (pi=startIndex; pi<=endIndex; pi++) // page==-1 => pi=[0..127], page!=-1 => pi=page 
2183   {
2184     MemberIndexList *ml = &memberLists[pi];
2185     if (ml->count()==0) continue;
2186     ml->sort();
2187     QListIterator<MemberDef> mli(*ml);
2188     MemberDef *md;
2189     for (mli.toFirst();(md=mli.current());++mli)
2190     {
2191       const char *sep;
2192       bool isFunc=!md->isObjCMethod() && 
2193         (md->isFunction() || md->isSlot() || md->isSignal()); 
2194       QCString name=md->name();
2195       int startIndex = getPrefixIndex(name);
2196       if (QCString(name.data()+startIndex)!=prevName) // new entry
2197       {
2198         if ((prevName.isEmpty() || 
2199             tolower(name.at(startIndex))!=tolower(prevName.at(0))) && 
2200             useSections) // new section
2201         {
2202           if (!firstItem)    ol.endItemListItem();
2203           if (!firstSection) ol.endItemList();
2204           char cl[2];
2205           cl[0] = tolower(name.at(startIndex));
2206           cl[1] = 0;
2207           QCString cs = letterToLabel(cl[0]);
2208           QCString anchor=(QCString)"index_"+cs;
2209           QCString title=(QCString)"- "+cl+" -";
2210           ol.startSection(anchor,title,SectionInfo::Subsection);
2211           ol.docify(title);
2212           ol.endSection(anchor,SectionInfo::Subsection);
2213           ol.startItemList();
2214           firstSection=FALSE;
2215           firstItem=TRUE;
2216         }
2217         else if (!useSections && first)
2218         {
2219           ol.startItemList();
2220           first=FALSE;
2221         }
2222
2223         // member name
2224         if (!firstItem) ol.endItemListItem();
2225         ol.startItemListItem();
2226         firstItem=FALSE;
2227         ol.docify(name);
2228         if (isFunc) ol.docify("()");
2229         ol.writeString("\n");
2230
2231         // link to class
2232         prevDefName="";
2233         sep = ": ";
2234         prevName = name.data()+startIndex;
2235       }
2236       else // same entry
2237       {
2238         sep = ", ";
2239         // link to class for other members with the same name
2240       }
2241       // write the link for the specific list type
2242       writeLinkForMemberMap[(int)type](ol,md,sep,prevDefName);
2243     }
2244   }
2245   if (!firstItem) ol.endItemListItem();
2246   ol.endItemList();
2247 }
2248
2249 //----------------------------------------------------------------------------
2250
2251 void initClassMemberIndices()
2252 {
2253   int i=0;
2254   int j=0;
2255   for (j=0;j<CMHL_Total;j++)
2256   {
2257     documentedClassMembers[j]=0;
2258     for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
2259     {
2260       g_memberIndexLetterUsed[j][i].clear();
2261     }
2262   }
2263 }
2264
2265 void addClassMemberNameToIndex(MemberDef *md)
2266 {
2267   static bool hideFriendCompounds = Config_getBool("HIDE_FRIEND_COMPOUNDS");
2268   ClassDef *cd=0;
2269
2270  
2271   
2272   if (md->isLinkableInProject() && 
2273       (cd=md->getClassDef())    && 
2274       cd->isLinkableInProject() &&
2275       cd->templateMaster()==0)
2276   {
2277     QCString n = md->name();
2278     int index = getPrefixIndex(n);
2279     uchar charCode = (uchar)n.at(index);
2280     uint letter = charCode<128 ? tolower(charCode) : charCode;
2281     if (!n.isEmpty()) 
2282     {
2283       bool isFriendToHide = hideFriendCompounds &&
2284         (QCString(md->typeString())=="friend class" || 
2285          QCString(md->typeString())=="friend struct" ||
2286          QCString(md->typeString())=="friend union");
2287       if (!(md->isFriend() && isFriendToHide))
2288       {
2289         g_memberIndexLetterUsed[CMHL_All][letter].append(md);
2290         documentedClassMembers[CMHL_All]++;
2291       }
2292       if (md->isFunction()  || md->isSlot() || md->isSignal())
2293       {
2294         g_memberIndexLetterUsed[CMHL_Functions][letter].append(md);
2295         documentedClassMembers[CMHL_Functions]++;
2296       } 
2297       else if (md->isVariable())
2298       {
2299         g_memberIndexLetterUsed[CMHL_Variables][letter].append(md);
2300         documentedClassMembers[CMHL_Variables]++;
2301       }
2302       else if (md->isTypedef())
2303       {
2304         g_memberIndexLetterUsed[CMHL_Typedefs][letter].append(md);
2305         documentedClassMembers[CMHL_Typedefs]++;
2306       }
2307       else if (md->isEnumerate())
2308       {
2309         g_memberIndexLetterUsed[CMHL_Enums][letter].append(md);
2310         documentedClassMembers[CMHL_Enums]++;
2311       }
2312       else if (md->isEnumValue())
2313       {
2314         g_memberIndexLetterUsed[CMHL_EnumValues][letter].append(md);
2315         documentedClassMembers[CMHL_EnumValues]++;
2316       }
2317       else if (md->isProperty())
2318       {
2319         g_memberIndexLetterUsed[CMHL_Properties][letter].append(md);
2320         documentedClassMembers[CMHL_Properties]++;
2321       }
2322       else if (md->isEvent())
2323       {
2324         g_memberIndexLetterUsed[CMHL_Events][letter].append(md);
2325         documentedClassMembers[CMHL_Events]++;
2326       }
2327       else if (md->isRelated() || md->isForeign() ||
2328                (md->isFriend() && !isFriendToHide))
2329       {
2330         g_memberIndexLetterUsed[CMHL_Related][letter].append(md);
2331         documentedClassMembers[CMHL_Related]++;
2332       }
2333     }
2334   }
2335 }
2336
2337 //----------------------------------------------------------------------------
2338
2339 void initNamespaceMemberIndices()
2340 {
2341   int i=0;
2342   int j=0;
2343   for (j=0;j<NMHL_Total;j++)
2344   {
2345     documentedNamespaceMembers[j]=0;
2346     for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
2347     {
2348       g_namespaceIndexLetterUsed[j][i].clear();
2349     }
2350   }
2351 }
2352
2353 void addNamespaceMemberNameToIndex(MemberDef *md)
2354 {
2355   NamespaceDef *nd=md->getNamespaceDef();
2356   if (nd && nd->isLinkableInProject() && md->isLinkableInProject())
2357   {
2358     QCString n = md->name();
2359     int index = getPrefixIndex(n);
2360     uchar charCode = (uchar)n.at(index);
2361     uint letter = charCode<128 ? tolower(charCode) : charCode;
2362     if (!n.isEmpty()) 
2363     {
2364       g_namespaceIndexLetterUsed[NMHL_All][letter].append(md);
2365       documentedNamespaceMembers[NMHL_All]++;
2366
2367       if (md->isFunction()) 
2368       {
2369         g_namespaceIndexLetterUsed[NMHL_Functions][letter].append(md);
2370         documentedNamespaceMembers[NMHL_Functions]++;
2371       }
2372       else if (md->isVariable()) 
2373       {
2374         g_namespaceIndexLetterUsed[NMHL_Variables][letter].append(md);
2375         documentedNamespaceMembers[NMHL_Variables]++;
2376       }
2377       else if (md->isTypedef())
2378       {
2379         g_namespaceIndexLetterUsed[NMHL_Typedefs][letter].append(md);
2380         documentedNamespaceMembers[NMHL_Typedefs]++;
2381       }
2382       else if (md->isEnumerate())
2383       {
2384         g_namespaceIndexLetterUsed[NMHL_Enums][letter].append(md);
2385         documentedNamespaceMembers[NMHL_Enums]++;
2386       }
2387       else if (md->isEnumValue())
2388       {
2389         g_namespaceIndexLetterUsed[NMHL_EnumValues][letter].append(md);
2390         documentedNamespaceMembers[NMHL_EnumValues]++;
2391       }
2392     }
2393   }
2394 }
2395
2396 //----------------------------------------------------------------------------
2397
2398 void initFileMemberIndices()
2399 {
2400   int i=0;
2401   int j=0;
2402   for (j=0;j<NMHL_Total;j++)
2403   {
2404     documentedFileMembers[j]=0;
2405     for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
2406     {
2407       g_fileIndexLetterUsed[j][i].clear();
2408     }
2409   }
2410 }
2411
2412 void addFileMemberNameToIndex(MemberDef *md)
2413 {
2414   FileDef *fd=md->getFileDef();
2415   if (fd && fd->isLinkableInProject() && md->isLinkableInProject())
2416   {
2417     QCString n = md->name();
2418     int index = getPrefixIndex(n);
2419     uchar charCode = (uchar)n.at(index);
2420     uint letter = charCode<128 ? tolower(charCode) : charCode;
2421     if (!n.isEmpty()) 
2422     {
2423       g_fileIndexLetterUsed[FMHL_All][letter].append(md);
2424       documentedFileMembers[FMHL_All]++;
2425
2426       if (md->isFunction()) 
2427       {
2428         g_fileIndexLetterUsed[FMHL_Functions][letter].append(md);
2429         documentedFileMembers[FMHL_Functions]++;
2430       }
2431       else if (md->isVariable()) 
2432       {
2433         g_fileIndexLetterUsed[FMHL_Variables][letter].append(md);
2434         documentedFileMembers[FMHL_Variables]++;
2435       }
2436       else if (md->isTypedef())
2437       {
2438         g_fileIndexLetterUsed[FMHL_Typedefs][letter].append(md);
2439         documentedFileMembers[FMHL_Typedefs]++;
2440       }
2441       else if (md->isEnumerate())
2442       {
2443         g_fileIndexLetterUsed[FMHL_Enums][letter].append(md);
2444         documentedFileMembers[FMHL_Enums]++;
2445       }
2446       else if (md->isEnumValue())
2447       {
2448         g_fileIndexLetterUsed[FMHL_EnumValues][letter].append(md);
2449         documentedFileMembers[FMHL_EnumValues]++;
2450       }
2451       else if (md->isDefine())
2452       {
2453         g_fileIndexLetterUsed[FMHL_Defines][letter].append(md);
2454         documentedFileMembers[FMHL_Defines]++;
2455       }
2456     }
2457   }
2458 }
2459
2460 //----------------------------------------------------------------------------
2461
2462 static void writeQuickMemberIndex(OutputList &ol,
2463     MemberIndexList charUsed[MEMBER_INDEX_ENTRIES],int page,
2464     QCString fullName,bool multiPage)
2465 {
2466   bool first=TRUE;
2467   int i;
2468   startQuickIndexList(ol,TRUE);
2469   for (i=33;i<127;i++)
2470   {
2471     char is[2];is[0]=(char)i;is[1]='\0';
2472     QCString ci = letterToLabel((char)i);
2473     if (charUsed[i].count()>0)
2474     {
2475       QCString anchor;
2476       QCString extension=Doxygen::htmlFileExtension;
2477       if (!multiPage)
2478         anchor="#index_";
2479       else if (first) 
2480         anchor=fullName+extension+"#index_";
2481       else 
2482         anchor=fullName+QCString().sprintf("_0x%02x",i)+extension+"#index_";
2483       startQuickIndexItem(ol,anchor+ci,i==page,TRUE,first);
2484       ol.writeString(is);
2485       endQuickIndexItem(ol);
2486       first=FALSE;
2487     }
2488   }
2489   endQuickIndexList(ol);
2490 }
2491
2492 //----------------------------------------------------------------------------
2493
2494 /** Helper class representing a class member in the navigation menu. */
2495 struct CmhlInfo
2496 {
2497   CmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {}
2498   const char *fname;
2499   QCString title;
2500 };
2501
2502 static const CmhlInfo *getCmhlInfo(int hl)
2503 {
2504   static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
2505   static bool vhdlOpt    = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
2506   static CmhlInfo cmhlInfo[] = 
2507   {
2508     CmhlInfo("functions",     theTranslator->trAll()),
2509     CmhlInfo("functions_func",
2510         fortranOpt ? theTranslator->trSubprograms() : 
2511         vhdlOpt    ? VhdlDocGen::trFunctionAndProc() :
2512                      theTranslator->trFunctions()),
2513     CmhlInfo("functions_vars",theTranslator->trVariables()),
2514     CmhlInfo("functions_type",theTranslator->trTypedefs()),
2515     CmhlInfo("functions_enum",theTranslator->trEnumerations()),
2516     CmhlInfo("functions_eval",theTranslator->trEnumerationValues()),
2517     CmhlInfo("functions_prop",theTranslator->trProperties()),
2518     CmhlInfo("functions_evnt",theTranslator->trEvents()),
2519     CmhlInfo("functions_rela",theTranslator->trRelatedFunctions())
2520   };
2521   return &cmhlInfo[hl];
2522 }
2523
2524 static void writeClassMemberIndexFiltered(OutputList &ol, ClassMemberHighlight hl)
2525 {
2526   if (documentedClassMembers[hl]==0) return;
2527   
2528   static bool disableIndex     = Config_getBool("DISABLE_INDEX");
2529
2530   bool multiPageIndex=FALSE;
2531   int numPages=1;
2532   if (documentedClassMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
2533   {
2534     multiPageIndex=TRUE;
2535     numPages=127;
2536   }
2537
2538   ol.pushGeneratorState();
2539   ol.disableAllBut(OutputGenerator::Html);
2540
2541   QCString extension=Doxygen::htmlFileExtension;
2542   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassMembers);
2543   QCString title = lne ? lne->title() : theTranslator->trCompoundMembers();
2544   if (hl!=CMHL_All) title+=(QCString)" - "+getCmhlInfo(hl)->title;
2545   bool addToIndex = lne==0 || lne->visible();
2546
2547   if (addToIndex)
2548   {
2549     Doxygen::indexList.addContentsItem(multiPageIndex,getCmhlInfo(hl)->title,0,
2550                                        getCmhlInfo(hl)->fname,0,multiPageIndex,TRUE);
2551     if (multiPageIndex) Doxygen::indexList.incContentsDepth();
2552   }
2553
2554   int page;
2555   bool first=TRUE;
2556   for (page=0;page<numPages;page++)
2557   {
2558     if (!multiPageIndex || g_memberIndexLetterUsed[hl][page].count()>0)
2559     {
2560       QCString fileName = getCmhlInfo(hl)->fname;
2561       if (multiPageIndex)
2562       { 
2563         if (!first)
2564         {
2565           fileName+=QCString().sprintf("_0x%02x",page);
2566         }
2567         char cs[2];
2568         cs[0]=page;
2569         cs[1]=0;
2570         if (addToIndex)
2571         {
2572           Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
2573         }
2574       }
2575       bool quickIndex = documentedClassMembers[hl]>maxItemsBeforeQuickIndex;
2576       
2577       ol.startFile(fileName+extension,0,title);
2578       ol.startQuickIndices();
2579       if (!disableIndex)
2580       {
2581         ol.writeQuickLinks(TRUE,HLI_Functions,0);
2582         startQuickIndexList(ol);
2583
2584         // index item for global member list
2585         startQuickIndexItem(ol,
2586             getCmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==CMHL_All,TRUE,first);
2587         ol.writeString(fixSpaces(getCmhlInfo(0)->title));
2588         endQuickIndexItem(ol);
2589
2590         int i;
2591         // index items per category member lists
2592         for (i=1;i<CMHL_Total;i++)
2593         {
2594           if (documentedClassMembers[i]>0)
2595           {
2596             startQuickIndexItem(ol,getCmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first);
2597             ol.writeString(fixSpaces(getCmhlInfo(i)->title));
2598             //printf("multiPageIndex=%d first=%d fileName=%s file=%s title=%s\n",
2599             //    multiPageIndex,first,fileName.data(),getCmhlInfo(i)->fname,getCmhlInfo(i)->title.data());
2600             endQuickIndexItem(ol);
2601           }
2602         }
2603
2604         endQuickIndexList(ol);
2605
2606         // quick alphabetical index
2607         if (quickIndex)
2608         {
2609           writeQuickMemberIndex(ol,g_memberIndexLetterUsed[hl],page,
2610               getCmhlInfo(hl)->fname,multiPageIndex);
2611         }
2612       }
2613       ol.endQuickIndices();
2614       ol.writeSplitBar(fileName);
2615       ol.writeSearchInfo();
2616
2617       ol.startContents();
2618
2619       if (hl==CMHL_All)
2620       {
2621         ol.startTextBlock();
2622         ol.parseText(lne ? lne->intro() : theTranslator->trCompoundMembersDescription(Config_getBool("EXTRACT_ALL")));
2623         ol.endTextBlock();
2624       }
2625       else
2626       {
2627         // hack to work around a mozilla bug, which refuses to switch to
2628         // normal lists otherwise
2629         ol.writeString("&#160;");
2630       }
2631       //ol.newParagraph();  // FIXME:PARA
2632       writeMemberList(ol,quickIndex,
2633                       multiPageIndex?page:-1,
2634                       g_memberIndexLetterUsed[hl],
2635                       Definition::TypeClass);
2636       endFile(ol);
2637       first=FALSE;
2638     }
2639   }
2640
2641   if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth();
2642   
2643   ol.popGeneratorState();
2644 }
2645
2646 static void writeClassMemberIndex(OutputList &ol)
2647 {
2648   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::ClassMembers);
2649   bool addToIndex = lne==0 || lne->visible();
2650
2651   if (documentedClassMembers[CMHL_All]>0 && addToIndex)
2652   {
2653     Doxygen::indexList.addContentsItem(TRUE,lne ? lne->title() : theTranslator->trCompoundMembers(),0,"functions",0); 
2654     Doxygen::indexList.incContentsDepth();
2655   }
2656   writeClassMemberIndexFiltered(ol,CMHL_All);
2657   writeClassMemberIndexFiltered(ol,CMHL_Functions);
2658   writeClassMemberIndexFiltered(ol,CMHL_Variables);
2659   writeClassMemberIndexFiltered(ol,CMHL_Typedefs);
2660   writeClassMemberIndexFiltered(ol,CMHL_Enums);
2661   writeClassMemberIndexFiltered(ol,CMHL_EnumValues);
2662   writeClassMemberIndexFiltered(ol,CMHL_Properties);
2663   writeClassMemberIndexFiltered(ol,CMHL_Events);
2664   writeClassMemberIndexFiltered(ol,CMHL_Related);
2665   if (documentedClassMembers[CMHL_All]>0 && addToIndex)
2666   {
2667     Doxygen::indexList.decContentsDepth();
2668   }
2669
2670 }
2671
2672 //----------------------------------------------------------------------------
2673
2674 /** Helper class representing a file member in the navigation menu. */
2675 struct FmhlInfo 
2676 {
2677   FmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {}
2678   const char *fname;
2679   QCString title;
2680 };
2681
2682 static const FmhlInfo *getFmhlInfo(int hl)
2683 {
2684   static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
2685   static bool vhdlOpt    = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
2686   static FmhlInfo fmhlInfo[] = 
2687   {
2688     FmhlInfo("globals",     theTranslator->trAll()),
2689     FmhlInfo("globals_func",
2690          fortranOpt ? theTranslator->trSubprograms()  : 
2691          vhdlOpt    ? VhdlDocGen::trFunctionAndProc() : 
2692                       theTranslator->trFunctions()),
2693     FmhlInfo("globals_vars",theTranslator->trVariables()),
2694     FmhlInfo("globals_type",theTranslator->trTypedefs()),
2695     FmhlInfo("globals_enum",theTranslator->trEnumerations()),
2696     FmhlInfo("globals_eval",theTranslator->trEnumerationValues()),
2697     FmhlInfo("globals_defs",theTranslator->trDefines())
2698   };
2699   return &fmhlInfo[hl];
2700 }
2701
2702 static void writeFileMemberIndexFiltered(OutputList &ol, FileMemberHighlight hl)
2703 {
2704   if (documentedFileMembers[hl]==0) return;
2705
2706   static bool disableIndex     = Config_getBool("DISABLE_INDEX");
2707
2708   bool multiPageIndex=FALSE;
2709   int numPages=1;
2710   if (documentedFileMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
2711   {
2712     multiPageIndex=TRUE;
2713     numPages=127;
2714   }
2715
2716   ol.pushGeneratorState();
2717   ol.disableAllBut(OutputGenerator::Html);
2718
2719   QCString extension=Doxygen::htmlFileExtension;
2720   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileGlobals);
2721   QCString title = lne ? lne->title() : theTranslator->trFileMembers();
2722   bool addToIndex = lne==0 || lne->visible();
2723
2724   if (addToIndex)
2725   {
2726     Doxygen::indexList.addContentsItem(multiPageIndex,getFmhlInfo(hl)->title,0,
2727                                        getFmhlInfo(hl)->fname,0,multiPageIndex,TRUE);
2728     if (multiPageIndex) Doxygen::indexList.incContentsDepth();
2729   }
2730
2731   int page;
2732   bool first=TRUE;
2733   for (page=0;page<numPages;page++)
2734   {
2735     if (!multiPageIndex || g_fileIndexLetterUsed[hl][page].count()>0)
2736     {
2737       QCString fileName = getFmhlInfo(hl)->fname;
2738       if (multiPageIndex)
2739       {
2740         if (!first)
2741         {
2742           fileName+=QCString().sprintf("_0x%02x",page);
2743         }
2744         char cs[2];
2745         cs[0]=page;
2746         cs[1]=0;
2747         if (addToIndex)
2748         {
2749           Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
2750         }
2751       }
2752       bool quickIndex = documentedFileMembers[hl]>maxItemsBeforeQuickIndex;
2753       
2754       ol.startFile(fileName+extension,0,title);
2755       ol.startQuickIndices();
2756       if (!disableIndex)
2757       {
2758         ol.writeQuickLinks(TRUE,HLI_Globals,0);
2759         startQuickIndexList(ol);
2760
2761         // index item for all file member lists
2762         startQuickIndexItem(ol,
2763             getFmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==FMHL_All,TRUE,first);
2764         ol.writeString(fixSpaces(getFmhlInfo(0)->title));
2765         endQuickIndexItem(ol);
2766
2767         int i;
2768         // index items for per category member lists
2769         for (i=1;i<FMHL_Total;i++)
2770         {
2771           if (documentedFileMembers[i]>0)
2772           {
2773             startQuickIndexItem(ol,
2774                 getFmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first);
2775             ol.writeString(fixSpaces(getFmhlInfo(i)->title));
2776             endQuickIndexItem(ol);
2777           }
2778         }
2779
2780         endQuickIndexList(ol);
2781
2782         if (quickIndex)
2783         {
2784           writeQuickMemberIndex(ol,g_fileIndexLetterUsed[hl],page,
2785               getFmhlInfo(hl)->fname,multiPageIndex);
2786         }
2787       }
2788       ol.endQuickIndices();
2789       ol.writeSplitBar(fileName);
2790       ol.writeSearchInfo();
2791
2792       ol.startContents();
2793
2794       if (hl==FMHL_All)
2795       {
2796         ol.startTextBlock();
2797         ol.parseText(lne ? lne->intro() : theTranslator->trFileMembersDescription(Config_getBool("EXTRACT_ALL")));
2798         ol.endTextBlock();
2799       }
2800       else
2801       {
2802         // hack to work around a mozilla bug, which refuses to switch to
2803         // normal lists otherwise
2804         ol.writeString("&#160;");
2805       }
2806       //ol.newParagraph();  // FIXME:PARA
2807       //writeFileMemberList(ol,quickIndex,hl,page);
2808       writeMemberList(ol,quickIndex,
2809           multiPageIndex?page:-1,
2810           g_fileIndexLetterUsed[hl],
2811           Definition::TypeFile);
2812       endFile(ol);
2813       first=FALSE;
2814     }
2815   }
2816   if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth();
2817   ol.popGeneratorState();
2818 }
2819
2820 static void writeFileMemberIndex(OutputList &ol)
2821 {
2822   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::FileGlobals);
2823   bool addToIndex = lne==0 || lne->visible();
2824   if (documentedFileMembers[FMHL_All]>0 && addToIndex)
2825   {
2826     Doxygen::indexList.addContentsItem(FALSE,lne ? lne->title() : theTranslator->trFileMembers(),0,"globals",0); 
2827     Doxygen::indexList.incContentsDepth();
2828   }
2829   writeFileMemberIndexFiltered(ol,FMHL_All);
2830   writeFileMemberIndexFiltered(ol,FMHL_Functions);
2831   writeFileMemberIndexFiltered(ol,FMHL_Variables);
2832   writeFileMemberIndexFiltered(ol,FMHL_Typedefs);
2833   writeFileMemberIndexFiltered(ol,FMHL_Enums);
2834   writeFileMemberIndexFiltered(ol,FMHL_EnumValues);
2835   writeFileMemberIndexFiltered(ol,FMHL_Defines);
2836   if (documentedFileMembers[FMHL_All]>0 && addToIndex)
2837   {
2838     Doxygen::indexList.decContentsDepth();
2839   }
2840
2841 }
2842
2843 //----------------------------------------------------------------------------
2844
2845 /** Helper class representing a namespace member in the navigation menu. */
2846 struct NmhlInfo
2847 {
2848   NmhlInfo(const char *fn,const char *t) : fname(fn), title(t) {}
2849   const char *fname;
2850   QCString title;
2851 };
2852
2853 static const NmhlInfo *getNmhlInfo(int hl)
2854 {
2855   static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
2856   static bool vhdlOpt    = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
2857   static NmhlInfo nmhlInfo[] = 
2858   {
2859     NmhlInfo("namespacemembers",     theTranslator->trAll()),
2860     NmhlInfo("namespacemembers_func",
2861         fortranOpt ? theTranslator->trSubprograms()  :
2862         vhdlOpt    ? VhdlDocGen::trFunctionAndProc() :
2863                      theTranslator->trFunctions()),
2864     NmhlInfo("namespacemembers_vars",theTranslator->trVariables()),
2865     NmhlInfo("namespacemembers_type",theTranslator->trTypedefs()),
2866     NmhlInfo("namespacemembers_enum",theTranslator->trEnumerations()),
2867     NmhlInfo("namespacemembers_eval",theTranslator->trEnumerationValues())
2868   };
2869   return &nmhlInfo[hl];
2870 }
2871
2872 //----------------------------------------------------------------------------
2873
2874 static void writeNamespaceMemberIndexFiltered(OutputList &ol,
2875                                         NamespaceMemberHighlight hl)
2876 {
2877   if (documentedNamespaceMembers[hl]==0) return;
2878
2879   static bool disableIndex     = Config_getBool("DISABLE_INDEX");
2880
2881
2882   bool multiPageIndex=FALSE;
2883   int numPages=1;
2884   if (documentedNamespaceMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
2885   {
2886     multiPageIndex=TRUE;
2887     numPages=127;
2888   }
2889
2890   ol.pushGeneratorState();
2891   ol.disableAllBut(OutputGenerator::Html);
2892
2893   QCString extension=Doxygen::htmlFileExtension;
2894   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceMembers);
2895   QCString title = lne ? lne->title() : theTranslator->trNamespaceMembers();
2896   bool addToIndex = lne==0 || lne->visible();
2897
2898   if (addToIndex)
2899   {
2900     Doxygen::indexList.addContentsItem(multiPageIndex,getNmhlInfo(hl)->title,0,
2901                                        getNmhlInfo(hl)->fname,0,multiPageIndex,TRUE);
2902     if (multiPageIndex) Doxygen::indexList.incContentsDepth();
2903   }
2904
2905   int page;
2906   bool first=TRUE;
2907   for (page=0;page<numPages;page++)
2908   {
2909     if (!multiPageIndex || g_namespaceIndexLetterUsed[hl][page].count()>0)
2910     {
2911       QCString fileName = getNmhlInfo(hl)->fname;
2912       if (multiPageIndex)
2913       {
2914         if (!first)
2915         {
2916           fileName+=QCString().sprintf("_0x%02x",page);
2917         }
2918         char cs[2];
2919         cs[0]=page;
2920         cs[1]=0;
2921         if (addToIndex)
2922         {
2923           Doxygen::indexList.addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
2924         }
2925       }
2926       bool quickIndex = documentedNamespaceMembers[hl]>maxItemsBeforeQuickIndex;
2927       
2928       ol.startFile(fileName+extension,0,title);
2929       ol.startQuickIndices();
2930       if (!disableIndex)
2931       {
2932         ol.writeQuickLinks(TRUE,HLI_NamespaceMembers,0);
2933         startQuickIndexList(ol);
2934
2935         // index item for all namespace member lists
2936         startQuickIndexItem(ol,
2937             getNmhlInfo(0)->fname+Doxygen::htmlFileExtension,hl==NMHL_All,TRUE,first);
2938         ol.writeString(fixSpaces(getNmhlInfo(0)->title));
2939         endQuickIndexItem(ol);
2940
2941         int i;
2942         // index items per category member lists
2943         for (i=1;i<NMHL_Total;i++)
2944         {
2945           if (documentedNamespaceMembers[i]>0)
2946           {
2947             startQuickIndexItem(ol,
2948                 getNmhlInfo(i)->fname+Doxygen::htmlFileExtension,hl==i,TRUE,first);
2949             ol.writeString(fixSpaces(getNmhlInfo(i)->title));
2950             endQuickIndexItem(ol);
2951           }
2952         }
2953
2954         endQuickIndexList(ol);
2955
2956         if (quickIndex)
2957         {
2958           writeQuickMemberIndex(ol,g_namespaceIndexLetterUsed[hl],page,
2959               getNmhlInfo(hl)->fname,multiPageIndex);
2960         }
2961
2962       }
2963       ol.endQuickIndices();
2964       ol.writeSplitBar(fileName);
2965       ol.writeSearchInfo();
2966
2967       ol.startContents();
2968
2969       if (hl==NMHL_All)
2970       {
2971         ol.startTextBlock();
2972         ol.parseText(lne ? lne->intro() : theTranslator->trNamespaceMemberDescription(Config_getBool("EXTRACT_ALL")));
2973         ol.endTextBlock();
2974       }
2975       else
2976       {
2977         // hack to work around a mozilla bug, which refuses to switch to
2978         // normal lists otherwise
2979         ol.writeString("&#160;");
2980       }
2981       //ol.newParagraph(); // FIXME:PARA
2982
2983       //writeNamespaceMemberList(ol,quickIndex,hl,page);
2984       writeMemberList(ol,quickIndex,
2985                       multiPageIndex?page:-1,
2986                       g_namespaceIndexLetterUsed[hl],
2987                       Definition::TypeNamespace);
2988       endFile(ol);
2989     }
2990   }
2991   if (multiPageIndex && addToIndex) Doxygen::indexList.decContentsDepth();
2992   ol.popGeneratorState();
2993 }
2994
2995 static void writeNamespaceMemberIndex(OutputList &ol)
2996 {
2997   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::NamespaceMembers);
2998   bool addToIndex = lne==0 || lne->visible();
2999   if (documentedNamespaceMembers[NMHL_All]>0 && addToIndex)
3000   {
3001     Doxygen::indexList.addContentsItem(FALSE,lne ? lne->title() : theTranslator->trNamespaceMembers(),0,"namespacemembers",0); 
3002     Doxygen::indexList.incContentsDepth();
3003   }
3004   //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
3005   writeNamespaceMemberIndexFiltered(ol,NMHL_All);
3006   writeNamespaceMemberIndexFiltered(ol,NMHL_Functions);
3007   writeNamespaceMemberIndexFiltered(ol,NMHL_Variables);
3008   writeNamespaceMemberIndexFiltered(ol,NMHL_Typedefs);
3009   writeNamespaceMemberIndexFiltered(ol,NMHL_Enums);
3010   writeNamespaceMemberIndexFiltered(ol,NMHL_EnumValues);
3011   if (documentedNamespaceMembers[NMHL_All]>0 && addToIndex)
3012   {
3013     Doxygen::indexList.decContentsDepth();
3014   }
3015
3016 }
3017
3018 //----------------------------------------------------------------------------
3019
3020 //----------------------------------------------------------------------------
3021
3022 static void writeExampleIndex(OutputList &ol)
3023 {
3024   if (Doxygen::exampleSDict->count()==0) return;
3025   ol.pushGeneratorState();
3026   ol.disable(OutputGenerator::Man);
3027   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Examples);
3028   QCString title = lne ? lne->title() : theTranslator->trExamples();
3029   bool addToIndex = lne==0 || lne->visible();
3030
3031   startFile(ol,"examples",0,title,HLI_Examples);
3032
3033   startTitle(ol,0);
3034   ol.parseText(title);
3035   endTitle(ol,0,0);
3036
3037   ol.startContents();
3038
3039   if (addToIndex)
3040   {
3041     Doxygen::indexList.addContentsItem(TRUE,title,0,"examples",0,TRUE,TRUE); 
3042     Doxygen::indexList.incContentsDepth();
3043   }
3044
3045   ol.startTextBlock();
3046   ol.parseText(lne ? lne->intro() : theTranslator->trExamplesDescription());
3047   ol.endTextBlock();
3048
3049   ol.startItemList();
3050   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
3051   PageDef *pd=0;
3052   for (pdi.toFirst();(pd=pdi.current());++pdi)
3053   {
3054     ol.startItemListItem();
3055     QCString n=pd->getOutputFileBase();
3056     if (!pd->title().isEmpty())
3057     {
3058       ol.writeObjectLink(0,n,0,pd->title());
3059       if (addToIndex)
3060       {
3061         Doxygen::indexList.addContentsItem(FALSE,filterTitle(pd->title()),pd->getReference(),n,0,FALSE,TRUE);
3062       }
3063     }
3064     else
3065     {
3066       ol.writeObjectLink(0,n,0,pd->name());
3067       if (addToIndex)
3068       {
3069         Doxygen::indexList.addContentsItem(FALSE,pd->name(),pd->getReference(),n,0,FALSE,TRUE);
3070       }
3071     }
3072     ol.endItemListItem();
3073     ol.writeString("\n");
3074   }
3075   ol.endItemList();
3076
3077   if (addToIndex)
3078   {
3079     Doxygen::indexList.decContentsDepth();
3080   }
3081   endFile(ol);
3082   ol.popGeneratorState();
3083 }
3084
3085
3086 //----------------------------------------------------------------------------
3087
3088 template<typename T>
3089 bool writeMemberNavIndex(FTextStream &t,
3090                          int indent,
3091                          int n,
3092                          int documentedMembers[],
3093                          MemberIndexList indexLetterUsed[][MEMBER_INDEX_ENTRIES],
3094                          const T *(*getInfo)(int),
3095                          bool &first
3096                         )
3097
3098 {
3099   bool found=FALSE;
3100   QCString indentStr;
3101   indentStr.fill(' ',indent*2);
3102   // index items per category member lists
3103   int i;
3104   for (i=0;i<n;i++)
3105   {
3106     bool hasIndex       = documentedMembers[i]>0;
3107     bool quickIndex     = documentedMembers[i]>maxItemsBeforeQuickIndex;
3108     bool multiIndexPage = documentedMembers[i]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX;
3109     if (hasIndex)
3110     {
3111       // terminate previous entry
3112       if (!first) t << "," << endl;
3113       first = FALSE;
3114
3115       // start entry
3116       if (!found)
3117       {
3118         t << "[" << endl;
3119       }
3120       found = TRUE;
3121
3122       t << indentStr << "  [ ";
3123       t << "\"" << fixSpaces(getInfo(i)->title) << "\", ";
3124       t << "\"" << getInfo(i)->fname << Doxygen::htmlFileExtension << "\", ";
3125       bool firstPage=TRUE;
3126       if (quickIndex)
3127       {
3128         t << "[ " << endl;
3129         int j;
3130         for (j=33;j<127;j++)
3131         {
3132           if (indexLetterUsed[i][j].count()>0)
3133           {
3134             if (!firstPage) t << "," << endl;
3135             QCString fullName = getInfo(i)->fname;
3136             QCString extension = Doxygen::htmlFileExtension;
3137             QCString anchor;
3138             if (firstPage || !multiIndexPage) 
3139               anchor=fullName+extension+"#index_";
3140             else 
3141               anchor=fullName+QCString().sprintf("_0x%02x",j)+extension+"#index_";
3142             char is[2];is[0]=(char)j;is[1]='\0';
3143             QCString ci = letterToLabel((char)j);
3144             t << indentStr << "    [ ";
3145             t << "\"" << is << "\", ";
3146             t << "\"" << anchor << ci << "\", null ]";
3147             firstPage=FALSE;
3148           }
3149         }
3150         t << endl << indentStr << "  ] ]";
3151       }
3152       else
3153       {
3154         t << "null" << " ]";
3155       }
3156     }
3157   }
3158   return found;
3159 }
3160
3161 //----------------------------------------------------------------------------
3162
3163 #if 0
3164 static bool writeFullNavIndex(FTextStream &t, LayoutNavEntry *root,int indent,bool &first)
3165 {
3166   static struct NavEntryCountMap 
3167   {
3168     LayoutNavEntry::Kind kind;
3169     bool hasItems;
3170   } navEntryCountMap[] =
3171   {
3172     { LayoutNavEntry::MainPage,         TRUE                                   },
3173     { LayoutNavEntry::Pages,            indexedPages>0                         },
3174     { LayoutNavEntry::Modules,          documentedGroups>0                     },
3175     { LayoutNavEntry::Namespaces,       documentedNamespaces>0                 },
3176     { LayoutNavEntry::NamespaceList,    documentedNamespaces>0                 },
3177     { LayoutNavEntry::NamespaceMembers, documentedNamespaceMembers[NMHL_All]>0 },
3178     { LayoutNavEntry::Classes,          annotatedClasses>0                     },
3179     { LayoutNavEntry::ClassList,        annotatedClasses>0                     },
3180     { LayoutNavEntry::ClassIndex,       annotatedClasses>0                     },
3181     { LayoutNavEntry::ClassHierarchy,   hierarchyClasses>0                     },
3182     { LayoutNavEntry::ClassMembers,     documentedClassMembers[CMHL_All]>0     },
3183     { LayoutNavEntry::Files,            documentedFiles>0                      },
3184     { LayoutNavEntry::FileList,         documentedFiles>0                      },
3185     { LayoutNavEntry::FileGlobals,      documentedFileMembers[FMHL_All]>0      },
3186     //{ LayoutNavEntry::Dirs,             documentedDirs>0                       },
3187     { LayoutNavEntry::Examples,         Doxygen::exampleSDict->count()>0       }
3188   };
3189
3190   QCString indentStr;
3191   indentStr.fill(' ',indent*2);
3192   bool found=FALSE;
3193   if (root->children().count()>0)
3194   {
3195     QListIterator<LayoutNavEntry> li(root->children());
3196     LayoutNavEntry *entry;
3197     for (li.toFirst();(entry=li.current());++li)
3198     {
3199       if (navEntryCountMap[entry->kind()].hasItems && entry->visible())
3200       {
3201         // terminate previous entry
3202         if (!first) t << "," << endl;
3203         first = FALSE;
3204
3205         // start entry
3206         if (!found)
3207         {
3208           t << "[" << endl;
3209         }
3210         found = TRUE;
3211
3212         bool emptySection=TRUE;
3213         t << indentStr << "  [ ";
3214         t << "\"" << fixSpaces(entry->title()) << "\", ";
3215         t << "\"" << entry->baseFile() << Doxygen::htmlFileExtension << "\", ";
3216
3217         // write children (if any)
3218         bool firstChild=TRUE;
3219         if (entry->kind()==LayoutNavEntry::ClassMembers)
3220         {
3221           emptySection = !writeMemberNavIndex(t,indent+1,CMHL_Total,documentedClassMembers,g_memberIndexLetterUsed,&getCmhlInfo,firstChild);
3222         }
3223         else if (entry->kind()==LayoutNavEntry::NamespaceMembers)
3224         {
3225           emptySection = !writeMemberNavIndex(t,indent+1,NMHL_Total,documentedNamespaceMembers,g_namespaceIndexLetterUsed,&getNmhlInfo,firstChild);
3226         }
3227         else if (entry->kind()==LayoutNavEntry::FileGlobals)
3228         {
3229           emptySection = !writeMemberNavIndex(t,indent+1,FMHL_Total,documentedFileMembers,g_fileIndexLetterUsed,&getFmhlInfo,firstChild);
3230         }
3231         else
3232         {
3233           emptySection = !writeFullNavIndex(t,entry,indent+1,firstChild);
3234         }
3235         // end entry
3236         if (emptySection) // entry without children
3237           t << "null ]";
3238         else // entry with children
3239           t << endl << indentStr << "  ] ]";
3240       }
3241     }
3242   }
3243   return found;
3244 }
3245 #endif
3246
3247 //----------------------------------------------------------------------------
3248
3249 static void countRelatedPages(int &docPages,int &indexPages)
3250 {
3251   docPages=indexPages=0;
3252   PageSDict::Iterator pdi(*Doxygen::pageSDict);
3253   PageDef *pd=0;
3254   for (pdi.toFirst();(pd=pdi.current());++pdi)
3255   {
3256     if ( pd->visibleInIndex())
3257     {
3258       indexPages++; 
3259     }
3260     if ( pd->documentedPage())
3261     {
3262       docPages++;
3263     }
3264   }
3265 }
3266
3267 //----------------------------------------------------------------------------
3268
3269 static void writePages(PageDef *pd,FTVHelp *ftv)
3270 {
3271   //printf("writePages()=%s pd=%p mainpage=%p\n",pd->name().data(),pd,Doxygen::mainPage);
3272   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Pages);
3273   bool addToIndex = lne==0 || lne->visible();
3274   if (!addToIndex) return;
3275
3276   bool hasSubPages = pd->hasSubPages();
3277   bool hasSections = pd->hasSections();
3278
3279   if (pd->visibleInIndex())
3280   {
3281     QCString pageTitle;
3282
3283     if (pd->title().isEmpty())
3284       pageTitle=pd->name();
3285     else
3286       pageTitle=pd->title();
3287
3288     if (ftv)
3289     {
3290       //printf("*** adding %s\n",pageTitle.data());
3291       ftv->addContentsItem(
3292           hasSubPages,pageTitle,
3293           pd->getReference(),pd->getOutputFileBase(),
3294           0,hasSubPages,TRUE,pd); 
3295     }
3296     if (addToIndex && pd!=Doxygen::mainPage)
3297     {
3298       Doxygen::indexList.addContentsItem(
3299           hasSubPages,pageTitle,
3300           pd->getReference(),pd->getOutputFileBase(),
3301           0,hasSubPages,TRUE);
3302     }
3303   }
3304   if (hasSubPages && ftv) ftv->incContentsDepth();
3305   if ((hasSections || hasSubPages) && pd!=Doxygen::mainPage)
3306   {
3307     Doxygen::indexList.incContentsDepth();
3308   }
3309   if (hasSections)
3310   {
3311     pd->addSectionsToIndex();
3312   }
3313   PageSDict *subPages = pd->getSubPages();
3314   if (subPages)
3315   {
3316     PageSDict::Iterator pi(*subPages);
3317     PageDef *subPage;
3318     for (pi.toFirst();(subPage=pi.current());++pi)
3319     {
3320       writePages(subPage,ftv);
3321     }
3322   }
3323   if (hasSubPages && ftv) ftv->decContentsDepth();
3324   if ((hasSections || hasSubPages) && pd!=Doxygen::mainPage)
3325   {
3326     Doxygen::indexList.decContentsDepth();
3327   }
3328   //printf("end writePages()=%s\n",pd->title().data());
3329 }
3330
3331
3332 static void writePageIndex(OutputList &ol)
3333 {
3334   if (indexedPages==0) return;
3335   ol.pushGeneratorState();
3336   ol.disableAllBut(OutputGenerator::Html);
3337   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Pages);
3338   QCString title = lne ? lne->title() : theTranslator->trRelatedPages();
3339   startFile(ol,"pages",0,title,HLI_Pages);
3340   startTitle(ol,0);
3341   ol.parseText(title);
3342   endTitle(ol,0,0);
3343   ol.startContents();
3344   ol.startTextBlock();
3345   ol.parseText(lne ? lne->intro() : theTranslator->trRelatedPagesDescription());
3346   ol.endTextBlock();
3347
3348   {
3349     FTVHelp* ftv = new FTVHelp(FALSE);
3350     PageSDict::Iterator pdi(*Doxygen::pageSDict);
3351     PageDef *pd=0;
3352     for (pdi.toFirst();(pd=pdi.current());++pdi)
3353     {
3354       if (pd->getOuterScope()==0 || 
3355           pd->getOuterScope()->definitionType()!=Definition::TypePage
3356          )  // not a sub page
3357       {
3358         writePages(pd,ftv);
3359       }
3360     }
3361     QGString outStr;
3362     FTextStream t(&outStr);
3363     ftv->generateTreeViewInline(t);
3364     ol.writeString(outStr);
3365     delete ftv;
3366   }
3367
3368 //  ol.popGeneratorState();
3369   // ------
3370
3371   endFile(ol);
3372   ol.popGeneratorState();
3373 }
3374
3375 //----------------------------------------------------------------------------
3376
3377 static int countGroups()
3378 {
3379   int count=0;
3380   GroupSDict::Iterator gli(*Doxygen::groupSDict);
3381   GroupDef *gd;
3382   for (gli.toFirst();(gd=gli.current());++gli)
3383   {
3384     if (!gd->isReference())
3385     {
3386       gd->visited=FALSE;
3387       count++;
3388     }
3389   }
3390   return count;
3391 }
3392
3393 //----------------------------------------------------------------------------
3394
3395 static int countDirs()
3396 {
3397   int count=0;
3398   SDict<DirDef>::Iterator dli(*Doxygen::directories);
3399   DirDef *dd;
3400   for (dli.toFirst();(dd=dli.current());++dli)
3401   {
3402     if (dd->isLinkableInProject())
3403     {
3404       dd->visited=FALSE;
3405       count++;
3406     }
3407   }
3408   return count;
3409 }
3410
3411
3412 //----------------------------------------------------------------------------
3413
3414 void writeGraphInfo(OutputList &ol)
3415 {
3416   if (!Config_getBool("HAVE_DOT") || !Config_getBool("GENERATE_HTML")) return;
3417   ol.pushGeneratorState();
3418   ol.disableAllBut(OutputGenerator::Html);
3419   generateGraphLegend(Config_getString("HTML_OUTPUT"));
3420   startFile(ol,"graph_legend",0,theTranslator->trLegendTitle().data());
3421   startTitle(ol,0);
3422   ol.parseText(theTranslator->trLegendTitle());
3423   endTitle(ol,0,0);
3424   ol.startContents();
3425   bool &stripCommentsStateRef = Config_getBool("STRIP_CODE_COMMENTS");
3426   bool oldStripCommentsState = stripCommentsStateRef;
3427   // temporarily disable the stripping of comments for our own code example!
3428   stripCommentsStateRef = FALSE;
3429   QCString legendDocs = theTranslator->trLegendDocs();
3430   int s = legendDocs.find("<center>");
3431   int e = legendDocs.find("</center>");
3432   if (Config_getEnum("DOT_IMAGE_FORMAT")=="svg" && s!=-1 && e!=-1)
3433   {
3434     legendDocs = legendDocs.left(s+8) + "[!-- SVG 0 --]\n" + legendDocs.mid(e); 
3435     //printf("legendDocs=%s\n",legendDocs.data());
3436   }
3437   FileDef fd("","graph_legend");
3438   ol.parseDoc("graph_legend",1,&fd,0,legendDocs,FALSE,FALSE);
3439   stripCommentsStateRef = oldStripCommentsState;
3440   endFile(ol);
3441   ol.popGeneratorState();
3442 }
3443
3444
3445
3446 //----------------------------------------------------------------------------
3447 /*!
3448  * write groups as hierarchical trees
3449  */
3450 static void writeGroupTreeNode(OutputList &ol, GroupDef *gd, int level, FTVHelp* ftv, bool addToIndex)
3451 {
3452   //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
3453   //bool vhdlOpt    = Config_getBool("OPTIMIZE_OUTPUT_VHDL");  
3454   if (level>20)
3455   {
3456     warn(gd->getDefFileName(),gd->getDefLine(),
3457         "warning: maximum nesting level exceeded for group %s: check for possible recursive group relation!\n",gd->name().data()
3458         );
3459     return;
3460   }
3461
3462   /* Some groups should appear twice under different parent-groups.
3463    * That is why we should not check if it was visited 
3464    */
3465   if (/*!gd->visited &&*/ (!gd->isASubGroup() || level>0) &&
3466       gd->isVisible() &&
3467       (!gd->isReference() || Config_getBool("EXTERNAL_GROUPS")) // hide external groups by default
3468      )
3469   {
3470     //printf("gd->name()=%s #members=%d\n",gd->name().data(),gd->countMembers());
3471     // write group info
3472     bool hasSubGroups = gd->getSubGroups()->count()>0;
3473     bool hasSubPages = gd->getPages()->count()>0;
3474     int numSubItems = 0;
3475     if (1 /*Config_getBool("TOC_EXPAND")*/)
3476     {
3477       QListIterator<MemberList> mli(gd->getMemberLists());
3478       MemberList *ml;
3479       for (mli.toFirst();(ml=mli.current());++mli)
3480       {
3481         if (ml->listType()&MemberList::documentationLists)
3482         {
3483           numSubItems += ml->count();
3484         }
3485       }
3486       numSubItems += gd->getNamespaces()->count();
3487       numSubItems += gd->getClasses()->count();
3488       numSubItems += gd->getFiles()->count();
3489       numSubItems += gd->getDirs()->count();
3490       numSubItems += gd->getPages()->count();
3491     }
3492
3493     bool isDir = hasSubGroups || hasSubPages || numSubItems>0;
3494     //printf("gd=`%s': pageDict=%d\n",gd->name().data(),gd->pageDict->count());
3495     if (addToIndex)
3496     {
3497       Doxygen::indexList.addContentsItem(isDir,gd->groupTitle(),gd->getReference(),gd->getOutputFileBase(),0,isDir,TRUE); 
3498       Doxygen::indexList.incContentsDepth();
3499     }
3500     if (ftv)
3501     {
3502       ftv->addContentsItem(hasSubGroups,gd->groupTitle(),
3503                            gd->getReference(),gd->getOutputFileBase(),0,
3504                            FALSE,FALSE,gd); 
3505       ftv->incContentsDepth();
3506     }
3507     
3508     //ol.writeListItem();
3509     //ol.startTextLink(gd->getOutputFileBase(),0);
3510     //parseText(ol,gd->groupTitle());
3511     //ol.endTextLink();
3512
3513     ol.startIndexListItem();
3514     ol.startIndexItem(gd->getReference(),gd->getOutputFileBase());
3515     ol.parseText(gd->groupTitle());
3516     ol.endIndexItem(gd->getReference(),gd->getOutputFileBase());
3517     if (gd->isReference()) 
3518     { 
3519       ol.startTypewriter(); 
3520       ol.docify(" [external]");
3521       ol.endTypewriter();
3522     }
3523
3524     QListIterator<LayoutDocEntry> eli(LayoutDocManager::instance().docEntries(LayoutDocManager::Group));
3525     LayoutDocEntry *lde;
3526     for (eli.toFirst();(lde=eli.current());++eli)
3527     {
3528       if (lde->kind()==LayoutDocEntry::MemberDef && addToIndex)
3529       {
3530         LayoutDocEntryMemberDef *lmd = (LayoutDocEntryMemberDef*)lde;
3531         MemberList *ml = gd->getMemberList(lmd->type);
3532         if (ml)
3533         {
3534           MemberListIterator mi(*ml);
3535           MemberDef *md;
3536           for (mi.toFirst();(md=mi.current());++mi)
3537           {
3538             LockingPtr<MemberList> enumList = md->enumFieldList();
3539             bool isDir = enumList!=0 && md->isEnumerate();
3540             if (md->isVisible() && md->name().find('@')==-1)
3541             {
3542               Doxygen::indexList.addContentsItem(isDir,
3543                   md->name(),md->getReference(),
3544                   md->getOutputFileBase(),md->anchor(),FALSE,addToIndex);
3545             }
3546             if (isDir)
3547             {
3548               Doxygen::indexList.incContentsDepth();
3549               MemberListIterator emli(*enumList);
3550               MemberDef *emd;
3551               for (emli.toFirst();(emd=emli.current());++emli)
3552               {
3553                 if (emd->isVisible())
3554                 {
3555                   Doxygen::indexList.addContentsItem(FALSE,
3556                       emd->name(),emd->getReference(),emd->getOutputFileBase(),
3557                       emd->anchor(),FALSE,addToIndex);
3558                 }
3559               }
3560               Doxygen::indexList.decContentsDepth();
3561             }
3562           }
3563         }
3564       }
3565       else if (lde->kind()==LayoutDocEntry::GroupClasses && addToIndex)
3566       {
3567         ClassSDict::Iterator it(*gd->getClasses());
3568         ClassDef *cd;
3569         for (;(cd=it.current());++it)
3570         {
3571           //bool nestedClassInSameGroup = 
3572           //    cd->getOuterScope() && cd->getOuterScope()->definitionType()==Definition::TypeClass &&
3573           //    cd->getOuterScope()->partOfGroups()!=0 && cd->getOuterScope()->partOfGroups()->contains(gd);
3574           //printf("===== GroupClasses: %s visible=%d nestedClassInSameGroup=%d\n",cd->name().data(),cd->isVisible(),nestedClassInSameGroup);
3575           if (cd->isVisible() /*&& !nestedClassInSameGroup*/)
3576           {
3577             //if (cd->isEmbeddedInOuterScope())
3578             //{
3579               //printf("add class & members %d\n",addToIndex);
3580               addMembersToIndex(cd,LayoutDocManager::Class,cd->displayName(FALSE),cd->anchor(),addToIndex,TRUE);
3581             //}
3582             //else // only index the class, not its members
3583             //{
3584             //  printf("%s: add class only\n",cd->name().data());
3585             //  Doxygen::indexList.addContentsItem(FALSE,
3586             //    cd->displayName(TRUE),cd->getReference(),
3587             //    cd->getOutputFileBase(),cd->anchor(),addToIndex,TRUE);
3588             //}
3589           }
3590         }
3591       }
3592       else if (lde->kind()==LayoutDocEntry::GroupNamespaces && addToIndex)
3593       {
3594         NamespaceSDict::Iterator it(*gd->getNamespaces());
3595         NamespaceDef *nd;
3596         for (;(nd=it.current());++it)
3597         {
3598           if (nd->isVisible())
3599           {
3600             Doxygen::indexList.addContentsItem(FALSE,
3601                 nd->localName(),nd->getReference(),
3602                 nd->getOutputFileBase(),0,FALSE,FALSE);
3603           }
3604         }
3605       }
3606       else if (lde->kind()==LayoutDocEntry::GroupFiles && addToIndex)
3607       {
3608         QListIterator<FileDef> it(*gd->getFiles());
3609         FileDef *fd;
3610         for (;(fd=it.current());++it)
3611         {
3612           if (fd->isVisible())
3613           {
3614             Doxygen::indexList.addContentsItem(FALSE,
3615                 fd->displayName(),fd->getReference(),
3616                 fd->getOutputFileBase(),0,FALSE,FALSE);
3617           }
3618         }
3619       }
3620       else if (lde->kind()==LayoutDocEntry::GroupDirs && addToIndex)
3621       {
3622         QListIterator<DirDef> it(*gd->getDirs());
3623         DirDef *dd;
3624         for (;(dd=it.current());++it)
3625         {
3626           if (dd->isVisible())
3627           {
3628             Doxygen::indexList.addContentsItem(FALSE,
3629                 dd->shortName(),dd->getReference(),
3630                 dd->getOutputFileBase(),0,FALSE,FALSE);
3631           }
3632         }
3633       }
3634       else if (lde->kind()==LayoutDocEntry::GroupPageDocs && addToIndex)
3635       {
3636         SDict<PageDef>::Iterator it(*gd->getPages());
3637         PageDef *pd;
3638         for (;(pd=it.current());++it)
3639         {
3640           SectionInfo *si=0;
3641           if (!pd->name().isEmpty()) si=Doxygen::sectionDict[pd->name()];
3642           bool hasSubPages = pd->hasSubPages();
3643           bool hasSections = pd->hasSections();
3644           Doxygen::indexList.addContentsItem(
3645               hasSubPages || hasSections,
3646               convertToHtml(pd->title(),TRUE),
3647               gd->getReference(),
3648               gd->getOutputFileBase(),
3649               si ? si->label.data() : 0,
3650               hasSubPages || hasSections,
3651               TRUE); // addToNavIndex
3652           if (hasSections || hasSubPages)
3653           {
3654             Doxygen::indexList.incContentsDepth();
3655           }
3656           if (hasSections)
3657           {
3658             pd->addSectionsToIndex();
3659           }
3660           writePages(pd,0);
3661           if (hasSections || hasSubPages)
3662           {
3663             Doxygen::indexList.decContentsDepth();
3664           }
3665         }
3666       }
3667       else if (lde->kind()==LayoutDocEntry::GroupNestedGroups)
3668       {
3669         if (gd->getSubGroups()->count()>0)
3670         {
3671           startIndexHierarchy(ol,level+1);
3672           if (Config_getBool("SORT_GROUP_NAMES")) gd->sortSubGroups();
3673           QListIterator<GroupDef> gli(*gd->getSubGroups());
3674           GroupDef *subgd = 0;
3675           for (gli.toFirst();(subgd=gli.current());++gli)
3676           {
3677             writeGroupTreeNode(ol,subgd,level+1,ftv,addToIndex);
3678           }
3679           endIndexHierarchy(ol,level+1); 
3680         }
3681       }
3682     }
3683
3684     ol.endIndexListItem();
3685     
3686     if (addToIndex)
3687     {
3688       Doxygen::indexList.decContentsDepth();
3689     }
3690     if (ftv)
3691     {
3692       ftv->decContentsDepth();
3693     }
3694     //gd->visited=TRUE;
3695   }
3696 }
3697
3698 static void writeGroupHierarchy(OutputList &ol, FTVHelp* ftv,bool addToIndex)
3699 {
3700   if (ftv)
3701   {
3702     ol.pushGeneratorState(); 
3703     ol.disable(OutputGenerator::Html);
3704   }
3705   startIndexHierarchy(ol,0);
3706   if (Config_getBool("SORT_GROUP_NAMES"))
3707   {
3708     Doxygen::groupSDict->sort();
3709   }
3710   GroupSDict::Iterator gli(*Doxygen::groupSDict);
3711   GroupDef *gd;
3712   for (gli.toFirst();(gd=gli.current());++gli)
3713   {
3714     writeGroupTreeNode(ol,gd,0,ftv,addToIndex);
3715   }
3716   endIndexHierarchy(ol,0); 
3717   if (ftv)
3718   {
3719     ol.popGeneratorState(); 
3720   }
3721 }
3722
3723 #if 0
3724 static void writeGroupTree(GroupDef *gd,FTVHelp *ftv,int level,bool addToIndex)
3725 {
3726   static bool externalGroups = Config_getBool("EXTERNAL_GROUPS");
3727   /* Some groups should appear twice under different parent-groups.
3728    * That is why we should not check if it was visited 
3729    */
3730   if ((!gd->isASubGroup() || level>0) &&
3731       gd->isVisible() &&
3732       (!gd->isReference() || externalGroups) // hide external groups by default
3733      )
3734   {
3735     if (ftv)
3736     {
3737       ftv->addContentsItem(hasSubGroups,gd->groupTitle(),gd->getReference(),gd->getOutputFileBase(),0); 
3738       ftv->incContentsDepth();
3739     }
3740     if (ftv)
3741     {
3742       ftv->decContentsDepth();
3743     }
3744   }
3745 }
3746
3747 static void writeGroupTree(FTVHelp *ftv,bool addToIndex)
3748 {
3749   GroupSDict::Iterator gli(*Doxygen::groupSDict);
3750   GroupDef *gd;
3751   for (gli.toFirst();(gd=gli.current());++gli)
3752   {
3753     writeGroupTree(gd,ftv,0,addToIndex);
3754   }
3755 }
3756 #endif
3757
3758 //----------------------------------------------------------------------------
3759
3760 static void writeGroupIndex(OutputList &ol)
3761 {
3762   if (documentedGroups==0) return; 
3763   ol.pushGeneratorState(); 
3764   // 1.{
3765   ol.disable(OutputGenerator::Man);
3766   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Modules);
3767   QCString title = lne ? lne->title() : theTranslator->trModules();
3768   bool addToIndex = lne==0 || lne->visible();
3769
3770   startFile(ol,"modules",0,title,HLI_Modules);
3771   startTitle(ol,0);
3772   ol.parseText(title);
3773   endTitle(ol,0,0);
3774   ol.startContents();
3775   ol.startTextBlock();
3776   ol.parseText(lne ? lne->intro() : theTranslator->trModulesDescription());
3777   ol.endTextBlock();
3778
3779   // ---------------
3780   // Normal group index for Latex/RTF
3781   // ---------------
3782   // 2.{
3783   ol.pushGeneratorState();
3784   ol.disable(OutputGenerator::Html);
3785   Doxygen::indexList.disable();
3786
3787   writeGroupHierarchy(ol,0,FALSE);
3788
3789   Doxygen::indexList.enable();
3790   ol.popGeneratorState();
3791   // 2.}
3792
3793   // ---------------
3794   // interactive group index for HTML
3795   // ---------------
3796   // 2.{
3797   ol.pushGeneratorState(); 
3798   ol.disableAllBut(OutputGenerator::Html);
3799
3800   {
3801     if (addToIndex)
3802     {
3803       Doxygen::indexList.addContentsItem(TRUE,title,0,"modules",0,TRUE,TRUE); 
3804       Doxygen::indexList.incContentsDepth();
3805     }
3806     FTVHelp* ftv = new FTVHelp(FALSE);
3807     writeGroupHierarchy(ol,ftv,addToIndex);
3808     QGString outStr;
3809     FTextStream t(&outStr);
3810     ftv->generateTreeViewInline(t);
3811     ol.disableAllBut(OutputGenerator::Html);
3812     ol.writeString(outStr);
3813     delete ftv;
3814     if (addToIndex)
3815     {
3816       Doxygen::indexList.decContentsDepth();
3817     }
3818   }
3819   ol.popGeneratorState();
3820   // 2.}
3821
3822   endFile(ol);
3823   ol.popGeneratorState();
3824   // 1.}
3825 }
3826
3827 //----------------------------------------------------------------------------
3828
3829 #if 0
3830 static void writeDirIndex(OutputList &ol)
3831 {
3832   if (documentedDirs==0) return; 
3833   ol.pushGeneratorState(); 
3834   ol.disable(OutputGenerator::Man);
3835   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Dirs);
3836   QCString title = lne ? lne->title() : theTranslator->trDirectories();
3837   bool addToIndex=FALSE; //lne==0 || lne->visible();
3838
3839   startFile(ol,"dirs",0,title,HLI_Directories);
3840   startTitle(ol,0);
3841   ol.parseText(title);
3842   endTitle(ol,0,0);
3843   ol.startContents();
3844   ol.startTextBlock();
3845
3846   if (addToIndex)
3847   {
3848     Doxygen::indexList.addContentsItem(TRUE,title,0,"dirs",0,TRUE,TRUE); 
3849     Doxygen::indexList.incContentsDepth();
3850   }
3851   ol.parseText(lne ? lne->intro() : theTranslator->trDirDescription());
3852   ol.endTextBlock();
3853
3854   FTVHelp* ftv = 0;
3855   bool treeView=Config_getBool("USE_INLINE_TREES");
3856   if (treeView)
3857   {
3858     ftv = new FTVHelp(FALSE);
3859   }
3860
3861   writeDirHierarchy(ol,ftv,addToIndex);
3862
3863   if (ftv)
3864   {
3865     QGString outStr;
3866     FTextStream t(&outStr);
3867     ftv->generateTreeViewInline(t);
3868     ol.pushGeneratorState(); 
3869     ol.disableAllBut(OutputGenerator::Html);
3870     ol.writeString(outStr);
3871     ol.popGeneratorState();
3872     delete ftv;
3873   }
3874   if (addToIndex)
3875   {
3876     Doxygen::indexList.decContentsDepth();
3877   }
3878   endFile(ol);
3879   ol.popGeneratorState();
3880 }
3881 #endif
3882
3883 //----------------------------------------------------------------------------
3884
3885 static void writeUserGroupStubPage(OutputList &ol,LayoutNavEntry *lne)
3886 {
3887   ol.pushGeneratorState();
3888   ol.disableAllBut(OutputGenerator::Html);
3889   startFile(ol,lne->baseFile(),0,lne->title(),HLI_UserGroup);
3890   startTitle(ol,0);
3891   ol.parseText(lne->title());
3892   endTitle(ol,0,0);
3893   QListIterator<LayoutNavEntry> li(lne->children());
3894   LayoutNavEntry *entry;
3895   int count=0;
3896   for (li.toFirst();(entry=li.current());++li)
3897   {
3898     if (entry->visible()) count++;
3899   }
3900   if (count>0)
3901   {
3902     ol.writeString("<ul>\n");
3903     for (li.toFirst();(entry=li.current());++li)
3904     {
3905       if (entry->visible())
3906       {
3907         ol.writeString("<li><a href=\""+entry->url()+"\"><span>"+
3908             fixSpaces(entry->title())+"</span></a></li>\n");
3909       }
3910     }
3911     ol.writeString("</ul>\n");
3912   }
3913   endFile(ol);
3914   ol.popGeneratorState();
3915 }
3916
3917 //----------------------------------------------------------------------------
3918
3919 static bool mainPageHasTitle()
3920 {
3921   if (Doxygen::mainPage==0) return FALSE;
3922   if (Doxygen::mainPage->title().isEmpty()) return FALSE;
3923   if (Doxygen::mainPage->title().lower()=="notitle") return FALSE;
3924   return TRUE;
3925 }
3926
3927 //----------------------------------------------------------------------------
3928
3929 static void writeIndex(OutputList &ol)
3930 {
3931   static bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
3932   static bool vhdlOpt    = Config_getBool("OPTIMIZE_OUTPUT_VHDL");
3933   // save old generator state
3934   ol.pushGeneratorState();
3935
3936   QCString projPrefix;
3937   if (!Config_getString("PROJECT_NAME").isEmpty())
3938   {
3939     projPrefix=Config_getString("PROJECT_NAME")+" ";
3940   }
3941
3942   //--------------------------------------------------------------------
3943   // write HTML index
3944   //--------------------------------------------------------------------
3945   ol.disableAllBut(OutputGenerator::Html);
3946
3947   QCString defFileName = 
3948     Doxygen::mainPage ? Doxygen::mainPage->docFile().data() : "[generated]";
3949   int defLine =
3950     Doxygen::mainPage ? Doxygen::mainPage->docLine() : -1;
3951
3952   QCString title;
3953   if (!mainPageHasTitle())
3954   {
3955     title = theTranslator->trMainPage();
3956   }
3957   else 
3958   {
3959     title = filterTitle(Doxygen::mainPage->title());
3960   }
3961
3962   QCString indexName="index";
3963   ol.startFile(indexName,0,title);
3964   
3965   if (Doxygen::mainPage)
3966   {
3967     if (/*Doxygen::mainPage->hasSubPages() || */
3968         (!Config_getString("PROJECT_NAME").isEmpty() && mainPageHasTitle())
3969        ) // to avoid duplicate entries in the treeview
3970     {
3971       Doxygen::indexList.addContentsItem(Doxygen::mainPage->hasSubPages(),title,0,indexName,0,Doxygen::mainPage->hasSubPages(),TRUE); 
3972     }
3973     if (Doxygen::mainPage->hasSubPages())
3974     {
3975       writePages(Doxygen::mainPage,0);
3976     }
3977   }
3978
3979   ol.startQuickIndices();
3980   if (!Config_getBool("DISABLE_INDEX")) 
3981   {
3982     ol.writeQuickLinks(TRUE,HLI_Main,0);
3983   }
3984   ol.endQuickIndices();
3985   ol.writeSplitBar(indexName);
3986   ol.writeSearchInfo();
3987   bool headerWritten=FALSE;
3988   if (Doxygen::mainPage && !Doxygen::mainPage->title().isEmpty())
3989   {
3990     if (Doxygen::mainPage->title().lower()!="notitle")
3991     {
3992       ol.startHeaderSection();
3993       ol.startTitleHead(0);
3994       ol.parseDoc(Doxygen::mainPage->docFile(),Doxygen::mainPage->docLine(),
3995                   Doxygen::mainPage,0,Doxygen::mainPage->title(),
3996                   TRUE,FALSE,0,TRUE,FALSE);
3997       headerWritten = TRUE;
3998     }
3999   }
4000   else
4001   {
4002     if (!Config_getString("PROJECT_NAME").isEmpty())
4003     {
4004       ol.startHeaderSection();
4005       ol.startTitleHead(0);
4006       ol.parseText(projPrefix+theTranslator->trDocumentation());
4007       headerWritten = TRUE;
4008     }
4009   }
4010   if (headerWritten)
4011   {
4012     ol.endTitleHead(0,0);
4013     ol.endHeaderSection();
4014   }
4015
4016   ol.startContents();
4017   if (Config_getBool("DISABLE_INDEX") && Doxygen::mainPage==0) 
4018   {
4019     ol.writeQuickLinks(FALSE,HLI_Main,0);
4020   }
4021
4022   if (Doxygen::mainPage)
4023   {
4024     Doxygen::insideMainPage=TRUE;
4025     if (Doxygen::mainPage->showToc() && Doxygen::mainPage->hasSections())
4026     {
4027       Doxygen::mainPage->writeToc(ol);
4028     }
4029
4030     ol.startTextBlock();
4031     ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0,
4032                 Doxygen::mainPage->documentation(),TRUE,FALSE
4033                 /*,Doxygen::mainPage->sectionDict*/);
4034     ol.endTextBlock();
4035
4036     Doxygen::insideMainPage=FALSE;
4037   }
4038   
4039   endFile(ol);
4040   ol.disable(OutputGenerator::Html);
4041   
4042   //--------------------------------------------------------------------
4043   // write LaTeX/RTF index
4044   //--------------------------------------------------------------------
4045   ol.enable(OutputGenerator::Latex);
4046   ol.enable(OutputGenerator::RTF);
4047
4048   ol.startFile("refman",0,0);
4049   ol.startIndexSection(isTitlePageStart);
4050   if (!Config_getString("LATEX_HEADER").isEmpty()) 
4051   {
4052     ol.disable(OutputGenerator::Latex);
4053   }
4054
4055   if (projPrefix.isEmpty())
4056   {
4057     ol.parseText(theTranslator->trReferenceManual());
4058   }
4059   else
4060   {
4061     ol.parseText(projPrefix);
4062   }
4063
4064   if (!Config_getString("PROJECT_NUMBER").isEmpty())
4065   {
4066     ol.startProjectNumber(); 
4067     ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0,Config_getString("PROJECT_NUMBER"),FALSE,FALSE);
4068     ol.endProjectNumber();
4069   }
4070   ol.endIndexSection(isTitlePageStart);
4071   ol.startIndexSection(isTitlePageAuthor);
4072   ol.parseText(theTranslator->trGeneratedBy());
4073   ol.endIndexSection(isTitlePageAuthor);
4074   ol.enable(OutputGenerator::Latex);
4075
4076   ol.lastIndexPage();
4077   if (Doxygen::mainPage)
4078   {
4079     ol.startIndexSection(isMainPage);
4080     if (mainPageHasTitle())
4081     {
4082       ol.parseText(Doxygen::mainPage->title());
4083     }
4084     else
4085     {
4086       ol.parseText(/*projPrefix+*/theTranslator->trMainPage());
4087     }
4088     ol.endIndexSection(isMainPage);
4089   }
4090   if (documentedPages>0)
4091   {
4092     //ol.parseText(projPrefix+theTranslator->trPageDocumentation());
4093     //ol.endIndexSection(isPageDocumentation);
4094     PageSDict::Iterator pdi(*Doxygen::pageSDict);
4095     PageDef *pd=pdi.toFirst();
4096     bool first=Doxygen::mainPage==0;
4097     for (pdi.toFirst();(pd=pdi.current());++pdi)
4098     {
4099       if (!pd->getGroupDef() && !pd->isReference() && 
4100           (!pd->hasParentPage() ||                    // not inside other page
4101            (Doxygen::mainPage==pd->getOuterScope()))  // or inside main page
4102          )
4103       {
4104         bool isCitationPage = pd->name()=="citelist";
4105         if (isCitationPage)
4106         {
4107           // For LaTeX the bibliograph is already written by \bibliography
4108           ol.pushGeneratorState();
4109           ol.disable(OutputGenerator::Latex);
4110         }
4111         QCString title = pd->title();
4112         if (title.isEmpty()) title=pd->name();
4113         ol.startIndexSection(isPageDocumentation);
4114         ol.parseText(title);
4115         ol.endIndexSection(isPageDocumentation);
4116         ol.pushGeneratorState(); // write TOC title (RTF only)
4117           ol.disableAllBut(OutputGenerator::RTF);
4118           ol.startIndexSection(isPageDocumentation2);
4119           ol.parseText(title);
4120           ol.endIndexSection(isPageDocumentation2);
4121           ol.popGeneratorState();
4122         ol.writeAnchor(0,pd->name());
4123
4124         ol.writePageLink(pd->getOutputFileBase(),first);
4125         first=FALSE;
4126
4127         if (isCitationPage)
4128         {
4129           ol.popGeneratorState();
4130         }
4131       }
4132     }
4133   }
4134
4135   if (!Config_getBool("LATEX_HIDE_INDICES"))
4136   {
4137     //if (indexedPages>0)
4138     //{
4139     //  ol.startIndexSection(isPageIndex);
4140     //  ol.parseText(/*projPrefix+*/ theTranslator->trPageIndex());
4141     //  ol.endIndexSection(isPageIndex);
4142     //}
4143     if (documentedGroups>0)
4144     {
4145       ol.startIndexSection(isModuleIndex);
4146       ol.parseText(/*projPrefix+*/ theTranslator->trModuleIndex());
4147       ol.endIndexSection(isModuleIndex);
4148     }
4149     if (documentedNamespaces>0)
4150     {
4151       ol.startIndexSection(isNamespaceIndex);
4152       ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModulesIndex():theTranslator->trNamespaceIndex()));
4153       ol.endIndexSection(isNamespaceIndex);
4154     }
4155     if (hierarchyClasses>0)
4156     {
4157       ol.startIndexSection(isClassHierarchyIndex);
4158       ol.parseText(/*projPrefix+*/
4159           (fortranOpt ? theTranslator->trCompoundIndexFortran() : 
4160            vhdlOpt    ? VhdlDocGen::trDesignUnitIndex()         :
4161                         theTranslator->trHierarchicalIndex()
4162           ));
4163       ol.endIndexSection(isClassHierarchyIndex);
4164     }
4165     if (annotatedClassesPrinted>0)
4166     {
4167       ol.startIndexSection(isCompoundIndex);
4168       ol.parseText(/*projPrefix+*/
4169           (fortranOpt ? theTranslator->trCompoundIndexFortran() :
4170               vhdlOpt ? VhdlDocGen::trDesignUnitIndex()         : 
4171                         theTranslator->trCompoundIndex()
4172           ));
4173       ol.endIndexSection(isCompoundIndex);
4174     }
4175     if (documentedFiles>0)
4176     {
4177       ol.startIndexSection(isFileIndex);
4178       ol.parseText(/*projPrefix+*/theTranslator->trFileIndex());
4179       ol.endIndexSection(isFileIndex);
4180     }
4181   }
4182   if (documentedGroups>0)
4183   {
4184     ol.startIndexSection(isModuleDocumentation);
4185     ol.parseText(/*projPrefix+*/theTranslator->trModuleDocumentation());
4186     ol.endIndexSection(isModuleDocumentation);
4187   }
4188   if (documentedNamespaces>0)
4189   {
4190     ol.startIndexSection(isNamespaceDocumentation);
4191     ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trModuleDocumentation():theTranslator->trNamespaceDocumentation()));
4192     ol.endIndexSection(isNamespaceDocumentation);
4193   }
4194   if (annotatedClassesPrinted>0)
4195   {
4196     ol.startIndexSection(isClassDocumentation);
4197     ol.parseText(/*projPrefix+*/(fortranOpt?theTranslator->trTypeDocumentation():theTranslator->trClassDocumentation()));
4198     ol.endIndexSection(isClassDocumentation);
4199   }
4200   if (documentedFiles>0)
4201   {
4202     ol.startIndexSection(isFileDocumentation);
4203     ol.parseText(/*projPrefix+*/theTranslator->trFileDocumentation());
4204     ol.endIndexSection(isFileDocumentation);
4205   }
4206   if (Doxygen::exampleSDict->count()>0)
4207   {
4208     ol.startIndexSection(isExampleDocumentation);
4209     ol.parseText(/*projPrefix+*/theTranslator->trExampleDocumentation());
4210     ol.endIndexSection(isExampleDocumentation);
4211   }
4212   ol.endIndexSection(isEndIndex);
4213   endFile(ol);
4214
4215   if (Doxygen::mainPage)
4216   {
4217     Doxygen::insideMainPage=TRUE;
4218     ol.disable(OutputGenerator::Man);
4219     startFile(ol,Doxygen::mainPage->name(),0,Doxygen::mainPage->title());
4220     ol.startContents();
4221     ol.startTextBlock();
4222     ol.parseDoc(defFileName,defLine,Doxygen::mainPage,0,
4223                 Doxygen::mainPage->documentation(),FALSE,FALSE
4224                );
4225     ol.endTextBlock();
4226     endFile(ol);
4227     ol.enable(OutputGenerator::Man);
4228     Doxygen::insideMainPage=FALSE;
4229   }
4230
4231   ol.popGeneratorState();
4232 }
4233
4234 static QArray<bool> indexWritten;
4235
4236 static void writeIndexHierarchyEntries(OutputList &ol,const QList<LayoutNavEntry> &entries)
4237 {
4238   QListIterator<LayoutNavEntry> li(entries);
4239   LayoutNavEntry *lne;
4240   for (li.toFirst();(lne=li.current());++li)
4241   {
4242     LayoutNavEntry::Kind kind = lne->kind();
4243     uint index = (uint)kind;
4244     if (index>=indexWritten.size())
4245     {
4246       uint i;
4247       uint oldSize = indexWritten.size();
4248       uint newSize = index+1;
4249       indexWritten.resize(newSize);
4250       for (i=oldSize;i<newSize;i++) indexWritten.at(i)=FALSE;
4251     }
4252     //printf("starting %s kind=%d\n",lne->title().data(),lne->kind());
4253     bool addToIndex=lne==0 || lne->visible();
4254     bool needsClosing=FALSE;
4255     if (!indexWritten.at(index))
4256     {
4257       switch(kind)
4258       {
4259         case LayoutNavEntry::MainPage: 
4260           msg("Generating index page...\n");
4261           writeIndex(ol); 
4262           break;
4263         case LayoutNavEntry::Pages: 
4264           msg("Generating page index...\n");
4265           writePageIndex(ol);
4266           break;
4267         case LayoutNavEntry::Modules: 
4268           msg("Generating module index...\n");
4269           writeGroupIndex(ol);
4270           break;
4271         case LayoutNavEntry::Namespaces: 
4272           {
4273             static bool showNamespaces = Config_getBool("SHOW_NAMESPACES");
4274             if (showNamespaces)
4275             {
4276               if (documentedNamespaces>0 && addToIndex)
4277               {
4278                 Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); 
4279                 Doxygen::indexList.incContentsDepth();
4280                 needsClosing=TRUE;
4281               }
4282               if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Namespaces)!=lne) // for backward compatibility with old layout file
4283               {
4284                 msg("Generating namespace index...\n");
4285                 writeNamespaceIndex(ol);
4286               }
4287             }
4288           }
4289           break;
4290         case LayoutNavEntry::NamespaceList: 
4291           {
4292             static bool showNamespaces = Config_getBool("SHOW_NAMESPACES");
4293             if (showNamespaces)
4294             {
4295               msg("Generating namespace index...\n");
4296               writeNamespaceIndex(ol);
4297             }
4298           }
4299           break;
4300         case LayoutNavEntry::NamespaceMembers: 
4301           msg("Generating namespace member index...\n");
4302           writeNamespaceMemberIndex(ol);
4303           break;
4304         case LayoutNavEntry::Classes: 
4305           if (annotatedClasses>0 && addToIndex)
4306           {
4307             Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); 
4308             Doxygen::indexList.incContentsDepth();
4309             needsClosing=TRUE;
4310           }
4311           if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Classes)!=lne) // for backward compatibility with old layout file
4312           {
4313             msg("Generating annotated compound index...\n");
4314             writeAnnotatedIndex(ol);
4315           }
4316           break;
4317         case LayoutNavEntry::ClassList: 
4318           msg("Generating annotated compound index...\n");
4319           writeAnnotatedIndex(ol);
4320           break;
4321         case LayoutNavEntry::ClassIndex:
4322           msg("Generating alphabetical compound index...\n");
4323           writeAlphabeticalIndex(ol);
4324           break;
4325         case LayoutNavEntry::ClassHierarchy: 
4326           msg("Generating hierarchical class index...\n");
4327           writeHierarchicalIndex(ol);
4328           if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
4329           {
4330             msg("Generating graphical class hierarchy...\n");
4331             writeGraphicalClassHierarchy(ol);
4332           }
4333           break;
4334         case LayoutNavEntry::ClassMembers: 
4335           msg("Generating member index...\n");
4336           writeClassMemberIndex(ol);
4337           break;
4338         case LayoutNavEntry::Files: 
4339           {
4340             static bool showFiles = Config_getBool("SHOW_FILES");
4341             if (showFiles)
4342             {
4343               if (documentedHtmlFiles>0 && addToIndex)
4344               {
4345                 Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,0,0); 
4346                 Doxygen::indexList.incContentsDepth();
4347                 needsClosing=TRUE;
4348               }
4349               if (LayoutDocManager::instance().rootNavEntry()->find(LayoutNavEntry::Files)!=lne) // for backward compatibility with old layout file
4350               {
4351                 msg("Generating file index...\n");
4352                 writeFileIndex(ol);
4353               }
4354             }
4355           }
4356           break;
4357         case LayoutNavEntry::FileList: 
4358           {
4359             static bool showFiles = Config_getBool("SHOW_FILES");
4360             if (showFiles)
4361             {
4362               msg("Generating file index...\n");
4363               writeFileIndex(ol);
4364             }
4365           }
4366           break;
4367         case LayoutNavEntry::FileGlobals: 
4368           msg("Generating file member index...\n");
4369           writeFileMemberIndex(ol);
4370           break;
4371         case LayoutNavEntry::Examples: 
4372           msg("Generating example index...\n");
4373           writeExampleIndex(ol);
4374           break;
4375         case LayoutNavEntry::User: 
4376           {
4377             // prepend a ! or ^ marker to the URL to avoid tampering with it
4378             QCString url = correctURL(lne->url(),"!"); // add ! to relative URL
4379             if (!url.isEmpty() && url.at(0)!='!') // absolute URL
4380             {
4381               url.prepend("^"); // prepend ^ to absolute URL
4382             }
4383             bool isRef = lne->baseFile().left(4)=="@ref" || lne->baseFile().left(4)=="\\ref";
4384             Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,url,0,FALSE,isRef); 
4385           }
4386           break;
4387         case LayoutNavEntry::UserGroup:
4388           if (addToIndex)
4389           {
4390             Doxygen::indexList.addContentsItem(TRUE,lne->title(),0,lne->baseFile(),0,TRUE,TRUE); 
4391             Doxygen::indexList.incContentsDepth();
4392             needsClosing=TRUE;
4393           }
4394           writeUserGroupStubPage(ol,lne);
4395           break;
4396       }
4397       if (kind!=LayoutNavEntry::User && kind!=LayoutNavEntry::UserGroup) // User entry may appear multiple times
4398       {
4399         indexWritten.at(index)=TRUE;
4400       }
4401     }
4402     writeIndexHierarchyEntries(ol,lne->children());
4403     if (needsClosing)
4404     {
4405       switch(kind)
4406       {
4407         case LayoutNavEntry::Namespaces: 
4408         case LayoutNavEntry::Classes: 
4409         case LayoutNavEntry::Files: 
4410         case LayoutNavEntry::UserGroup: 
4411           Doxygen::indexList.decContentsDepth();
4412           break;
4413         default:
4414           break;
4415       }
4416     }
4417     //printf("ending %s kind=%d\n",lne->title().data(),lne->kind());
4418   }
4419 }
4420
4421 void writeIndexHierarchy(OutputList &ol)
4422 {
4423   LayoutNavEntry *lne = LayoutDocManager::instance().rootNavEntry();
4424   if (lne)
4425   {
4426     writeIndexHierarchyEntries(ol,lne->children());
4427   }
4428 }
4429