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