Orb/Doxygen/src/dirdef.cpp
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 #include <md5.h>
       
     2 
       
     3 #include "dirdef.h"
       
     4 #include "filename.h"
       
     5 #include "doxygen.h"
       
     6 #include "util.h"
       
     7 #include "outputlist.h"
       
     8 #include "language.h"
       
     9 #include "message.h"
       
    10 #include "dot.h"
       
    11 #include "layout.h"
       
    12 
       
    13 //----------------------------------------------------------------------
       
    14 // method implementation
       
    15 
       
    16 static int g_dirCount=0;
       
    17 
       
    18 DirDef::DirDef(const char *path) : Definition(path,1,path)
       
    19 {
       
    20   // get display name (stipping the paths mentioned in STRIP_FROM_PATH)
       
    21   m_dispName = stripFromPath(path);
       
    22   // get short name (last part of path)
       
    23   m_shortName = path;
       
    24   if (m_shortName.at(m_shortName.length()-1)=='/')
       
    25   { // strip trailing /
       
    26     m_shortName = m_shortName.left(m_shortName.length()-1);
       
    27   }
       
    28   int pi=m_shortName.findRev('/');
       
    29   if (pi!=-1) 
       
    30   { // remove everything till the last /
       
    31     m_shortName = m_shortName.mid(pi+1);
       
    32   }
       
    33   setLocalName(m_shortName);
       
    34   
       
    35   m_fileList   = new FileList;
       
    36   m_usedDirs   = new QDict<UsedDir>(257);
       
    37   m_usedDirs->setAutoDelete(TRUE);
       
    38   m_dirCount   = g_dirCount++;
       
    39   m_level=-1;
       
    40   m_parent=0;
       
    41 }
       
    42 
       
    43 DirDef::~DirDef()
       
    44 {
       
    45   delete m_fileList;
       
    46   delete m_usedDirs;
       
    47 }
       
    48 
       
    49 bool DirDef::isLinkableInProject() const 
       
    50 { 
       
    51   return !isReference() && Config_getBool("SHOW_DIRECTORIES"); 
       
    52 }
       
    53 
       
    54 bool DirDef::isLinkable() const 
       
    55 { 
       
    56   return isReference() || isLinkableInProject(); 
       
    57 }
       
    58 
       
    59 void DirDef::addSubDir(DirDef *subdir)
       
    60 {
       
    61   m_subdirs.inSort(subdir);
       
    62   subdir->setOuterScope(this);
       
    63   subdir->m_parent=this;
       
    64 }
       
    65 
       
    66 void DirDef::addFile(FileDef *fd)
       
    67 {
       
    68   m_fileList->inSort(fd);
       
    69   fd->setDirDef(this);
       
    70 }
       
    71 
       
    72 static QCString encodeDirName(const QCString &anchor)
       
    73 {
       
    74   QCString result;
       
    75 
       
    76   // convert to md5 hash
       
    77   uchar md5_sig[16];
       
    78   QCString sigStr(33);
       
    79   MD5Buffer((const unsigned char *)anchor.data(),anchor.length(),md5_sig);
       
    80   MD5SigToString(md5_sig,sigStr.data(),33);
       
    81   return sigStr;
       
    82 
       
    83   // old algorithm
       
    84 
       
    85 //  int l = anchor.length(),i;
       
    86 //  for (i=0;i<l;i++)
       
    87 //  {
       
    88 //    char c = anchor.at(i);
       
    89 //    if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'))
       
    90 //    {
       
    91 //      result+=c;
       
    92 //    }
       
    93 //    else
       
    94 //    {
       
    95 //      static char hexStr[]="0123456789ABCDEF";
       
    96 //      char escChar[]={ '_', 0, 0, 0 };
       
    97 //      escChar[1]=hexStr[c>>4];
       
    98 //      escChar[2]=hexStr[c&0xf];
       
    99 //      result+=escChar;
       
   100 //    }
       
   101 //  }
       
   102 //  return result;
       
   103 }
       
   104 
       
   105 QCString DirDef::getOutputFileBase() const
       
   106 {
       
   107   return "dir_"+encodeDirName(name());
       
   108   //return QCString().sprintf("dir_%06d",m_dirCount);
       
   109 }
       
   110 
       
   111 void DirDef::writeDetailedDescription(OutputList &ol,const QCString &title)
       
   112 {
       
   113   if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || 
       
   114       !documentation().isEmpty())
       
   115   {
       
   116     ol.writeRuler();
       
   117     ol.pushGeneratorState();
       
   118     ol.disableAllBut(OutputGenerator::Html);
       
   119       ol.writeAnchor(0,"_details");
       
   120     ol.popGeneratorState();
       
   121     ol.startGroupHeader();
       
   122     ol.parseText(title);
       
   123     ol.endGroupHeader();
       
   124 
       
   125     // repeat brief description
       
   126     if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF"))
       
   127     {
       
   128       ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE);
       
   129     }
       
   130     // separator between brief and details
       
   131     if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && 
       
   132         !documentation().isEmpty())
       
   133     {
       
   134       ol.pushGeneratorState();
       
   135         ol.disable(OutputGenerator::Man);
       
   136         ol.disable(OutputGenerator::RTF);
       
   137         // ol.newParagraph();  // FIXME:PARA
       
   138         ol.enableAll();
       
   139         ol.disableAllBut(OutputGenerator::Man);
       
   140         ol.writeString("\n\n");
       
   141       ol.popGeneratorState();
       
   142     }
       
   143 
       
   144     // write documentation
       
   145     if (!documentation().isEmpty())
       
   146     {
       
   147       ol.parseDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE);
       
   148     }
       
   149   }
       
   150 }
       
   151 
       
   152 void DirDef::writeBriefDescription(OutputList &ol)
       
   153 {
       
   154   if (!briefDescription().isEmpty()) 
       
   155   {
       
   156     ol.startParagraph();
       
   157     ol.parseDoc(briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE);
       
   158     ol.pushGeneratorState();
       
   159     ol.disable(OutputGenerator::RTF);
       
   160     ol.writeString(" \n");
       
   161     ol.enable(OutputGenerator::RTF);
       
   162 
       
   163     if (Config_getBool("REPEAT_BRIEF") ||
       
   164         !documentation().isEmpty()
       
   165        )
       
   166     {
       
   167       ol.disableAllBut(OutputGenerator::Html);
       
   168       ol.startTextLink(0,"_details");
       
   169       ol.parseText(theTranslator->trMore());
       
   170       ol.endTextLink();
       
   171     }
       
   172     ol.popGeneratorState();
       
   173 
       
   174     //ol.pushGeneratorState();
       
   175     //ol.disable(OutputGenerator::RTF);
       
   176     //ol.newParagraph();
       
   177     //ol.popGeneratorState();
       
   178     ol.endParagraph();
       
   179   }
       
   180   ol.writeSynopsis();
       
   181 }
       
   182 
       
   183 void DirDef::writeDirectoryGraph(OutputList &ol)
       
   184 {
       
   185   // write graph dependency graph
       
   186   if (/*Config_getBool("DIRECTORY_GRAPH") &&*/ Config_getBool("HAVE_DOT"))
       
   187   {
       
   188     DotDirDeps dirDep(this);
       
   189     if (!dirDep.isTrivial())
       
   190     {
       
   191       msg("Generating dependency graph for directory %s\n",displayName().data());
       
   192       ol.disable(OutputGenerator::Man);
       
   193       ol.startParagraph();
       
   194       ol.startDirDepGraph();
       
   195       //TODO: ol.parseText(theTranslator->trDirDepGraph());
       
   196       ol.endDirDepGraph(dirDep);
       
   197       ol.endParagraph();
       
   198       ol.enableAll();
       
   199     }
       
   200   }
       
   201 }
       
   202 
       
   203 void DirDef::writeSubDirList(OutputList &ol)
       
   204 {
       
   205   // write subdir list
       
   206   if (m_subdirs.count()>0)
       
   207   {
       
   208     ol.startMemberHeader();
       
   209     ol.parseText(theTranslator->trDir(TRUE,FALSE));
       
   210     ol.endMemberHeader();
       
   211     ol.startMemberList();
       
   212     DirDef *dd=m_subdirs.first();
       
   213     while (dd)
       
   214     {
       
   215       ol.startMemberItem(0);
       
   216       ol.parseText(theTranslator->trDir(FALSE,TRUE)+" ");
       
   217       ol.insertMemberAlign();
       
   218       ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName());
       
   219       ol.endMemberItem();
       
   220       if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
       
   221       {
       
   222         Doxygen::tagFile << "    <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl;
       
   223       }
       
   224       if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
       
   225       {
       
   226         ol.startParagraph();
       
   227         ol.startMemberDescription();
       
   228         ol.parseDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),
       
   229             FALSE, // indexWords
       
   230             FALSE, // isExample
       
   231             0,     // exampleName
       
   232             FALSE, // single line
       
   233             TRUE   // link from index
       
   234            );
       
   235         ol.endMemberDescription();
       
   236         ol.endParagraph();
       
   237       }
       
   238       dd=m_subdirs.next();
       
   239     }
       
   240 
       
   241     ol.endMemberList();
       
   242   }
       
   243 }
       
   244 
       
   245 void DirDef::writeFileList(OutputList &ol)
       
   246 {
       
   247   // write file list
       
   248   if (m_fileList->count()>0)
       
   249   {
       
   250     ol.startMemberHeader();
       
   251     ol.parseText(theTranslator->trFile(TRUE,FALSE));
       
   252     ol.endMemberHeader();
       
   253     ol.startMemberList();
       
   254     FileDef *fd=m_fileList->first();
       
   255     while (fd)
       
   256     {
       
   257       ol.startMemberItem(0);
       
   258       ol.docify(theTranslator->trFile(FALSE,TRUE)+" ");
       
   259       ol.insertMemberAlign();
       
   260       if (fd->isLinkable())
       
   261       {
       
   262         ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
       
   263       }
       
   264       else
       
   265       {
       
   266         ol.startBold();
       
   267         ol.docify(fd->name()); 
       
   268         ol.endBold();
       
   269       }
       
   270       if (fd->generateSourceFile())
       
   271       {
       
   272         ol.pushGeneratorState();
       
   273         ol.disableAllBut(OutputGenerator::Html);
       
   274         ol.docify(" ");
       
   275         ol.startTextLink(fd->includeName(),0);
       
   276         ol.docify("[");
       
   277         ol.parseText(theTranslator->trCode());
       
   278         ol.docify("]");
       
   279         ol.endTextLink();
       
   280         ol.popGeneratorState();
       
   281       }
       
   282       if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
       
   283       {
       
   284         Doxygen::tagFile << "    <file>" << convertToXML(fd->name()) << "</file>" << endl;
       
   285       }
       
   286       ol.endMemberItem();
       
   287       if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
       
   288       {
       
   289         ol.startParagraph();
       
   290         ol.startMemberDescription();
       
   291         ol.parseDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),
       
   292             FALSE, // indexWords
       
   293             FALSE, // isExample
       
   294             0,     // exampleName
       
   295             FALSE, // single line
       
   296             TRUE   // link from index
       
   297            );
       
   298         ol.endMemberDescription();
       
   299         ol.endParagraph();
       
   300       }
       
   301       fd=m_fileList->next();
       
   302     }
       
   303     ol.endMemberList();
       
   304   }
       
   305 }
       
   306 
       
   307 void DirDef::startMemberDeclarations(OutputList &ol)
       
   308 {
       
   309   ol.startMemberSections();
       
   310 }
       
   311 
       
   312 void DirDef::endMemberDeclarations(OutputList &ol)
       
   313 {
       
   314   ol.endMemberSections();
       
   315 }
       
   316 
       
   317 void DirDef::writeDocumentation(OutputList &ol)
       
   318 {
       
   319   ol.pushGeneratorState();
       
   320   
       
   321   QCString shortTitle=theTranslator->trDirReference(m_shortName);
       
   322   QCString title=theTranslator->trDirReference(m_dispName);
       
   323   startFile(ol,getOutputFileBase(),name(),title,HLI_None,TRUE);
       
   324 
       
   325   // write navigation path
       
   326   writeNavigationPath(ol);
       
   327 
       
   328   ol.endQuickIndices();
       
   329   ol.startContents();
       
   330 
       
   331   startTitle(ol,getOutputFileBase());
       
   332   ol.pushGeneratorState();
       
   333     ol.disableAllBut(OutputGenerator::Html);
       
   334     ol.parseText(shortTitle);
       
   335     ol.enableAll();
       
   336     ol.disable(OutputGenerator::Html);
       
   337     ol.parseText(title);
       
   338   ol.popGeneratorState();
       
   339   endTitle(ol,getOutputFileBase(),title);
       
   340 
       
   341   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
       
   342   {
       
   343     Doxygen::tagFile << "  <compound kind=\"dir\">" << endl;
       
   344     Doxygen::tagFile << "    <name>" << convertToXML(displayName()) << "</name>" << endl;
       
   345     Doxygen::tagFile << "    <path>" << convertToXML(name()) << "</path>" << endl;
       
   346     Doxygen::tagFile << "    <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl;
       
   347   }
       
   348   
       
   349   //---------------------------------------- start flexible part -------------------------------
       
   350 
       
   351   QListIterator<LayoutDocEntry> eli(
       
   352       LayoutDocManager::instance().docEntries(LayoutDocManager::Directory));
       
   353   LayoutDocEntry *lde;
       
   354   for (eli.toFirst();(lde=eli.current());++eli)
       
   355   {
       
   356     switch (lde->kind())
       
   357     {
       
   358       case LayoutDocEntry::BriefDesc: 
       
   359         writeBriefDescription(ol);
       
   360         break; 
       
   361       case LayoutDocEntry::DirGraph: 
       
   362         writeDirectoryGraph(ol);
       
   363         break; 
       
   364       case LayoutDocEntry::MemberDeclStart: 
       
   365         startMemberDeclarations(ol);
       
   366         break; 
       
   367       case LayoutDocEntry::DirSubDirs: 
       
   368         writeSubDirList(ol);
       
   369         break; 
       
   370       case LayoutDocEntry::DirFiles: 
       
   371         writeFileList(ol);
       
   372         break; 
       
   373       case LayoutDocEntry::MemberDeclEnd: 
       
   374         endMemberDeclarations(ol);
       
   375         break;
       
   376       case LayoutDocEntry::DetailedDesc: 
       
   377         {
       
   378           LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
       
   379           writeDetailedDescription(ol,ls->title);
       
   380         }
       
   381         break;
       
   382       case LayoutDocEntry::ClassIncludes:
       
   383       case LayoutDocEntry::ClassInheritanceGraph:
       
   384       case LayoutDocEntry::ClassNestedClasses:
       
   385       case LayoutDocEntry::ClassCollaborationGraph:
       
   386       case LayoutDocEntry::ClassAllMembersLink:
       
   387       case LayoutDocEntry::ClassUsedFiles:
       
   388       case LayoutDocEntry::NamespaceNestedNamespaces:
       
   389       case LayoutDocEntry::NamespaceClasses:
       
   390       case LayoutDocEntry::FileClasses:
       
   391       case LayoutDocEntry::FileNamespaces:
       
   392       case LayoutDocEntry::FileIncludes:
       
   393       case LayoutDocEntry::FileIncludeGraph:
       
   394       case LayoutDocEntry::FileIncludedByGraph: 
       
   395       case LayoutDocEntry::FileSourceLink:
       
   396       case LayoutDocEntry::GroupClasses: 
       
   397       case LayoutDocEntry::GroupNamespaces:
       
   398       case LayoutDocEntry::GroupDirs: 
       
   399       case LayoutDocEntry::GroupNestedGroups: 
       
   400       case LayoutDocEntry::GroupFiles:
       
   401       case LayoutDocEntry::GroupGraph: 
       
   402       case LayoutDocEntry::GroupPageDocs:
       
   403       case LayoutDocEntry::AuthorSection:
       
   404       case LayoutDocEntry::MemberGroups:
       
   405       case LayoutDocEntry::MemberDecl:
       
   406       case LayoutDocEntry::MemberDef:
       
   407       case LayoutDocEntry::MemberDefStart:
       
   408       case LayoutDocEntry::MemberDefEnd:
       
   409         err("Internal inconsistency: member %d should not be part of "
       
   410             "LayoutDocManager::Directory entry list\n",lde->kind());
       
   411         break;
       
   412     }
       
   413   }
       
   414 
       
   415   //---------------------------------------- end flexible part -------------------------------
       
   416 
       
   417   if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
       
   418   {
       
   419     writeDocAnchorsToTagFile();
       
   420     Doxygen::tagFile << "  </compound>" << endl;
       
   421   }
       
   422 
       
   423   endFile(ol); 
       
   424   ol.popGeneratorState();
       
   425 
       
   426 
       
   427 }
       
   428 
       
   429 #if 0
       
   430 void DirDef::writePathFragment(OutputList &ol) const
       
   431 {
       
   432   if (m_parent)
       
   433   {
       
   434     m_parent->writePathFragment(ol);
       
   435     ol.writeString("&nbsp;/&nbsp;");
       
   436   }
       
   437   ol.writeObjectLink(getReference(),getOutputFileBase(),0,shortName());
       
   438 }
       
   439 
       
   440 void DirDef::writeNavigationPath(OutputList &ol)
       
   441 {
       
   442   ol.pushGeneratorState();
       
   443   ol.disableAllBut(OutputGenerator::Html);
       
   444 
       
   445   ol.writeString("<div class=\"nav\">\n");
       
   446   writePathFragment(ol);
       
   447   ol.writeString("</div>\n");
       
   448 
       
   449   ol.popGeneratorState();
       
   450 }
       
   451 #endif
       
   452 
       
   453 void DirDef::setLevel()
       
   454 {
       
   455   if (m_level==-1) // level not set before
       
   456   {
       
   457     DirDef *p = parent();
       
   458     if (p)
       
   459     {
       
   460       p->setLevel();
       
   461       m_level = p->level()+1;
       
   462     }
       
   463     else
       
   464     {
       
   465       m_level = 0;
       
   466     }
       
   467   }
       
   468 }
       
   469 
       
   470 /** Add as "uses" dependency between \a this dir and \a dir,
       
   471  *  that was caused by a dependency on file \a fd.
       
   472  */ 
       
   473 void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd,
       
   474                                FileDef *dstFd,bool inherited)
       
   475 {
       
   476   if (this==dir) return; // do not add self-dependencies
       
   477   //static int count=0;
       
   478   //printf("  %d add dependency %s->%s due to %s->%s\n",
       
   479   //    count++,shortName().data(),
       
   480   //    dir->shortName().data(),
       
   481   //    srcFd->name().data(),
       
   482   //    dstFd->name().data());
       
   483 
       
   484   // levels match => add direct dependency
       
   485   bool added=FALSE;
       
   486   UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase());
       
   487   if (usedDir) // dir dependency already present
       
   488   {
       
   489      FilePair *usedPair = usedDir->findFilePair(
       
   490          srcFd->getOutputFileBase()+dstFd->getOutputFileBase());
       
   491      if (usedPair==0) // new file dependency
       
   492      {
       
   493        //printf("  => new file\n");
       
   494        usedDir->addFileDep(srcFd,dstFd); 
       
   495        added=TRUE;
       
   496      }
       
   497      else
       
   498      {
       
   499        // dir & file dependency already added
       
   500      }
       
   501   }
       
   502   else // new directory dependency
       
   503   {
       
   504     //printf("  => new file\n");
       
   505     usedDir = new UsedDir(dir,inherited);
       
   506     usedDir->addFileDep(srcFd,dstFd); 
       
   507     m_usedDirs->insert(dir->getOutputFileBase(),usedDir);
       
   508     added=TRUE;
       
   509   }
       
   510   if (added)
       
   511   {
       
   512     if (dir->parent())
       
   513     {
       
   514       // add relation to parent of used dir
       
   515       addUsesDependency(dir->parent(),srcFd,dstFd,inherited);
       
   516     }
       
   517     if (parent())
       
   518     {
       
   519       // add relation for the parent of this dir as well
       
   520       parent()->addUsesDependency(dir,srcFd,dstFd,TRUE);
       
   521     }
       
   522   }
       
   523 }
       
   524 
       
   525 /** Computes the dependencies between directories
       
   526  */
       
   527 void DirDef::computeDependencies()
       
   528 {
       
   529   FileList *fl = m_fileList;
       
   530   if (fl) 
       
   531   {
       
   532     QListIterator<FileDef> fli(*fl);
       
   533     FileDef *fd;
       
   534     for (fli.toFirst();(fd=fli.current());++fli) // foreach file in dir dd
       
   535     {
       
   536       //printf("  File %s\n",fd->name().data());
       
   537       //printf("** dir=%s file=%s\n",shortName().data(),fd->name().data());
       
   538       QList<IncludeInfo> *ifl = fd->includeFileList();
       
   539       if (ifl)
       
   540       {
       
   541         QListIterator<IncludeInfo> ifli(*ifl); 
       
   542         IncludeInfo *ii;
       
   543         for (ifli.toFirst();(ii=ifli.current());++ifli) // foreach include file
       
   544         {
       
   545           //printf("  > %s\n",ii->includeName.data());
       
   546           //printf("    #include %s\n",ii->includeName.data());
       
   547           if (ii->fileDef && ii->fileDef->isLinkable()) // linkable file
       
   548           {
       
   549             DirDef *usedDir = ii->fileDef->getDirDef();
       
   550             if (usedDir)
       
   551             {
       
   552               // add dependency: thisDir->usedDir
       
   553               //static int count=0;
       
   554               //printf("      %d: add dependency %s->%s\n",count++,name().data(),usedDir->name().data());
       
   555               addUsesDependency(usedDir,fd,ii->fileDef,FALSE);
       
   556             }
       
   557           } 
       
   558         }
       
   559       }
       
   560     }
       
   561   }
       
   562 }
       
   563 
       
   564 bool DirDef::isParentOf(DirDef *dir) const
       
   565 {
       
   566   if (dir->parent()==this) // this is a parent of dir 
       
   567     return TRUE;
       
   568   else if (dir->parent()) // repeat for the parent of dir
       
   569     return isParentOf(dir->parent()); 
       
   570   else
       
   571     return FALSE;
       
   572 }
       
   573 
       
   574 bool DirDef::depGraphIsTrivial() const
       
   575 {
       
   576   return FALSE;
       
   577 }
       
   578 
       
   579 //----------------------------------------------------------------------
       
   580 
       
   581 int FilePairDict::compareItems(GCI item1,GCI item2)
       
   582 {
       
   583   FilePair *left  = (FilePair*)item1;
       
   584   FilePair *right = (FilePair*)item2;
       
   585   int orderHi = stricmp(left->source()->name(),right->source()->name());
       
   586   int orderLo = stricmp(left->destination()->name(),right->destination()->name());
       
   587   return orderHi==0 ? orderLo : orderHi;
       
   588 }
       
   589 
       
   590 //----------------------------------------------------------------------
       
   591 
       
   592 UsedDir::UsedDir(DirDef *dir,bool inherited) :
       
   593    m_dir(dir), m_filePairs(7), m_inherited(inherited)
       
   594 {
       
   595   m_filePairs.setAutoDelete(TRUE);
       
   596 }
       
   597 
       
   598 UsedDir::~UsedDir()
       
   599 {
       
   600 }
       
   601 
       
   602 
       
   603 void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd)
       
   604 {
       
   605   m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(),
       
   606                      new FilePair(srcFd,dstFd));
       
   607 }
       
   608 
       
   609 FilePair *UsedDir::findFilePair(const char *name)
       
   610 {
       
   611   QCString n=name;
       
   612   return n.isEmpty() ? 0 : m_filePairs.find(n);
       
   613 }
       
   614 
       
   615 DirDef *DirDef::createNewDir(const char *path)
       
   616 {
       
   617   ASSERT(path!=0);
       
   618   DirDef *dir = Doxygen::directories->find(path);
       
   619   if (dir==0) // new dir
       
   620   {
       
   621     //printf("Adding new dir %s\n",path);
       
   622     dir = new DirDef(path);
       
   623     //printf("createNewDir %s short=%s\n",path,dir->shortName().data());
       
   624     Doxygen::directories->inSort(path,dir);
       
   625   }
       
   626   return dir;
       
   627 }
       
   628 
       
   629 bool DirDef::matchPath(const QCString &path,QStrList &l)
       
   630 {
       
   631   const char *s=l.first();
       
   632   while (s)
       
   633   {
       
   634     QCString prefix = s;
       
   635     if (stricmp(prefix.left(path.length()),path)==0) // case insensitive compare
       
   636     {
       
   637       return TRUE;
       
   638     }
       
   639     s = l.next();
       
   640   }
       
   641   return FALSE;
       
   642 }
       
   643 
       
   644 /*! strip part of \a path if it matches
       
   645  *  one of the paths in the Config_getList("STRIP_FROM_PATH") list
       
   646  */
       
   647 DirDef *DirDef::mergeDirectoryInTree(const QCString &path)
       
   648 {
       
   649   //printf("DirDef::mergeDirectoryInTree(%s)\n",path.data());
       
   650   int p=0,i=0;
       
   651   DirDef *dir=0;
       
   652   while ((i=path.find('/',p))!=-1)
       
   653   {
       
   654     QCString part=path.left(i+1);
       
   655     if (!matchPath(part,Config_getList("STRIP_FROM_PATH")) && part!="/")
       
   656     {
       
   657       dir=createNewDir(part); 
       
   658     }
       
   659     p=i+1;
       
   660   }
       
   661   return dir;
       
   662 }
       
   663 
       
   664 void DirDef::writeDepGraph(QTextStream &t)
       
   665 {
       
   666     writeDotDirDepGraph(t,this);
       
   667 }
       
   668 
       
   669 //----------------------------------------------------------------------
       
   670 
       
   671 static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target)
       
   672 {
       
   673   if (target->parent()!=root) 
       
   674   {
       
   675     writePartialDirPath(ol,root,target->parent());
       
   676     ol.writeString("&nbsp;/&nbsp;");
       
   677   }
       
   678   ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName());
       
   679 }
       
   680 
       
   681 static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd)
       
   682 {
       
   683   if (fd->getDirDef() && fd->getDirDef()!=root)
       
   684   {
       
   685     writePartialDirPath(ol,root,fd->getDirDef());
       
   686     ol.writeString("&nbsp;/&nbsp;");
       
   687   }
       
   688   if (fd->isLinkable())
       
   689   {
       
   690     ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
       
   691   }
       
   692   else
       
   693   {
       
   694     ol.startBold();
       
   695     ol.docify(fd->name());
       
   696     ol.endBold();
       
   697   }
       
   698 }
       
   699 
       
   700 void DirRelation::writeDocumentation(OutputList &ol)
       
   701 {
       
   702   ol.pushGeneratorState();
       
   703   ol.disableAllBut(OutputGenerator::Html);
       
   704 
       
   705   QCString shortTitle=theTranslator->trDirRelation(
       
   706                       m_src->shortName()+" &rarr; "+
       
   707                       m_dst->dir()->shortName());
       
   708   QCString title=theTranslator->trDirRelation(
       
   709                  m_src->displayName()+" -> "+
       
   710                  m_dst->dir()->shortName());
       
   711   startFile(ol,getOutputFileBase(),getOutputFileBase(),title);
       
   712 
       
   713   // write navigation path
       
   714   m_src->writeNavigationPath(ol);
       
   715 
       
   716   //startTitle(ol,getOutputFileBase());
       
   717   //  ol.parseText(shortTitle);
       
   718   //endTitle(ol,getOutputFileBase(),title);
       
   719   ol.writeString("<h3>"+shortTitle+"</h3>");
       
   720   
       
   721   ol.writeString("<table class=\"dirtab\">");
       
   722   ol.writeString("<tr class=\"dirtab\">");
       
   723   // TODO: translate me! "File in %s"
       
   724   ol.writeString("<th class=\"dirtab\">File in ");
       
   725   m_src->writePathFragment(ol);
       
   726   ol.writeString("</th>");
       
   727   // TODO: translate me! "Includes file in %s"
       
   728   ol.writeString("<th class=\"dirtab\">Includes file in ");
       
   729   m_dst->dir()->writePathFragment(ol);
       
   730   ol.writeString("</th>");
       
   731   ol.writeString("</tr>");
       
   732 
       
   733   SDict<FilePair>::Iterator fpi(m_dst->filePairs());
       
   734   FilePair *fp;
       
   735   for (fpi.toFirst();(fp=fpi.current());++fpi)
       
   736   {
       
   737     ol.writeString("<tr class=\"dirtab\">");
       
   738     ol.writeString("<td class=\"dirtab\">");
       
   739     writePartialFilePath(ol,m_src,fp->source());
       
   740     ol.writeString("</td>");
       
   741     ol.writeString("<td class=\"dirtab\">");
       
   742     writePartialFilePath(ol,m_dst->dir(),fp->destination());
       
   743     ol.writeString("</td>");
       
   744     ol.writeString("</tr>");
       
   745   }
       
   746   ol.writeString("</table>");
       
   747   
       
   748   endFile(ol); 
       
   749   ol.popGeneratorState();
       
   750 }
       
   751 
       
   752 //----------------------------------------------------------------------
       
   753 // external functions
       
   754 
       
   755 void buildDirectories()
       
   756 {
       
   757   // for each input file
       
   758   FileNameListIterator fnli(*Doxygen::inputNameList); 
       
   759   FileName *fn;
       
   760   for (fnli.toFirst();(fn=fnli.current());++fnli)
       
   761   {
       
   762     FileNameIterator fni(*fn);
       
   763     FileDef *fd;
       
   764     for (;(fd=fni.current());++fni)
       
   765     {
       
   766       //printf("buildDirectories %s\n",fd->name().data());
       
   767       if (fd->getReference().isEmpty() && !fd->isDocumentationFile())
       
   768       {
       
   769         DirDef *dir;
       
   770         if ((dir=Doxygen::directories->find(fd->getPath()))==0) // new directory
       
   771         {
       
   772           dir = DirDef::mergeDirectoryInTree(fd->getPath());
       
   773         }
       
   774         if (dir) dir->addFile(fd);
       
   775       }
       
   776       else
       
   777       {
       
   778         // do something for file imported via tag files.
       
   779       }
       
   780     }
       
   781   }
       
   782 
       
   783   //DirDef *root = new DirDef("root:");
       
   784   // compute relations between directories => introduce container dirs.
       
   785   DirDef *dir;
       
   786   DirSDict::Iterator sdi(*Doxygen::directories);
       
   787   for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   788   {
       
   789     //printf("New dir %s\n",dir->displayName().data());
       
   790     QCString name = dir->name();
       
   791     int i=name.findRev('/',name.length()-2);
       
   792     if (i>0)
       
   793     {
       
   794       DirDef *parent = Doxygen::directories->find(name.left(i+1));
       
   795       //if (parent==0) parent=root;
       
   796       if (parent) 
       
   797       {
       
   798         parent->addSubDir(dir); 
       
   799         //printf("DirDef::addSubdir(): Adding subdir\n%s to\n%s\n",
       
   800         //  dir->displayName().data(), parent->displayName().data());
       
   801       }
       
   802     }
       
   803   }
       
   804 }
       
   805 
       
   806 void computeDirDependencies()
       
   807 {
       
   808   DirDef *dir;
       
   809   DirSDict::Iterator sdi(*Doxygen::directories);
       
   810   // compute nesting level for each directory
       
   811   for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   812   {
       
   813     dir->setLevel();
       
   814   }
       
   815   // compute uses dependencies between directories
       
   816   for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   817   {
       
   818     //printf("computeDependencies for %s: #dirs=%d\n",dir->name().data(),Doxygen::directories.count());
       
   819     dir->computeDependencies();
       
   820   }
       
   821 
       
   822 #if 0
       
   823   printf("-------------------------------------------------------------\n");
       
   824   // print dependencies (for debugging)
       
   825   for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   826   {
       
   827     if (dir->usedDirs())
       
   828     {
       
   829       QDictIterator<UsedDir> udi(*dir->usedDirs());
       
   830       UsedDir *usedDir;
       
   831       for (udi.toFirst();(usedDir=udi.current());++udi)
       
   832       {
       
   833         printf("%s depends on %s due to ",
       
   834             dir->shortName().data(),usedDir->dir()->shortName().data());
       
   835         QDictIterator<FileDef> fdi(usedDir->files());
       
   836         FileDef *fd;
       
   837         for (fdi.toFirst();(fd=fdi.current());++fdi)
       
   838         {
       
   839           printf("%s ",fd->name().data());
       
   840         }
       
   841         printf("\n");
       
   842       }
       
   843     }
       
   844   }
       
   845   printf("^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^-^\n");
       
   846 #endif
       
   847 }
       
   848 
       
   849 #if 0
       
   850 void writeDirDependencyGraph(const char *dirName)
       
   851 {
       
   852   QString path;
       
   853   DirDef *dir;
       
   854   DirSDict::Iterator sdi(*Doxygen::directories);
       
   855   QFile htmlPage(QCString(dirName)+"/dirdeps.html");
       
   856   if (htmlPage.open(IO_WriteOnly))
       
   857   {
       
   858     QTextStream out(&htmlPage);
       
   859     out << "<html><body>";
       
   860     for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   861     {
       
   862       path=dirName;
       
   863       path+="/";
       
   864       path+=dir->getOutputFileBase();
       
   865       path+="_dep.dot";
       
   866       out << "<h4>" << dir->displayName() << "</h4>" << endl;
       
   867       out << "<img src=\"" << dir->getOutputFileBase() << "_dep.gif\">" << endl;
       
   868       QFile f(path);
       
   869       if (f.open(IO_WriteOnly))
       
   870       {
       
   871         QTextStream t(&f);
       
   872         dir->writeDepGraph(t);
       
   873       }
       
   874       f.close();
       
   875 
       
   876       QCString imgExt = Config_getEnum("DOT_IMAGE_FORMAT");
       
   877       QCString outFile = QCString(dirName)+"/"+
       
   878                          dir->getOutputFileBase()+"_dep."+imgExt; 
       
   879       DotRunner dotRun(path);
       
   880       dotRun.addJob(imgExt,outFile);
       
   881       dotRun.run();
       
   882       
       
   883       //QCString dotArgs(4096);
       
   884       //dotArgs.sprintf("%s -Tgif -o %s",path.data(),outFile.data());
       
   885       //if (portable_system(Config_getString("DOT_PATH")+"dot",dotArgs,FALSE)!=0)
       
   886       //{
       
   887       //  err("Problems running dot. Check your installation!\n");
       
   888       //}
       
   889     }
       
   890     out << "</body></html>";
       
   891   }
       
   892   htmlPage.close();
       
   893 }
       
   894 #endif
       
   895 
       
   896 void generateDirDocs(OutputList &ol)
       
   897 {
       
   898   DirDef *dir;
       
   899   DirSDict::Iterator sdi(*Doxygen::directories);
       
   900   for (sdi.toFirst();(dir=sdi.current());++sdi)
       
   901   {
       
   902     dir->writeDocumentation(ol);
       
   903   }
       
   904   if (Config_getBool("DIRECTORY_GRAPH"))
       
   905   {
       
   906     SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations);
       
   907     DirRelation *dr;
       
   908     for (rdi.toFirst();(dr=rdi.current());++rdi)
       
   909     {
       
   910       dr->writeDocumentation(ol);
       
   911     }
       
   912   }
       
   913 }
       
   914