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