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