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