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