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