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