1 /******************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby
9  * granted. No representations are made about the suitability of this software
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17 
18 #include <algorithm>
19 #include <vector>
20 
21 #include <ctype.h>
22 
23 #include "groupdef.h"
24 #include "classdef.h"
25 #include "filedef.h"
26 #include "classlist.h"
27 #include "outputlist.h"
28 #include "namespacedef.h"
29 #include "language.h"
30 #include "util.h"
31 #include "memberlist.h"
32 #include "message.h"
33 #include "membergroup.h"
34 #include "doxygen.h"
35 #include "pagedef.h"
36 #include "docparser.h"
37 #include "searchindex.h"
38 #include "dot.h"
39 #include "dotgroupcollaboration.h"
40 #include "vhdldocgen.h"
41 #include "layout.h"
42 #include "arguments.h"
43 #include "entry.h"
44 #include "membername.h"
45 #include "dirdef.h"
46 #include "config.h"
47 #include "definitionimpl.h"
48 #include "regex.h"
49 
50 //---------------------------------------------------------------------------
51 
52 class GroupDefImpl : public DefinitionMixin<GroupDef>
53 {
54   public:
55     GroupDefImpl(const QCString &fileName,int line,const QCString &name,const QCString &title,const QCString &refFileName=QCString());
56     virtual ~GroupDefImpl();
57 
definitionType() const58     virtual DefType definitionType() const { return TypeGroup; }
codeSymbolType() const59     virtual CodeSymbolType codeSymbolType() const { return CodeSymbolType::Default; }
60     virtual QCString getOutputFileBase() const;
anchor() const61     virtual QCString anchor() const { return QCString(); }
displayName(bool=TRUE) const62     virtual QCString displayName(bool=TRUE) const { return hasGroupTitle() ? m_title : DefinitionMixin::name(); }
groupTitle() const63     virtual QCString groupTitle() const { return m_title; }
64     virtual void setGroupTitle( const QCString &newtitle );
hasGroupTitle() const65     virtual bool hasGroupTitle( ) const { return m_titleSet; }
66     virtual void addFile(const FileDef *def);
67     virtual bool addClass(const ClassDef *def);
68     virtual bool addConcept(const ConceptDef *def);
69     virtual bool addNamespace(const NamespaceDef *def);
70     virtual void addGroup(const GroupDef *def);
71     virtual void addPage(const PageDef *def);
72     virtual void addExample(const PageDef *def);
73     virtual void addDir(DirDef *dd);
74     virtual bool insertMember(const MemberDef *def,bool docOnly=FALSE);
75     virtual void removeMember(MemberDef *md);
76     virtual bool findGroup(const GroupDef *def) const; // true if def is a subgroup of this group
77     virtual void writeDocumentation(OutputList &ol);
78     virtual void writeMemberPages(OutputList &ol);
79     virtual void writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const;
80     virtual void writeTagFile(TextStream &);
81     virtual size_t numDocMembers() const;
82     virtual bool isLinkableInProject() const;
83     virtual bool isLinkable() const;
84     virtual bool isASubGroup() const;
85     virtual void computeAnchors();
86     virtual void countMembers();
87 
88     virtual void addMembersToMemberGroup();
89     virtual void distributeMemberGroupDocumentation();
90     virtual void findSectionsInDocumentation();
91 
92     virtual void addListReferences();
93     virtual void sortMemberLists();
subGrouping() const94     virtual bool subGrouping() const { return m_subGrouping; }
95 
setGroupScope(Definition * d)96     virtual void setGroupScope(Definition *d) { m_groupScope = d; }
getGroupScope() const97     virtual Definition *getGroupScope() const { return m_groupScope; }
98 
99     virtual MemberList *getMemberList(MemberListType lt) const;
getMemberLists() const100     virtual const MemberLists &getMemberLists() const { return m_memberLists; }
101 
102     /* user defined member groups */
getMemberGroups() const103     virtual const MemberGroupList &getMemberGroups() const { return m_memberGroups; }
104 
getFiles() const105     virtual const FileList &getFiles() const                    { return m_fileList; }
getClasses() const106     virtual const ClassLinkedRefMap &getClasses() const         { return m_classes; }
getConcepts() const107     virtual const ConceptLinkedRefMap &getConcepts() const      { return m_concepts; }
getNamespaces() const108     virtual const NamespaceLinkedRefMap &getNamespaces() const  { return m_namespaces; }
getSubGroups() const109     virtual const GroupList &getSubGroups() const               { return m_groups; }
getPages() const110     virtual const PageLinkedRefMap &getPages() const            { return m_pages; }
getDirs() const111     virtual const DirList & getDirs() const                     { return m_dirList; }
getExamples() const112     virtual const PageLinkedRefMap &getExamples() const         { return m_examples; }
113     virtual bool hasDetailedDescription() const;
114     virtual void sortSubGroups();
115 
116   private:
117     void addMemberListToGroup(MemberList *,bool (MemberDef::*)() const);
118     void addMemberToList(MemberListType lt,const MemberDef *md);
119     void writeMemberDeclarations(OutputList &ol,MemberListType lt,const QCString &title);
120     void writeMemberDocumentation(OutputList &ol,MemberListType lt,const QCString &title);
121     void removeMemberFromList(MemberListType lt,MemberDef *md);
122     void writeGroupGraph(OutputList &ol);
123     void writeFiles(OutputList &ol,const QCString &title);
124     void writeNamespaces(OutputList &ol,const QCString &title);
125     void writeNestedGroups(OutputList &ol,const QCString &title);
126     void writeDirs(OutputList &ol,const QCString &title);
127     void writeClasses(OutputList &ol,const QCString &title);
128     void writeConcepts(OutputList &ol,const QCString &title);
129     void writeInlineClasses(OutputList &ol);
130     void writePageDocumentation(OutputList &ol);
131     void writeDetailedDescription(OutputList &ol,const QCString &title);
132     void writeBriefDescription(OutputList &ol);
133     void writeMemberGroups(OutputList &ol);
134     void startMemberDeclarations(OutputList &ol);
135     void endMemberDeclarations(OutputList &ol);
136     void startMemberDocumentation(OutputList &ol);
137     void endMemberDocumentation(OutputList &ol);
138     void writeAuthorSection(OutputList &ol);
139     void writeSummaryLinks(OutputList &ol) const;
140     void updateLanguage(const Definition *);
141 
142     QCString             m_title;               // title of the group
143     bool                 m_titleSet;            // true if title is not the same as the name
144     QCString             m_fileName;            // base name of the generated file
145     FileList             m_fileList;            // list of files in the group
146     ClassLinkedRefMap    m_classes;             // list of classes in the group
147     ConceptLinkedRefMap  m_concepts;            // list of concepts in the group
148     NamespaceLinkedRefMap m_namespaces;         // list of namespaces in the group
149     GroupList            m_groups;              // list of sub groups.
150     PageLinkedRefMap     m_pages;               // list of pages in the group
151     PageLinkedRefMap     m_examples;            // list of examples in the group
152     DirList              m_dirList;             // list of directories in the group
153     MemberList           m_allMemberList;
154     MemberNameInfoLinkedMap m_allMemberNameInfoLinkedMap;
155     Definition *         m_groupScope;
156     MemberLists          m_memberLists;
157     MemberGroupList      m_memberGroups;
158     bool                 m_subGrouping;
159 
160 };
161 
createGroupDef(const QCString & fileName,int line,const QCString & name,const QCString & title,const QCString & refFileName)162 GroupDef *createGroupDef(const QCString &fileName,int line,const QCString &name,
163                                 const QCString &title,const QCString &refFileName)
164 {
165   return new GroupDefImpl(fileName,line,name,title,refFileName);
166 }
167 
168 
169 //---------------------------------------------------------------------------
170 
GroupDefImpl(const QCString & df,int dl,const QCString & na,const QCString & t,const QCString & refFileName)171 GroupDefImpl::GroupDefImpl(const QCString &df,int dl,const QCString &na,const QCString &t,
172                    const QCString &refFileName) : DefinitionMixin(df,dl,1,na),
173                     m_allMemberList(MemberListType_allMembersList,MemberListContainer::Group)
174 {
175   if (!refFileName.isEmpty())
176   {
177     m_fileName=stripExtension(refFileName);
178   }
179   else
180   {
181     m_fileName = convertNameToFile(QCString("group_")+na);
182   }
183   setGroupTitle( t );
184 
185   //visited = 0;
186   m_groupScope = 0;
187   m_subGrouping=Config_getBool(SUBGROUPING);
188 }
189 
~GroupDefImpl()190 GroupDefImpl::~GroupDefImpl()
191 {
192 }
193 
setGroupTitle(const QCString & t)194 void GroupDefImpl::setGroupTitle( const QCString &t )
195 {
196   if ( !t.isEmpty())
197   {
198     m_title = t;
199     m_titleSet = TRUE;
200   }
201   else
202   {
203     m_title = name();
204     m_title[0]=(char)toupper(m_title[0]);
205     m_titleSet = FALSE;
206   }
207 }
208 
209 
distributeMemberGroupDocumentation()210 void GroupDefImpl::distributeMemberGroupDocumentation()
211 {
212   for (const auto &mg : m_memberGroups)
213   {
214     mg->distributeMemberGroupDocumentation();
215   }
216 }
217 
findSectionsInDocumentation()218 void GroupDefImpl::findSectionsInDocumentation()
219 {
220   docFindSections(briefDescription(),this,docFile());
221   docFindSections(documentation(),this,docFile());
222 
223   for (const auto &mg : m_memberGroups)
224   {
225     mg->findSectionsInDocumentation(this);
226   }
227 
228   for (auto &ml : m_memberLists)
229   {
230     if (ml->listType()&MemberListType_declarationLists)
231     {
232       ml->findSectionsInDocumentation(this);
233     }
234   }
235 }
236 
addFile(const FileDef * def)237 void GroupDefImpl::addFile(const FileDef *def)
238 {
239   static bool sortBriefDocs = Config_getBool(SORT_BRIEF_DOCS);
240   if (def->isHidden()) return;
241   updateLanguage(def);
242   if (sortBriefDocs)
243     m_fileList.insert( std::upper_bound( m_fileList.begin(), m_fileList.end(), def,
244                                          [](const auto &fd1, const auto &fd2)
245                                          { return qstricmp(fd1->name(),fd2->name())<0; }),
246                        def);
247   else
248     m_fileList.push_back(def);
249 }
250 
addClass(const ClassDef * cd)251 bool GroupDefImpl::addClass(const ClassDef *cd)
252 {
253   if (cd->isHidden()) return FALSE;
254   updateLanguage(cd);
255   QCString qn = cd->name();
256   if (m_classes.find(qn)==0)
257   {
258     m_classes.add(qn,cd);
259     return TRUE;
260   }
261   return FALSE;
262 }
263 
addConcept(const ConceptDef * cd)264 bool GroupDefImpl::addConcept(const ConceptDef *cd)
265 {
266   if (cd->isHidden()) return FALSE;
267   QCString qn = cd->name();
268   if (m_concepts.find(qn)==0)
269   {
270     m_concepts.add(qn,cd);
271     return TRUE;
272   }
273   return FALSE;
274 }
275 
addNamespace(const NamespaceDef * def)276 bool GroupDefImpl::addNamespace(const NamespaceDef *def)
277 {
278   //printf("adding namespace hidden=%d\n",def->isHidden());
279   if (def->isHidden()) return false;
280   if (m_namespaces.find(def->name())==0)
281   {
282     updateLanguage(def);
283     m_namespaces.add(def->name(),def);
284     return true;
285   }
286   return false;
287 }
288 
addDir(DirDef * def)289 void GroupDefImpl::addDir(DirDef *def)
290 {
291   if (def->isHidden()) return;
292   m_dirList.push_back(def);
293 }
294 
addPage(const PageDef * def)295 void GroupDefImpl::addPage(const PageDef *def)
296 {
297   if (def->isHidden()) return;
298   //printf("Making page %s part of a group\n",qPrint(def->name));
299   m_pages.add(def->name(),def);
300   const_cast<PageDef*>(def)->makePartOfGroup(this);
301 }
302 
addExample(const PageDef * def)303 void GroupDefImpl::addExample(const PageDef *def)
304 {
305   if (def->isHidden()) return;
306   m_examples.add(def->name(),def);
307 }
308 
309 
addMembersToMemberGroup()310 void GroupDefImpl::addMembersToMemberGroup()
311 {
312   for (auto &ml : m_memberLists)
313   {
314     if (ml->listType()&MemberListType_declarationLists)
315     {
316       ::addMembersToMemberGroup(ml.get(),&m_memberGroups,this);
317     }
318   }
319 }
320 
321 
insertMember(const MemberDef * md,bool docOnly)322 bool GroupDefImpl::insertMember(const MemberDef *md,bool docOnly)
323 {
324   if (md->isHidden()) return FALSE;
325   updateLanguage(md);
326   //printf("GroupDef(%s)::insertMember(%s)\n", qPrint(title), qPrint(md->name()));
327   MemberNameInfo *mni = m_allMemberNameInfoLinkedMap.add(md->name());
328   for (auto &srcMi : *mni)
329   {
330     const MemberDef *srcMd = srcMi->memberDef();
331     if (srcMd==md) return FALSE; // already added before!
332 
333     bool sameScope = srcMd->getOuterScope()==md->getOuterScope() || // same class or namespace
334         // both inside a file => definition and declaration do not have to be in the same file
335          (srcMd->getOuterScope()->definitionType()==Definition::TypeFile &&
336              md->getOuterScope()->definitionType()==Definition::TypeFile);
337 
338     const ArgumentList &srcMdAl  = srcMd->argumentList();
339     const ArgumentList &mdAl     = md->argumentList();
340     const ArgumentList &tSrcMdAl = srcMd->templateArguments();
341     const ArgumentList &tMdAl    = md->templateArguments();
342 
343     if (srcMd->isFunction() && md->isFunction() && // both are a function
344         (tSrcMdAl.size()==tMdAl.size()) &&       // same number of template arguments
345         matchArguments2(srcMd->getOuterScope(),srcMd->getFileDef(),&srcMdAl,
346                         md->getOuterScope(),md->getFileDef(),&mdAl,
347                         TRUE
348                        ) && // matching parameters
349         sameScope // both are found in the same scope
350        )
351     {
352       MemberDefMutable *mdm = toMemberDefMutable(md);
353       if (mdm && srcMd->getGroupAlias()==0)
354       {
355         mdm->setGroupAlias(srcMd);
356       }
357       else if (mdm && md!=srcMd->getGroupAlias())
358       {
359         mdm->setGroupAlias(srcMd->getGroupAlias());
360       }
361       return FALSE; // member is the same as one that is already added
362     }
363   }
364   mni->push_back(std::make_unique<MemberInfo>(md,md->protection(),md->virtualness(),FALSE));
365   //printf("Added member!\n");
366   m_allMemberList.push_back(md);
367   switch(md->memberType())
368   {
369     case MemberType_Variable:
370       if (!docOnly)
371       {
372         addMemberToList(MemberListType_decVarMembers,md);
373       }
374       addMemberToList(MemberListType_docVarMembers,md);
375       break;
376     case MemberType_Function:
377       if (!docOnly)
378       {
379         addMemberToList(MemberListType_decFuncMembers,md);
380       }
381       addMemberToList(MemberListType_docFuncMembers,md);
382       break;
383     case MemberType_Typedef:
384       if (!docOnly)
385       {
386         addMemberToList(MemberListType_decTypedefMembers,md);
387       }
388       addMemberToList(MemberListType_docTypedefMembers,md);
389       break;
390     case MemberType_Enumeration:
391       if (!docOnly)
392       {
393         addMemberToList(MemberListType_decEnumMembers,md);
394       }
395       addMemberToList(MemberListType_docEnumMembers,md);
396       break;
397     case MemberType_EnumValue:
398       if (!docOnly)
399       {
400         addMemberToList(MemberListType_decEnumValMembers,md);
401       }
402       addMemberToList(MemberListType_docEnumValMembers,md);
403       break;
404     case MemberType_Define:
405       if (!docOnly)
406       {
407         addMemberToList(MemberListType_decDefineMembers,md);
408       }
409       addMemberToList(MemberListType_docDefineMembers,md);
410       break;
411     case MemberType_Signal:
412       if (!docOnly)
413       {
414         addMemberToList(MemberListType_decSignalMembers,md);
415       }
416       addMemberToList(MemberListType_docSignalMembers,md);
417       break;
418     case MemberType_Slot:
419       if (md->protection()==Public)
420       {
421         if (!docOnly)
422         {
423           addMemberToList(MemberListType_decPubSlotMembers,md);
424         }
425         addMemberToList(MemberListType_docPubSlotMembers,md);
426       }
427       else if (md->protection()==Protected)
428       {
429         if (!docOnly)
430         {
431           addMemberToList(MemberListType_decProSlotMembers,md);
432         }
433         addMemberToList(MemberListType_docProSlotMembers,md);
434       }
435       else
436       {
437         if (!docOnly)
438         {
439           addMemberToList(MemberListType_decPriSlotMembers,md);
440         }
441         addMemberToList(MemberListType_docPriSlotMembers,md);
442       }
443       break;
444     case MemberType_Event:
445       if (!docOnly)
446       {
447         addMemberToList(MemberListType_decEventMembers,md);
448       }
449       addMemberToList(MemberListType_docEventMembers,md);
450       break;
451     case MemberType_Property:
452       if (!docOnly)
453       {
454         addMemberToList(MemberListType_decPropMembers,md);
455       }
456       addMemberToList(MemberListType_docPropMembers,md);
457       break;
458     case MemberType_Friend:
459       if (!docOnly)
460       {
461         addMemberToList(MemberListType_decFriendMembers,md);
462       }
463       addMemberToList(MemberListType_docFriendMembers,md);
464       break;
465     default:
466       err("GroupDefImpl::insertMembers(): "
467            "member '%s' (typeid=%d) with scope '%s' inserted in group scope '%s'!\n",
468            qPrint(md->name()),md->memberType(),
469            md->getClassDef() ? qPrint(md->getClassDef()->name()) : "",
470            qPrint(name()));
471   }
472   return TRUE;
473 }
474 
removeMember(MemberDef * md)475 void GroupDefImpl::removeMember(MemberDef *md)
476 {
477   // fprintf(stderr, "GroupDef(%s)::removeMember( %s )\n", qPrint(title), qPrint(md->name()));
478   MemberNameInfo *mni = m_allMemberNameInfoLinkedMap.find(md->name());
479   if (mni)
480   {
481     m_allMemberNameInfoLinkedMap.del(md->name());
482 
483     removeMemberFromList(MemberListType_allMembersList,md);
484     switch(md->memberType())
485     {
486       case MemberType_Variable:
487 	removeMemberFromList(MemberListType_decVarMembers,md);
488         removeMemberFromList(MemberListType_docVarMembers,md);
489         break;
490       case MemberType_Function:
491         removeMemberFromList(MemberListType_decFuncMembers,md);
492         removeMemberFromList(MemberListType_docFuncMembers,md);
493         break;
494       case MemberType_Typedef:
495         removeMemberFromList(MemberListType_decTypedefMembers,md);
496         removeMemberFromList(MemberListType_docTypedefMembers,md);
497         break;
498       case MemberType_Enumeration:
499         removeMemberFromList(MemberListType_decEnumMembers,md);
500         removeMemberFromList(MemberListType_docEnumMembers,md);
501         break;
502       case MemberType_EnumValue:
503         removeMemberFromList(MemberListType_decEnumValMembers,md);
504         removeMemberFromList(MemberListType_docEnumValMembers,md);
505         break;
506       case MemberType_Define:
507         removeMemberFromList(MemberListType_decDefineMembers,md);
508         removeMemberFromList(MemberListType_docDefineMembers,md);
509         break;
510       case MemberType_Signal:
511         removeMemberFromList(MemberListType_decSignalMembers,md);
512         removeMemberFromList(MemberListType_docSignalMembers,md);
513         break;
514       case MemberType_Slot:
515         if (md->protection()==Public)
516         {
517           removeMemberFromList(MemberListType_decPubSlotMembers,md);
518           removeMemberFromList(MemberListType_docPubSlotMembers,md);
519         }
520         else if (md->protection()==Protected)
521         {
522           removeMemberFromList(MemberListType_decProSlotMembers,md);
523           removeMemberFromList(MemberListType_docProSlotMembers,md);
524         }
525         else
526         {
527           removeMemberFromList(MemberListType_decPriSlotMembers,md);
528           removeMemberFromList(MemberListType_docPriSlotMembers,md);
529         }
530         break;
531       case MemberType_Event:
532         removeMemberFromList(MemberListType_decEventMembers,md);
533         removeMemberFromList(MemberListType_docEventMembers,md);
534         break;
535       case MemberType_Property:
536         removeMemberFromList(MemberListType_decPropMembers,md);
537         removeMemberFromList(MemberListType_docPropMembers,md);
538         break;
539       case MemberType_Friend:
540         removeMemberFromList(MemberListType_decFriendMembers,md);
541         removeMemberFromList(MemberListType_docFriendMembers,md);
542         break;
543       default:
544         err("GroupDefImpl::removeMember(): unexpected member remove in file!\n");
545     }
546   }
547 }
548 
findGroup(const GroupDef * def) const549 bool GroupDefImpl::findGroup(const GroupDef *def) const
550 {
551   if (this==def)
552   {
553     return TRUE;
554   }
555   for (const auto &gd : m_groups)
556   {
557     if (gd->findGroup(def))
558     {
559       return TRUE;
560     }
561   }
562   return FALSE;
563 }
564 
addGroup(const GroupDef * def)565 void GroupDefImpl::addGroup(const GroupDef *def)
566 {
567   //printf("adding group '%s' to group '%s'\n",qPrint(def->name()),qPrint(name()));
568   //if (Config_getBool(SORT_MEMBER_DOCS))
569   //  groupList->inSort(def);
570   //else
571   m_groups.push_back(def);
572 }
573 
isASubGroup() const574 bool GroupDefImpl::isASubGroup() const
575 {
576   return !partOfGroups().empty();
577 }
578 
countMembers()579 void GroupDefImpl::countMembers()
580 {
581   for (auto &ml : m_memberLists)
582   {
583     ml->countDecMembers();
584     ml->countDocMembers();
585   }
586   for (const auto &mg : m_memberGroups)
587   {
588     mg->countDecMembers();
589     mg->countDocMembers();
590   }
591 }
592 
numDocMembers() const593 size_t GroupDefImpl::numDocMembers() const
594 {
595   return m_fileList.size()+
596          m_classes.size()+
597          m_namespaces.size()+
598          m_groups.size()+
599          m_allMemberList.size()+
600          m_pages.size()+
601          m_examples.size();
602 }
603 
604 /*! Compute the HTML anchor names for all members in the group */
computeAnchors()605 void GroupDefImpl::computeAnchors()
606 {
607   //printf("GroupDefImpl::computeAnchors()\n");
608   m_allMemberList.setAnchors();
609 }
610 
writeTagFile(TextStream & tagFile)611 void GroupDefImpl::writeTagFile(TextStream &tagFile)
612 {
613   tagFile << "  <compound kind=\"group\">\n";
614   tagFile << "    <name>" << convertToXML(name()) << "</name>\n";
615   tagFile << "    <title>" << convertToXML(m_title) << "</title>\n";
616   tagFile << "    <filename>" << addHtmlExtensionIfMissing(getOutputFileBase()) << "</filename>\n";
617   for (const auto &lde : LayoutDocManager::instance().docEntries(LayoutDocManager::Group))
618   {
619     switch (lde->kind())
620     {
621       case LayoutDocEntry::GroupClasses:
622         {
623           for (const auto &cd : m_classes)
624           {
625             if (cd->isLinkableInProject())
626             {
627               tagFile << "    <class kind=\"" << cd->compoundTypeString()
628                       << "\">" << convertToXML(cd->name()) << "</class>\n";
629             }
630           }
631         }
632         break;
633       case LayoutDocEntry::GroupConcepts:
634         {
635           for (const auto &cd : m_concepts)
636           {
637             if (cd->isLinkableInProject())
638             {
639               tagFile << "    <concept>" << convertToXML(cd->name())
640                       << "</concept>\n";
641             }
642           }
643         }
644         break;
645       case LayoutDocEntry::GroupNamespaces:
646         {
647           for (const auto &nd : m_namespaces)
648           {
649             if (nd->isLinkableInProject())
650             {
651               tagFile << "    <namespace>" << convertToXML(nd->name())
652                       << "</namespace>\n";
653             }
654           }
655         }
656         break;
657       case LayoutDocEntry::GroupFiles:
658         {
659           for (const auto &fd : m_fileList)
660           {
661             if (fd->isLinkableInProject())
662             {
663               tagFile << "    <file>" << convertToXML(fd->name()) << "</file>\n";
664             }
665           }
666         }
667         break;
668       case LayoutDocEntry::GroupPageDocs:
669         {
670           for (const auto &pd : m_pages)
671           {
672             QCString pageName = pd->getOutputFileBase();
673             if (pd->isLinkableInProject())
674             {
675               tagFile << "    <page>" << convertToXML(pageName) << "</page>\n";
676             }
677           }
678         }
679         break;
680       case LayoutDocEntry::GroupDirs:
681         {
682           for (const auto &dd : m_dirList)
683           {
684             if (dd->isLinkableInProject())
685             {
686               tagFile << "    <dir>" << convertToXML(dd->displayName()) << "</dir>\n";
687             }
688           }
689         }
690         break;
691       case LayoutDocEntry::GroupNestedGroups:
692         {
693           for (const auto &gd : m_groups)
694           {
695             if (gd->isVisible())
696             {
697               tagFile << "    <subgroup>" << convertToXML(gd->name()) << "</subgroup>\n";
698             }
699           }
700         }
701         break;
702       case LayoutDocEntry::MemberDecl:
703         {
704           const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get();
705           MemberList * ml = getMemberList(lmd->type);
706           if (ml)
707           {
708             ml->writeTagFile(tagFile);
709           }
710         }
711         break;
712       case LayoutDocEntry::MemberGroups:
713         {
714           for (const auto &mg : m_memberGroups)
715           {
716             mg->writeTagFile(tagFile);
717           }
718         }
719         break;
720       default:
721         break;
722     }
723   }
724   writeDocAnchorsToTagFile(tagFile);
725   tagFile << "  </compound>\n";
726 }
727 
writeDetailedDescription(OutputList & ol,const QCString & title)728 void GroupDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title)
729 {
730   if ((!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF))
731       || !documentation().isEmpty() || !inbodyDocumentation().isEmpty()
732      )
733   {
734     ol.pushGeneratorState();
735     if (m_pages.size()!=numDocMembers()) // not only pages -> classical layout
736     {
737       ol.pushGeneratorState();
738         ol.disable(OutputGenerator::Html);
739         ol.writeRuler();
740       ol.popGeneratorState();
741       ol.pushGeneratorState();
742         ol.disableAllBut(OutputGenerator::Html);
743         ol.writeAnchor(QCString(),"details");
744       ol.popGeneratorState();
745     }
746     else
747     {
748       ol.disableAllBut(OutputGenerator::Man); // always print title for man page
749     }
750     ol.startGroupHeader();
751     ol.parseText(title);
752     ol.endGroupHeader();
753     ol.popGeneratorState();
754 
755     // repeat brief description
756     if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF))
757     {
758       ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE,
759                      QCString(),FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
760     }
761     // write separator between brief and details
762     if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF) &&
763         !documentation().isEmpty())
764     {
765       ol.pushGeneratorState();
766       ol.disable(OutputGenerator::Man);
767       ol.disable(OutputGenerator::RTF);
768       // ol.newParagraph(); // FIXME:PARA
769       ol.enableAll();
770       ol.disableAllBut(OutputGenerator::Man);
771       ol.enable(OutputGenerator::Latex);
772       ol.writeString("\n\n");
773       ol.popGeneratorState();
774     }
775 
776     // write detailed documentation
777     if (!documentation().isEmpty())
778     {
779       ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE,
780                      QCString(),FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
781     }
782 
783     // write inbody documentation
784     if (!inbodyDocumentation().isEmpty())
785     {
786       ol.generateDoc(inbodyFile(),inbodyLine(),this,0,inbodyDocumentation()+"\n",TRUE,FALSE,
787                      QCString(),FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
788     }
789   }
790 }
791 
writeBriefDescription(OutputList & ol)792 void GroupDefImpl::writeBriefDescription(OutputList &ol)
793 {
794   if (hasBriefDescription())
795   {
796     std::unique_ptr<IDocParser> parser { createDocParser() };
797     std::unique_ptr<DocRoot>  rootNode { validatingParseDoc(*parser.get(),
798                                          briefFile(),briefLine(),this,0,
799                                          briefDescription(),TRUE,FALSE,
800                                          QCString(),TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)) };
801     if (rootNode && !rootNode->isEmpty())
802     {
803       ol.startParagraph();
804       ol.pushGeneratorState();
805       ol.disableAllBut(OutputGenerator::Man);
806       ol.writeString(" - ");
807       ol.popGeneratorState();
808       ol.writeDoc(rootNode.get(),this,0);
809       ol.pushGeneratorState();
810       ol.disable(OutputGenerator::RTF);
811       ol.writeString(" \n");
812       ol.enable(OutputGenerator::RTF);
813 
814       if (hasDetailedDescription())
815       {
816         ol.disableAllBut(OutputGenerator::Html);
817         ol.startTextLink(QCString(),"details");
818         ol.parseText(theTranslator->trMore());
819         ol.endTextLink();
820       }
821       ol.popGeneratorState();
822       ol.endParagraph();
823     }
824   }
825   ol.writeSynopsis();
826 }
827 
writeGroupGraph(OutputList & ol)828 void GroupDefImpl::writeGroupGraph(OutputList &ol)
829 {
830   if (Config_getBool(HAVE_DOT) /*&& Config_getBool(GROUP_GRAPHS)*/ )
831   {
832     DotGroupCollaboration graph(this);
833     if (!graph.isTrivial())
834     {
835       msg("Generating dependency graph for group %s\n",qPrint(qualifiedName()));
836       ol.pushGeneratorState();
837       ol.disable(OutputGenerator::Man);
838       //ol.startParagraph();
839       ol.startGroupCollaboration();
840       ol.parseText(theTranslator->trCollaborationDiagram(m_title));
841       ol.endGroupCollaboration(graph);
842       //ol.endParagraph();
843       ol.popGeneratorState();
844     }
845   }
846 }
847 
writeFiles(OutputList & ol,const QCString & title)848 void GroupDefImpl::writeFiles(OutputList &ol,const QCString &title)
849 {
850   // write list of files
851   if (!m_fileList.empty())
852   {
853     ol.startMemberHeader("files");
854     ol.parseText(title);
855     ol.endMemberHeader();
856     ol.startMemberList();
857     for (const auto &fd : m_fileList)
858     {
859       if (!fd->hasDocumentation()) continue;
860       ol.startMemberDeclaration();
861       ol.startMemberItem(fd->getOutputFileBase(),0);
862       ol.docify(theTranslator->trFile(FALSE,TRUE)+" ");
863       ol.insertMemberAlign();
864       ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),QCString(),fd->name());
865       ol.endMemberItem();
866       if (!fd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC))
867       {
868         ol.startMemberDescription(fd->getOutputFileBase());
869         ol.generateDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),FALSE,FALSE,
870                        QCString(),TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
871         ol.endMemberDescription();
872       }
873       ol.endMemberDeclaration(QCString(),QCString());
874     }
875     ol.endMemberList();
876   }
877 }
878 
writeNamespaces(OutputList & ol,const QCString & title)879 void GroupDefImpl::writeNamespaces(OutputList &ol,const QCString &title)
880 {
881   // write list of namespaces
882   m_namespaces.writeDeclaration(ol,title);
883 }
884 
writeNestedGroups(OutputList & ol,const QCString & title)885 void GroupDefImpl::writeNestedGroups(OutputList &ol,const QCString &title)
886 {
887   // write list of groups
888   int count=0;
889   for (const auto &gd : m_groups)
890   {
891     if (gd->isVisible()) count++;
892   }
893   if (count>0)
894   {
895     ol.startMemberHeader("groups");
896     ol.parseText(title);
897     ol.endMemberHeader();
898     ol.startMemberList();
899     for (const auto &gd : m_groups)
900     {
901       if (gd->isVisible())
902       {
903         if (!gd->hasDocumentation()) continue;
904         ol.startMemberDeclaration();
905         ol.startMemberItem(gd->getOutputFileBase(),0);
906         //ol.docify(theTranslator->trGroup(FALSE,TRUE));
907         //ol.docify(" ");
908         ol.insertMemberAlign();
909         ol.writeObjectLink(gd->getReference(),gd->getOutputFileBase(),QCString(),gd->groupTitle());
910         ol.endMemberItem();
911         if (!gd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC))
912         {
913           ol.startMemberDescription(gd->getOutputFileBase());
914           ol.generateDoc(briefFile(),briefLine(),gd,0,gd->briefDescription(),FALSE,FALSE,
915                          QCString(),TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
916           ol.endMemberDescription();
917         }
918         ol.endMemberDeclaration(QCString(),QCString());
919       }
920     }
921     ol.endMemberList();
922   }
923 }
924 
writeDirs(OutputList & ol,const QCString & title)925 void GroupDefImpl::writeDirs(OutputList &ol,const QCString &title)
926 {
927   // write list of directories
928   if (!m_dirList.empty())
929   {
930     ol.startMemberHeader("dirs");
931     ol.parseText(title);
932     ol.endMemberHeader();
933     ol.startMemberList();
934     for(const auto dd : m_dirList)
935     {
936       if (!dd->hasDocumentation()) continue;
937       ol.startMemberDeclaration();
938       ol.startMemberItem(dd->getOutputFileBase(),0);
939       ol.parseText(theTranslator->trDir(FALSE,TRUE));
940       ol.insertMemberAlign();
941       ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),QCString(),dd->shortName());
942       ol.endMemberItem();
943       if (!dd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC))
944       {
945         ol.startMemberDescription(dd->getOutputFileBase());
946         ol.generateDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),FALSE,FALSE,
947                        QCString(),TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
948         ol.endMemberDescription();
949       }
950       ol.endMemberDeclaration(QCString(),QCString());
951     }
952 
953     ol.endMemberList();
954   }
955 }
956 
writeClasses(OutputList & ol,const QCString & title)957 void GroupDefImpl::writeClasses(OutputList &ol,const QCString &title)
958 {
959   // write list of classes
960   m_classes.writeDeclaration(ol,0,title,FALSE);
961 }
962 
writeConcepts(OutputList & ol,const QCString & title)963 void GroupDefImpl::writeConcepts(OutputList &ol,const QCString &title)
964 {
965   // write list of concepts
966   m_concepts.writeDeclaration(ol,title,FALSE);
967 }
968 
writeInlineClasses(OutputList & ol)969 void GroupDefImpl::writeInlineClasses(OutputList &ol)
970 {
971   m_classes.writeDocumentation(ol);
972 }
973 
writePageDocumentation(OutputList & ol)974 void GroupDefImpl::writePageDocumentation(OutputList &ol)
975 {
976   for (const auto *pd : m_pages)
977   {
978     if (!pd->isReference())
979     {
980       const SectionInfo *si=0;
981       if (pd->hasTitle() && !pd->name().isEmpty() &&
982           (si=SectionManager::instance().find(pd->name()))!=0)
983       {
984         ol.startSection(si->label(),si->title(),SectionType::Subsection);
985         ol.docify(si->title());
986         ol.endSection(si->label(),SectionType::Subsection);
987       }
988       ol.startTextBlock();
989       ol.generateDoc(pd->docFile(),pd->docLine(),pd,0,(pd->documentation()+pd->inbodyDocumentation()),TRUE,FALSE,
990                      QCString(),TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
991       ol.endTextBlock();
992     }
993   }
994 }
995 
writeMemberGroups(OutputList & ol)996 void GroupDefImpl::writeMemberGroups(OutputList &ol)
997 {
998   /* write user defined member groups */
999   for (const auto &mg : m_memberGroups)
1000   {
1001     mg->writeDeclarations(ol,0,0,0,this);
1002   }
1003 }
1004 
startMemberDeclarations(OutputList & ol)1005 void GroupDefImpl::startMemberDeclarations(OutputList &ol)
1006 {
1007   ol.startMemberSections();
1008 }
1009 
endMemberDeclarations(OutputList & ol)1010 void GroupDefImpl::endMemberDeclarations(OutputList &ol)
1011 {
1012   ol.endMemberSections();
1013 }
1014 
startMemberDocumentation(OutputList & ol)1015 void GroupDefImpl::startMemberDocumentation(OutputList &ol)
1016 {
1017   //printf("** GroupDefImpl::startMemberDocumentation()\n");
1018   if (Config_getBool(SEPARATE_MEMBER_PAGES))
1019   {
1020     ol.pushGeneratorState();
1021     ol.disable(OutputGenerator::Html);
1022     Doxygen::suppressDocWarnings = TRUE;
1023   }
1024 }
1025 
endMemberDocumentation(OutputList & ol)1026 void GroupDefImpl::endMemberDocumentation(OutputList &ol)
1027 {
1028   //printf("** GroupDefImpl::endMemberDocumentation()\n");
1029   if (Config_getBool(SEPARATE_MEMBER_PAGES))
1030   {
1031     ol.popGeneratorState();
1032     Doxygen::suppressDocWarnings = FALSE;
1033   }
1034 }
1035 
writeAuthorSection(OutputList & ol)1036 void GroupDefImpl::writeAuthorSection(OutputList &ol)
1037 {
1038   // write Author section (Man only)
1039   ol.pushGeneratorState();
1040   ol.disableAllBut(OutputGenerator::Man);
1041   ol.startGroupHeader();
1042   ol.parseText(theTranslator->trAuthor(TRUE,TRUE));
1043   ol.endGroupHeader();
1044   ol.parseText(theTranslator->trGeneratedAutomatically(Config_getString(PROJECT_NAME)));
1045   ol.popGeneratorState();
1046 }
1047 
writeSummaryLinks(OutputList & ol) const1048 void GroupDefImpl::writeSummaryLinks(OutputList &ol) const
1049 {
1050   ol.pushGeneratorState();
1051   ol.disableAllBut(OutputGenerator::Html);
1052   bool first=TRUE;
1053   SrcLangExt lang = getLanguage();
1054   for (const auto &lde : LayoutDocManager::instance().docEntries(LayoutDocManager::Group))
1055   {
1056     if ((lde->kind()==LayoutDocEntry::GroupClasses      &&  m_classes.declVisible()) ||
1057         (lde->kind()==LayoutDocEntry::GroupConcepts     &&  m_concepts.declVisible()) ||
1058         (lde->kind()==LayoutDocEntry::GroupNamespaces   &&  m_namespaces.declVisible(false)) ||
1059         (lde->kind()==LayoutDocEntry::GroupFiles        && !m_fileList.empty()) ||
1060         (lde->kind()==LayoutDocEntry::GroupNestedGroups && !m_groups.empty()) ||
1061         (lde->kind()==LayoutDocEntry::GroupDirs         && !m_dirList.empty())
1062        )
1063     {
1064       const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1065       QCString label = lde->kind()==LayoutDocEntry::GroupClasses      ? "nested-classes" :
1066                        lde->kind()==LayoutDocEntry::GroupConcepts     ? "concepts"       :
1067                        lde->kind()==LayoutDocEntry::GroupNamespaces   ? "namespaces"     :
1068                        lde->kind()==LayoutDocEntry::GroupFiles        ? "files"          :
1069                        lde->kind()==LayoutDocEntry::GroupNestedGroups ? "groups"         :
1070                        "dirs";
1071       ol.writeSummaryLink(QCString(),label,ls->title(lang),first);
1072       first=FALSE;
1073     }
1074     else if (lde->kind()==LayoutDocEntry::MemberDecl)
1075     {
1076       const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get();
1077       MemberList * ml = getMemberList(lmd->type);
1078       if (ml && ml->declVisible())
1079       {
1080         ol.writeSummaryLink(QCString(),MemberList::listTypeAsString(ml->listType()),lmd->title(lang),first);
1081         first=FALSE;
1082       }
1083     }
1084   }
1085   if (!first)
1086   {
1087     ol.writeString("  </div>\n");
1088   }
1089   ol.popGeneratorState();
1090 }
1091 
writeDocumentation(OutputList & ol)1092 void GroupDefImpl::writeDocumentation(OutputList &ol)
1093 {
1094   //static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
1095   ol.pushGeneratorState();
1096   startFile(ol,getOutputFileBase(),name(),m_title,HLI_Modules);
1097 
1098   ol.startHeaderSection();
1099   writeSummaryLinks(ol);
1100   ol.startTitleHead(getOutputFileBase());
1101   ol.pushGeneratorState();
1102   ol.disable(OutputGenerator::Man);
1103   ol.parseText(m_title);
1104   ol.popGeneratorState();
1105   addGroupListToTitle(ol,this);
1106   ol.pushGeneratorState();
1107   ol.disable(OutputGenerator::Man);
1108   ol.endTitleHead(getOutputFileBase(),m_title);
1109   ol.popGeneratorState();
1110   ol.pushGeneratorState();
1111   ol.disableAllBut(OutputGenerator::Man);
1112   ol.endTitleHead(getOutputFileBase(),name());
1113   if (!m_title.isEmpty())
1114   {
1115     ol.writeString(" - ");
1116     ol.parseText(m_title);
1117   }
1118   ol.popGeneratorState();
1119   ol.endHeaderSection();
1120   ol.startContents();
1121 
1122   //---------------------------------------- start flexible part -------------------------------
1123 
1124   SrcLangExt lang=getLanguage();
1125   for (const auto &lde : LayoutDocManager::instance().docEntries(LayoutDocManager::Group))
1126   {
1127     switch (lde->kind())
1128     {
1129       case LayoutDocEntry::BriefDesc:
1130         writeBriefDescription(ol);
1131         break;
1132       case LayoutDocEntry::MemberDeclStart:
1133         startMemberDeclarations(ol);
1134         break;
1135       case LayoutDocEntry::GroupClasses:
1136         {
1137           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1138           writeClasses(ol,ls->title(lang));
1139         }
1140         break;
1141       case LayoutDocEntry::GroupConcepts:
1142         {
1143           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1144           writeConcepts(ol,ls->title(lang));
1145         }
1146         break;
1147       case LayoutDocEntry::GroupInlineClasses:
1148         {
1149           writeInlineClasses(ol);
1150         }
1151         break;
1152       case LayoutDocEntry::GroupNamespaces:
1153         {
1154           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1155           writeNamespaces(ol,ls->title(lang));
1156         }
1157         break;
1158       case LayoutDocEntry::MemberGroups:
1159         writeMemberGroups(ol);
1160         break;
1161       case LayoutDocEntry::MemberDecl:
1162         {
1163           const LayoutDocEntryMemberDecl *lmd = (const LayoutDocEntryMemberDecl*)lde.get();
1164           writeMemberDeclarations(ol,lmd->type,lmd->title(lang));
1165         }
1166         break;
1167       case LayoutDocEntry::MemberDeclEnd:
1168         endMemberDeclarations(ol);
1169         break;
1170       case LayoutDocEntry::DetailedDesc:
1171         {
1172           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1173           writeDetailedDescription(ol,ls->title(lang));
1174         }
1175         break;
1176       case LayoutDocEntry::MemberDefStart:
1177         startMemberDocumentation(ol);
1178         break;
1179       case LayoutDocEntry::MemberDef:
1180         {
1181           const LayoutDocEntryMemberDef *lmd = (const LayoutDocEntryMemberDef*)lde.get();
1182           writeMemberDocumentation(ol,lmd->type,lmd->title(lang));
1183         }
1184         break;
1185       case LayoutDocEntry::MemberDefEnd:
1186         endMemberDocumentation(ol);
1187         break;
1188       case LayoutDocEntry::GroupNestedGroups:
1189         {
1190           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1191           writeNestedGroups(ol,ls->title(lang));
1192         }
1193         break;
1194       case LayoutDocEntry::GroupPageDocs:
1195         writePageDocumentation(ol);
1196         break;
1197       case LayoutDocEntry::GroupDirs:
1198         {
1199           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1200           writeDirs(ol,ls->title(lang));
1201         }
1202         break;
1203       case LayoutDocEntry::GroupFiles:
1204         {
1205           const LayoutDocEntrySection *ls = (const LayoutDocEntrySection*)lde.get();
1206           writeFiles(ol,ls->title(lang));
1207         }
1208         break;
1209       case LayoutDocEntry::GroupGraph:
1210         writeGroupGraph(ol);
1211         break;
1212       case LayoutDocEntry::AuthorSection:
1213         writeAuthorSection(ol);
1214         break;
1215       case LayoutDocEntry::ClassIncludes:
1216       case LayoutDocEntry::ClassInheritanceGraph:
1217       case LayoutDocEntry::ClassNestedClasses:
1218       case LayoutDocEntry::ClassCollaborationGraph:
1219       case LayoutDocEntry::ClassAllMembersLink:
1220       case LayoutDocEntry::ClassUsedFiles:
1221       case LayoutDocEntry::ClassInlineClasses:
1222       case LayoutDocEntry::NamespaceNestedNamespaces:
1223       case LayoutDocEntry::NamespaceNestedConstantGroups:
1224       case LayoutDocEntry::NamespaceClasses:
1225       case LayoutDocEntry::NamespaceConcepts:
1226       case LayoutDocEntry::NamespaceInterfaces:
1227       case LayoutDocEntry::NamespaceStructs:
1228       case LayoutDocEntry::NamespaceExceptions:
1229       case LayoutDocEntry::NamespaceInlineClasses:
1230       case LayoutDocEntry::ConceptDefinition:
1231       case LayoutDocEntry::FileClasses:
1232       case LayoutDocEntry::FileConcepts:
1233       case LayoutDocEntry::FileInterfaces:
1234       case LayoutDocEntry::FileStructs:
1235       case LayoutDocEntry::FileExceptions:
1236       case LayoutDocEntry::FileNamespaces:
1237       case LayoutDocEntry::FileConstantGroups:
1238       case LayoutDocEntry::FileIncludes:
1239       case LayoutDocEntry::FileIncludeGraph:
1240       case LayoutDocEntry::FileIncludedByGraph:
1241       case LayoutDocEntry::FileSourceLink:
1242       case LayoutDocEntry::FileInlineClasses:
1243       case LayoutDocEntry::DirSubDirs:
1244       case LayoutDocEntry::DirFiles:
1245       case LayoutDocEntry::DirGraph:
1246         err("Internal inconsistency: member %d should not be part of "
1247             "LayoutDocManager::Group entry list\n",lde->kind());
1248         break;
1249     }
1250   }
1251 
1252   //---------------------------------------- end flexible part -------------------------------
1253 
1254   endFile(ol);
1255 
1256   ol.popGeneratorState();
1257 
1258   if (Config_getBool(SEPARATE_MEMBER_PAGES))
1259   {
1260     m_allMemberList.sort();
1261     writeMemberPages(ol);
1262   }
1263 
1264 }
1265 
writeMemberPages(OutputList & ol)1266 void GroupDefImpl::writeMemberPages(OutputList &ol)
1267 {
1268   ol.pushGeneratorState();
1269   ol.disableAllBut(OutputGenerator::Html);
1270 
1271   for (const auto &ml : m_memberLists)
1272   {
1273     if (ml->listType()&MemberListType_documentationLists)
1274     {
1275        ml->writeDocumentationPage(ol,name(),this);
1276     }
1277   }
1278 
1279   ol.popGeneratorState();
1280 }
1281 
writeQuickMemberLinks(OutputList & ol,const MemberDef * currentMd) const1282 void GroupDefImpl::writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const
1283 {
1284   static bool createSubDirs=Config_getBool(CREATE_SUBDIRS);
1285 
1286   ol.writeString("      <div class=\"navtab\">\n");
1287   ol.writeString("        <table>\n");
1288 
1289   for (const auto *md : m_allMemberList)
1290   {
1291     if (md->getGroupDef()==this && md->isLinkable() && !md->isEnumValue())
1292     {
1293       if (md->isLinkableInProject())
1294       {
1295         if (md==currentMd) // selected item => highlight
1296         {
1297           ol.writeString("          <tr><td class=\"navtabHL\">");
1298         }
1299         else
1300         {
1301           ol.writeString("          <tr><td class=\"navtab\">");
1302         }
1303         ol.writeString("<a class=\"navtab\" ");
1304         ol.writeString("href=\"");
1305         if (createSubDirs) ol.writeString("../../");
1306         ol.writeString(addHtmlExtensionIfMissing(md->getOutputFileBase())+"#"+md->anchor());
1307         ol.writeString("\">");
1308         ol.writeString(convertToHtml(md->localName()));
1309         ol.writeString("</a>");
1310         ol.writeString("</td></tr>\n");
1311       }
1312     }
1313   }
1314   ol.writeString("        </table>\n");
1315   ol.writeString("      </div>\n");
1316 }
1317 
1318 
1319 
1320 //---- helper functions ------------------------------------------------------
1321 
addClassToGroups(const Entry * root,ClassDef * cd)1322 void addClassToGroups(const Entry *root,ClassDef *cd)
1323 {
1324   for (const Grouping &g : root->groups)
1325   {
1326     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1327     if (gd && gd->addClass(cd))
1328     {
1329       ClassDefMutable *cdm = toClassDefMutable(cd);
1330       if (cdm)
1331       {
1332         cdm->makePartOfGroup(gd);
1333       }
1334       //printf("Compound %s: in group %s\n",qPrint(cd->name()),gd->groupTitle());
1335     }
1336   }
1337 }
1338 
addConceptToGroups(const Entry * root,ConceptDef * cd)1339 void addConceptToGroups(const Entry *root,ConceptDef *cd)
1340 {
1341   for (const Grouping &g : root->groups)
1342   {
1343     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1344     if (gd && gd->addConcept(cd))
1345     {
1346       ConceptDefMutable *cdm = toConceptDefMutable(cd);
1347       if (cdm)
1348       {
1349         cdm->makePartOfGroup(gd);
1350       }
1351       //printf("Compound %s: in group %s\n",qPrint(cd->name()),gd->groupTitle());
1352     }
1353   }
1354 }
1355 
1356 
addNamespaceToGroups(const Entry * root,NamespaceDef * nd)1357 void addNamespaceToGroups(const Entry *root,NamespaceDef *nd)
1358 {
1359   //printf("root->groups.size()=%zu\n",root->groups.size());
1360   for (const Grouping &g : root->groups)
1361   {
1362     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1363     //printf("group '%s' gd=%p\n",qPrint(g.groupname),(void*)gd);
1364     if (gd && gd->addNamespace(nd))
1365     {
1366       NamespaceDefMutable *ndm = toNamespaceDefMutable(nd);
1367       if (ndm)
1368       {
1369         ndm->makePartOfGroup(gd);
1370       }
1371       //printf("Namespace %s: in group %s\n",qPrint(nd->name()),qPrint(gd->name()));
1372     }
1373   }
1374 }
1375 
addDirToGroups(const Entry * root,DirDef * dd)1376 void addDirToGroups(const Entry *root,DirDef *dd)
1377 {
1378   //printf("*** root->groups.size()=%d\n",root->groups.size());
1379   for (const Grouping &g : root->groups)
1380   {
1381     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1382     //printf("group '%s'\n",qPrint(g->groupname));
1383     if (gd)
1384     {
1385       gd->addDir(dd);
1386       dd->makePartOfGroup(gd);
1387       //printf("Dir %s: in group %s\n",qPrint(dd->name()),qPrint(g->groupname));
1388     }
1389   }
1390 }
1391 
addGroupToGroups(const Entry * root,GroupDef * subGroup)1392 void addGroupToGroups(const Entry *root,GroupDef *subGroup)
1393 {
1394   //printf("addGroupToGroups for %s groups=%d\n",qPrint(root->name),root->groups.size());
1395   for (const Grouping &g : root->groups)
1396   {
1397     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1398     if (gd)
1399     {
1400       if (gd==subGroup)
1401       {
1402         warn(root->fileName,root->startLine,"Refusing to add group %s to itself",
1403             qPrint(gd->name()));
1404       }
1405       else if (subGroup->findGroup(gd))
1406       {
1407         warn(root->fileName,root->startLine,"Refusing to add group %s to group %s, since the latter is already a "
1408                                             "subgroup of the former\n", qPrint(subGroup->name()),qPrint(gd->name()));
1409       }
1410       else if (!gd->findGroup(subGroup))
1411       {
1412         gd->addGroup(subGroup);
1413         subGroup->makePartOfGroup(gd);
1414       }
1415     }
1416   }
1417 }
1418 
1419 /*! Add a member to the group with the highest priority */
addMemberToGroups(const Entry * root,MemberDef * md)1420 void addMemberToGroups(const Entry *root,MemberDef *md)
1421 {
1422   //printf("addMemberToGroups:  Root %p = %s, md %p=%s groups=%zu\n",
1423   //    root, qPrint(root->name), md, qPrint(md->name()), root->groups.size() );
1424 
1425   // Search entry's group list for group with highest pri.
1426   Grouping::GroupPri_t pri = Grouping::GROUPING_LOWEST;
1427   GroupDef *fgd=0;
1428   for (const Grouping &g : root->groups)
1429   {
1430     GroupDef *gd=0;
1431     if (!g.groupname.isEmpty() &&
1432         (gd=Doxygen::groupLinkedMap->find(g.groupname)) &&
1433         g.pri >= pri)
1434     {
1435       if (fgd && gd!=fgd && g.pri==pri)
1436       {
1437         warn(root->fileName, root->startLine,
1438             "Member %s found in multiple %s groups! "
1439             "The member will be put in group %s, and not in group %s",
1440             qPrint(md->name()), Grouping::getGroupPriName( pri ),
1441             qPrint(gd->name()), qPrint(fgd->name())
1442             );
1443       }
1444 
1445       fgd = gd;
1446       pri = g.pri;
1447     }
1448   }
1449   //printf("fgd=%p\n",fgd);
1450 
1451   // put member into group defined by this entry?
1452   if (fgd)
1453   {
1454     GroupDef *mgd = const_cast<GroupDef*>(md->getGroupDef());
1455     //printf("mgd=%p\n",mgd);
1456     bool insertit = FALSE;
1457     if (mgd==0)
1458     {
1459       insertit = TRUE;
1460     }
1461     else if (mgd!=fgd)
1462     {
1463       bool moveit = FALSE;
1464 
1465       // move member from one group to another if
1466       // - the new one has a higher priority
1467       // - the new entry has the same priority, but with docs where the old one had no docs
1468       if (md->getGroupPri()<pri)
1469       {
1470         moveit = TRUE;
1471       }
1472       else
1473       {
1474         if (md->getGroupPri()==pri)
1475         {
1476           if (!root->doc.isEmpty() && !md->getGroupHasDocs())
1477           {
1478             moveit = TRUE;
1479           }
1480           else if (!root->doc.isEmpty() && md->getGroupHasDocs())
1481           {
1482             warn(md->getGroupFileName(),md->getGroupStartLine(),
1483                 "Member documentation for %s found several times in %s groups!\n"
1484                 "%s:%d: The member will remain in group %s, and won't be put into group %s",
1485                 qPrint(md->name()), Grouping::getGroupPriName( pri ),
1486                 qPrint(root->fileName), root->startLine,
1487                 qPrint(mgd->name()),
1488                 qPrint(fgd->name())
1489                 );
1490           }
1491         }
1492       }
1493 
1494       if (moveit)
1495       {
1496         //printf("removeMember\n");
1497         mgd->removeMember(md);
1498         insertit = TRUE;
1499       }
1500     }
1501 
1502     if (insertit)
1503     {
1504       //printf("insertMember found at %s line %d: %s: related %s\n",
1505       //    qPrint(md->getDefFileName()),md->getDefLine(),
1506       //    qPrint(md->name()),qPrint(root->relates));
1507       bool success = fgd->insertMember(md);
1508       if (success)
1509       {
1510         MemberDefMutable *mdm = toMemberDefMutable(md);
1511         if (mdm)
1512         {
1513           //printf("insertMember successful\n");
1514           mdm->setGroupDef(fgd,pri,root->fileName,root->startLine,!root->doc.isEmpty());
1515           ClassDefMutable *cdm = toClassDefMutable(mdm->getClassDefOfAnonymousType());
1516           if (cdm)
1517           {
1518             cdm->setGroupDefForAllMembers(fgd,pri,root->fileName,root->startLine,root->doc.length() != 0);
1519           }
1520           if (mdm->isEnumerate() && mdm->getGroupDef() && md->isStrong())
1521           {
1522             for (const auto &emd : mdm->enumFieldList())
1523             {
1524               MemberDefMutable *emdm = toMemberDefMutable(emd);
1525               if (emdm && emdm->getGroupDef()==0)
1526               {
1527                 emdm->setGroupDef(mdm->getGroupDef(),mdm->getGroupPri(),
1528                                  mdm->getGroupFileName(),mdm->getGroupStartLine(),
1529                                  mdm->getGroupHasDocs());
1530               }
1531             }
1532           }
1533         }
1534       }
1535     }
1536   }
1537 }
1538 
1539 
addExampleToGroups(const Entry * root,PageDef * eg)1540 void addExampleToGroups(const Entry *root,PageDef *eg)
1541 {
1542   for (const Grouping &g : root->groups)
1543   {
1544     GroupDef *gd = Doxygen::groupLinkedMap->find(g.groupname);
1545     if (gd)
1546     {
1547       gd->addExample(eg);
1548       eg->makePartOfGroup(gd);
1549       //printf("Example %s: in group %s\n",qPrint(eg->name()),s->data());
1550     }
1551   }
1552 }
1553 
getOutputFileBase() const1554 QCString GroupDefImpl::getOutputFileBase() const
1555 {
1556   return m_fileName;
1557 }
1558 
addListReferences()1559 void GroupDefImpl::addListReferences()
1560 {
1561   {
1562     const RefItemVector &xrefItems = xrefListItems();
1563     addRefItem(xrefItems,
1564              getOutputFileBase(),
1565              theTranslator->trGroup(TRUE,TRUE),
1566              getOutputFileBase(),name(),
1567              QCString(),
1568              0
1569             );
1570   }
1571   for (const auto &mg : m_memberGroups)
1572   {
1573     mg->addListReferences(this);
1574   }
1575   for (auto &ml : m_memberLists)
1576   {
1577     if (ml->listType()&MemberListType_documentationLists)
1578     {
1579       ml->addListReferences(this);
1580     }
1581   }
1582 }
1583 
addMemberToList(MemberListType lt,const MemberDef * md)1584 void GroupDefImpl::addMemberToList(MemberListType lt,const MemberDef *md)
1585 {
1586   static bool sortBriefDocs = Config_getBool(SORT_BRIEF_DOCS);
1587   static bool sortMemberDocs = Config_getBool(SORT_MEMBER_DOCS);
1588   const auto &ml = m_memberLists.get(lt,MemberListContainer::Group);
1589   ml->setNeedsSorting(
1590       ((ml->listType()&MemberListType_declarationLists) && sortBriefDocs) ||
1591       ((ml->listType()&MemberListType_documentationLists) && sortMemberDocs));
1592   ml->push_back(md);
1593 }
1594 
1595 // performs a partial reordering to group elements together with the same scope
1596 template<class Vec>
groupClassesWithSameScope(Vec & vec)1597 static void groupClassesWithSameScope(Vec &vec)
1598 {
1599   bool done=false;
1600   while (!done) // for each iteration
1601   {
1602     done=true;
1603     for (size_t i=0; i<vec.size(); i++) // go through all items
1604     {
1605       std::string qni = vec[i]->name().str();
1606       size_t posi = qni.rfind("::");
1607       if (posi!=std::string::npos)
1608       {
1609         std::string scope = qni.substr(0,posi);
1610         auto it = std::find_if( vec.begin(), vec.end(),
1611             [&](typename Vec::Ptr &cd)
1612             { return cd->name().str()==scope; });
1613         if (it!=vec.end())
1614         {
1615           size_t idx = std::distance(vec.begin(),it);
1616           if (i<idx) // parent scope located after child scope
1617           {
1618             // to avoid reordering elements with the same parent
1619             // we skip to the last one with the same scope
1620             size_t k = idx;
1621             while (k<vec.size() && vec[k]->name().str().substr(0,posi)==scope)
1622             {
1623               idx = k;
1624               k++;
1625             }
1626             // swap the items such that i is inserted after idx
1627             for (size_t j=i; j<idx; j++)
1628             {
1629               std::swap(vec[j],vec[j+1]);
1630             }
1631             done=false;
1632           }
1633           else if (idx<i && vec[i-1]->name().str().substr(0,posi)!=scope)
1634           {
1635             // parent scope is found before the item, and the item
1636             // has some other item with a different scope in front of it
1637             // move idx to the end of range with the same scope
1638             while (idx<i && vec[idx]->name().str().substr(0,posi)==scope)
1639             {
1640               idx++;
1641             }
1642             // swap the items such that i is just after idx
1643             for (size_t j=idx; j<i; j++)
1644             {
1645               std::swap(vec[j],vec[j+1]);
1646             }
1647             done=false;
1648           }
1649         }
1650       }
1651     }
1652   }
1653 }
1654 
sortMemberLists()1655 void GroupDefImpl::sortMemberLists()
1656 {
1657   for (auto &ml : m_memberLists)
1658   {
1659     if (ml->needsSorting()) { ml->sort(); ml->setNeedsSorting(FALSE); }
1660   }
1661   if (Config_getBool(SORT_BRIEF_DOCS))
1662   {
1663     std::sort(m_dirList.begin(), m_dirList.end(), compareDirDefs);
1664 
1665     auto classComp = [](const ClassLinkedRefMap::Ptr &c1,const ClassLinkedRefMap::Ptr &c2)
1666     {
1667       return Config_getBool(SORT_BY_SCOPE_NAME)     ?
1668         qstricmp(c1->name(), c2->name())<0          :
1669         qstricmp(c1->className(), c2->className())<0;
1670     };
1671     std::sort(m_classes.begin(), m_classes.end(), classComp);
1672 
1673     auto namespaceComp = [](const NamespaceLinkedRefMap::Ptr &n1,const NamespaceLinkedRefMap::Ptr &n2)
1674     {
1675       return qstricmp(n1->name(),n2->name())<0;
1676     };
1677 
1678     std::sort(m_namespaces.begin(),m_namespaces.end(),namespaceComp);
1679   }
1680   else
1681   {
1682     groupClassesWithSameScope(m_classes);
1683     groupClassesWithSameScope(m_namespaces);
1684   }
1685 }
1686 
getMemberList(MemberListType lt) const1687 MemberList *GroupDefImpl::getMemberList(MemberListType lt) const
1688 {
1689   for (auto &ml : m_memberLists)
1690   {
1691     if (ml->listType()==lt)
1692     {
1693       return ml.get();
1694     }
1695   }
1696   return 0;
1697 }
1698 
writeMemberDeclarations(OutputList & ol,MemberListType lt,const QCString & title)1699 void GroupDefImpl::writeMemberDeclarations(OutputList &ol,MemberListType lt,const QCString &title)
1700 {
1701   static bool optimizeVhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
1702 
1703   MemberList * ml = getMemberList(lt);
1704   if (optimizeVhdl && ml)
1705   {
1706     VhdlDocGen::writeVhdlDeclarations(ml,ol,this,0,0,0);
1707     return;
1708   }
1709   if (ml)
1710   {
1711     ml->writeDeclarations(ol,0,0,0,this,title,QCString());
1712   }
1713 }
1714 
writeMemberDocumentation(OutputList & ol,MemberListType lt,const QCString & title)1715 void GroupDefImpl::writeMemberDocumentation(OutputList &ol,MemberListType lt,const QCString &title)
1716 {
1717   MemberList * ml = getMemberList(lt);
1718   if (ml) ml->writeDocumentation(ol,name(),this,title);
1719 }
1720 
removeMemberFromList(MemberListType lt,MemberDef * md)1721 void GroupDefImpl::removeMemberFromList(MemberListType lt,MemberDef *md)
1722 {
1723   MemberList *ml = getMemberList(lt);
1724   if (ml) ml->remove(md);
1725 }
1726 
sortSubGroups()1727 void GroupDefImpl::sortSubGroups()
1728 {
1729   std::sort(m_groups.begin(),
1730             m_groups.end(),
1731             [](const auto &g1,const auto &g2)
1732             { return g1->groupTitle() < g2->groupTitle(); });
1733 }
1734 
isLinkableInProject() const1735 bool GroupDefImpl::isLinkableInProject() const
1736 {
1737   return !isReference() && isLinkable();
1738 }
1739 
isLinkable() const1740 bool GroupDefImpl::isLinkable() const
1741 {
1742   return hasUserDocumentation();
1743 }
1744 
1745 // let the "programming language" for a group depend on what is inserted into it.
1746 // First item that has an associated languages determines the language for the whole group.
updateLanguage(const Definition * d)1747 void GroupDefImpl::updateLanguage(const Definition *d)
1748 {
1749   if (getLanguage()==SrcLangExt_Unknown && d->getLanguage()!=SrcLangExt_Unknown)
1750   {
1751     setLanguage(d->getLanguage());
1752   }
1753 }
1754 
hasDetailedDescription() const1755 bool GroupDefImpl::hasDetailedDescription() const
1756 {
1757   static bool repeatBrief = Config_getBool(REPEAT_BRIEF);
1758   return ((!briefDescription().isEmpty() && repeatBrief) ||
1759          !documentation().isEmpty() ||
1760          !inbodyDocumentation().isEmpty()) &&
1761          (m_pages.size()!=numDocMembers());
1762 }
1763 
1764 // --- Cast functions
1765 
toGroupDef(Definition * d)1766 GroupDef *toGroupDef(Definition *d)
1767 {
1768   if (d==0) return 0;
1769   if (d && typeid(*d)==typeid(GroupDefImpl))
1770   {
1771     return static_cast<GroupDef*>(d);
1772   }
1773   else
1774   {
1775     return 0;
1776   }
1777 }
1778 
toGroupDef(const Definition * d)1779 const GroupDef *toGroupDef(const Definition *d)
1780 {
1781   if (d==0) return 0;
1782   if (d && typeid(*d)==typeid(GroupDefImpl))
1783   {
1784     return static_cast<const GroupDef*>(d);
1785   }
1786   else
1787   {
1788     return 0;
1789   }
1790 }
1791 
1792 
1793