dirdef.cpp 25.3 KB
Newer Older
Dimitri van Heesch's avatar
Dimitri van Heesch committed
1
#include "md5.h"
2

3 4 5 6
#include "dirdef.h"
#include "filename.h"
#include "doxygen.h"
#include "util.h"
7 8
#include "outputlist.h"
#include "language.h"
9
#include "message.h"
10
#include "dot.h"
11
#include "layout.h"
12
#include "ftextstream.h"
13
#include "config.h"
14
#include "docparser.h"
15 16 17 18

//----------------------------------------------------------------------
// method implementation

19 20
static int g_dirCount=0;

21
DirDef::DirDef(const char *path) : Definition(path,1,1,path)
22
{
23
  bool fullPathNames = Config_getBool("FULL_PATH_NAMES");
24 25 26
  // get display name (stipping the paths mentioned in STRIP_FROM_PATH)
  // get short name (last part of path)
  m_shortName = path;
27
  m_diskName = path;
28 29 30 31 32 33 34 35 36
  if (m_shortName.at(m_shortName.length()-1)=='/')
  { // strip trailing /
    m_shortName = m_shortName.left(m_shortName.length()-1);
  }
  int pi=m_shortName.findRev('/');
  if (pi!=-1) 
  { // remove everything till the last /
    m_shortName = m_shortName.mid(pi+1);
  }
37
  setLocalName(m_shortName);
38
  m_dispName = fullPathNames ? stripFromPath(path) : m_shortName;
39
  if (m_dispName.length()>0 && m_dispName.at(m_dispName.length()-1)=='/')
40 41 42
  { // strip trailing /
    m_dispName = m_dispName.left(m_dispName.length()-1);
  }
43
  
44 45 46 47 48 49
  m_fileList   = new FileList;
  m_usedDirs   = new QDict<UsedDir>(257);
  m_usedDirs->setAutoDelete(TRUE);
  m_dirCount   = g_dirCount++;
  m_level=-1;
  m_parent=0;
50 51 52 53
}

DirDef::~DirDef()
{
54 55
  delete m_fileList;
  delete m_usedDirs;
56 57
}

58 59
bool DirDef::isLinkableInProject() const 
{ 
60
  return !isReference(); 
61 62 63 64 65 66 67
}

bool DirDef::isLinkable() const 
{ 
  return isReference() || isLinkableInProject(); 
}

68 69
void DirDef::addSubDir(DirDef *subdir)
{
70 71
  m_subdirs.inSort(subdir);
  subdir->setOuterScope(this);
72
  subdir->m_parent=this;
73 74 75 76
}

void DirDef::addFile(FileDef *fd)
{
77
  m_fileList->inSort(fd);
78 79 80
  fd->setDirDef(this);
}

81
static QCString encodeDirName(const QCString &anchor)
82 83
{
  QCString result;
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111

  // convert to md5 hash
  uchar md5_sig[16];
  QCString sigStr(33);
  MD5Buffer((const unsigned char *)anchor.data(),anchor.length(),md5_sig);
  MD5SigToString(md5_sig,sigStr.data(),33);
  return sigStr;

  // old algorithm

//  int l = anchor.length(),i;
//  for (i=0;i<l;i++)
//  {
//    char c = anchor.at(i);
//    if ((c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'))
//    {
//      result+=c;
//    }
//    else
//    {
//      static char hexStr[]="0123456789ABCDEF";
//      char escChar[]={ '_', 0, 0, 0 };
//      escChar[1]=hexStr[c>>4];
//      escChar[2]=hexStr[c&0xf];
//      result+=escChar;
//    }
//  }
//  return result;
112 113
}

114 115
QCString DirDef::getOutputFileBase() const
{
116 117 118
  //printf("DirDef::getOutputFileBase() %s->dir_%s\n",
  //    m_diskName.data(),encodeDirName(m_diskName).data());
  return "dir_"+encodeDirName(m_diskName);
119 120
}

121
void DirDef::writeDetailedDescription(OutputList &ol,const QCString &title)
122
{
123 124
  if ((!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF")) || 
      !documentation().isEmpty())
125 126
  {
    ol.pushGeneratorState();
Dimitri van Heesch's avatar
Dimitri van Heesch committed
127 128 129 130 131
      ol.disable(OutputGenerator::Html);
      ol.writeRuler();
    ol.popGeneratorState();
    ol.pushGeneratorState();
      ol.disableAllBut(OutputGenerator::Html);
Dimitri van Heesch's avatar
Dimitri van Heesch committed
132
      ol.writeAnchor(0,"details");
133 134
    ol.popGeneratorState();
    ol.startGroupHeader();
135
    ol.parseText(title);
136 137 138 139 140
    ol.endGroupHeader();

    // repeat brief description
    if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF"))
    {
141
      ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE);
142 143 144 145 146 147 148 149
    }
    // separator between brief and details
    if (!briefDescription().isEmpty() && Config_getBool("REPEAT_BRIEF") && 
        !documentation().isEmpty())
    {
      ol.pushGeneratorState();
        ol.disable(OutputGenerator::Man);
        ol.disable(OutputGenerator::RTF);
150
        // ol.newParagraph();  // FIXME:PARA
151 152 153 154
        ol.enableAll();
        ol.disableAllBut(OutputGenerator::Man);
        ol.writeString("\n\n");
      ol.popGeneratorState();
155 156 157 158 159
    }

    // write documentation
    if (!documentation().isEmpty())
    {
160
      ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE);
161 162 163 164
    }
  }
}

165
void DirDef::writeBriefDescription(OutputList &ol)
166
{
167
  if (!briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
168
  {
169 170 171
    DocRoot *rootNode = validatingParseDoc(
         briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE);
    if (rootNode && !rootNode->isEmpty())
172
    {
173 174 175 176 177 178
      ol.startParagraph();
      ol.writeDoc(rootNode,this,0);
      ol.pushGeneratorState();
      ol.disable(OutputGenerator::RTF);
      ol.writeString(" \n");
      ol.enable(OutputGenerator::RTF);
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193
      if (Config_getBool("REPEAT_BRIEF") ||
          !documentation().isEmpty()
         )
      {
        ol.disableAllBut(OutputGenerator::Html);
        ol.startTextLink(0,"details");
        ol.parseText(theTranslator->trMore());
        ol.endTextLink();
      }
      ol.popGeneratorState();

      ol.endParagraph();
    }
    delete rootNode;
194
  }
195 196
  ol.writeSynopsis();
}
197

198 199
void DirDef::writeDirectoryGraph(OutputList &ol)
{
200
  // write graph dependency graph
Dimitri van Heesch's avatar
Dimitri van Heesch committed
201
  if (Config_getBool("DIRECTORY_GRAPH") && Config_getBool("HAVE_DOT"))
202 203 204 205 206 207
  {
    DotDirDeps dirDep(this);
    if (!dirDep.isTrivial())
    {
      msg("Generating dependency graph for directory %s\n",displayName().data());
      ol.disable(OutputGenerator::Man);
208
      //ol.startParagraph();
209
      ol.startDirDepGraph();
210
      ol.parseText(theTranslator->trDirDepGraph(shortName()));
211
      ol.endDirDepGraph(dirDep);
212
      //ol.endParagraph();
213 214 215
      ol.enableAll();
    }
  }
216
}
217

218 219
void DirDef::writeSubDirList(OutputList &ol)
{
220 221 222
  // write subdir list
  if (m_subdirs.count()>0)
  {
223
    ol.startMemberHeader("subdirs");
224 225 226 227 228 229
    ol.parseText(theTranslator->trDir(TRUE,FALSE));
    ol.endMemberHeader();
    ol.startMemberList();
    DirDef *dd=m_subdirs.first();
    while (dd)
    {
230
      ol.startMemberDeclaration();
231
      ol.startMemberItem(dd->getOutputFileBase(),0);
232
      ol.parseText(theTranslator->trDir(FALSE,TRUE)+" ");
233 234 235
      ol.insertMemberAlign();
      ol.writeObjectLink(dd->getReference(),dd->getOutputFileBase(),0,dd->shortName());
      ol.endMemberItem();
236 237 238 239
      if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
      {
        Doxygen::tagFile << "    <dir>" << convertToXML(dd->displayName()) << "</dir>" << endl;
      }
240 241
      if (!dd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
      {
242
        ol.startMemberDescription(dd->getOutputFileBase());
243
        ol.generateDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),
244 245 246
            FALSE, // indexWords
            FALSE, // isExample
            0,     // exampleName
247
            TRUE,  // single line
248 249
            TRUE   // link from index
           );
250 251
        ol.endMemberDescription();
      }
252
      ol.endMemberDeclaration(0,0);
253 254 255 256 257
      dd=m_subdirs.next();
    }

    ol.endMemberList();
  }
258 259 260 261
}

void DirDef::writeFileList(OutputList &ol)
{
262 263 264
  // write file list
  if (m_fileList->count()>0)
  {
265
    ol.startMemberHeader("files");
266 267 268 269 270 271
    ol.parseText(theTranslator->trFile(TRUE,FALSE));
    ol.endMemberHeader();
    ol.startMemberList();
    FileDef *fd=m_fileList->first();
    while (fd)
    {
272
      ol.startMemberDeclaration();
273
      ol.startMemberItem(fd->getOutputFileBase(),0);
274
      ol.docify(theTranslator->trFile(FALSE,TRUE)+" ");
275
      ol.insertMemberAlign();
276 277 278 279 280 281 282
      if (fd->isLinkable())
      {
        ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
      }
      else
      {
        ol.startBold();
283
        ol.docify(fd->name()); 
284 285
        ol.endBold();
      }
286 287 288 289 290 291 292 293 294 295 296 297
      if (fd->generateSourceFile())
      {
        ol.pushGeneratorState();
        ol.disableAllBut(OutputGenerator::Html);
        ol.docify(" ");
        ol.startTextLink(fd->includeName(),0);
        ol.docify("[");
        ol.parseText(theTranslator->trCode());
        ol.docify("]");
        ol.endTextLink();
        ol.popGeneratorState();
      }
298 299 300 301
      if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
      {
        Doxygen::tagFile << "    <file>" << convertToXML(fd->name()) << "</file>" << endl;
      }
302 303 304
      ol.endMemberItem();
      if (!fd->briefDescription().isEmpty() && Config_getBool("BRIEF_MEMBER_DESC"))
      {
305
        ol.startMemberDescription(fd->getOutputFileBase());
306
        ol.generateDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),
307 308 309
            FALSE, // indexWords
            FALSE, // isExample
            0,     // exampleName
310
            TRUE,  // single line
311 312
            TRUE   // link from index
           );
313 314
        ol.endMemberDescription();
      }
315
      ol.endMemberDeclaration(0,0);
316 317 318 319
      fd=m_fileList->next();
    }
    ol.endMemberList();
  }
320 321 322 323 324 325 326 327 328
}

void DirDef::startMemberDeclarations(OutputList &ol)
{
  ol.startMemberSections();
}

void DirDef::endMemberDeclarations(OutputList &ol)
{
329
  ol.endMemberSections();
330 331 332 333
}

void DirDef::writeDocumentation(OutputList &ol)
{
334
  static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
335 336 337 338
  ol.pushGeneratorState();
  
  QCString shortTitle=theTranslator->trDirReference(m_shortName);
  QCString title=theTranslator->trDirReference(m_dispName);
339
  startFile(ol,getOutputFileBase(),name(),title,HLI_None,!generateTreeView);
340

341 342 343 344 345 346
  if (!generateTreeView)
  {
    // write navigation path
    writeNavigationPath(ol);
    ol.endQuickIndices();
  }
347 348 349 350 351 352 353 354 355 356

  startTitle(ol,getOutputFileBase());
  ol.pushGeneratorState();
    ol.disableAllBut(OutputGenerator::Html);
    ol.parseText(shortTitle);
    ol.enableAll();
    ol.disable(OutputGenerator::Html);
    ol.parseText(title);
  ol.popGeneratorState();
  endTitle(ol,getOutputFileBase(),title);
357
  ol.startContents();
358

359
  if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
360
  {
361 362 363 364 365 366 367 368
    Doxygen::tagFile << "  <compound kind=\"dir\">" << endl;
    Doxygen::tagFile << "    <name>" << convertToXML(displayName()) << "</name>" << endl;
    Doxygen::tagFile << "    <path>" << convertToXML(name()) << "</path>" << endl;
    Doxygen::tagFile << "    <filename>" << convertToXML(getOutputFileBase()) << Doxygen::htmlFileExtension << "</filename>" << endl;
  }
  
  //---------------------------------------- start flexible part -------------------------------

369
  SrcLangExt lang = getLanguage();
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397
  QListIterator<LayoutDocEntry> eli(
      LayoutDocManager::instance().docEntries(LayoutDocManager::Directory));
  LayoutDocEntry *lde;
  for (eli.toFirst();(lde=eli.current());++eli)
  {
    switch (lde->kind())
    {
      case LayoutDocEntry::BriefDesc: 
        writeBriefDescription(ol);
        break; 
      case LayoutDocEntry::DirGraph: 
        writeDirectoryGraph(ol);
        break; 
      case LayoutDocEntry::MemberDeclStart: 
        startMemberDeclarations(ol);
        break; 
      case LayoutDocEntry::DirSubDirs: 
        writeSubDirList(ol);
        break; 
      case LayoutDocEntry::DirFiles: 
        writeFileList(ol);
        break; 
      case LayoutDocEntry::MemberDeclEnd: 
        endMemberDeclarations(ol);
        break;
      case LayoutDocEntry::DetailedDesc: 
        {
          LayoutDocEntrySection *ls = (LayoutDocEntrySection*)lde;
398
          writeDetailedDescription(ol,ls->title(lang));
399 400 401
        }
        break;
      case LayoutDocEntry::ClassIncludes:
402
      case LayoutDocEntry::ClassInlineClasses:
403 404 405 406 407 408
      case LayoutDocEntry::ClassInheritanceGraph:
      case LayoutDocEntry::ClassNestedClasses:
      case LayoutDocEntry::ClassCollaborationGraph:
      case LayoutDocEntry::ClassAllMembersLink:
      case LayoutDocEntry::ClassUsedFiles:
      case LayoutDocEntry::NamespaceNestedNamespaces:
409
      case LayoutDocEntry::NamespaceNestedConstantGroups:
410
      case LayoutDocEntry::NamespaceClasses:
411
      case LayoutDocEntry::NamespaceInlineClasses:
412 413
      case LayoutDocEntry::FileClasses:
      case LayoutDocEntry::FileNamespaces:
414
      case LayoutDocEntry::FileConstantGroups:
415 416 417 418
      case LayoutDocEntry::FileIncludes:
      case LayoutDocEntry::FileIncludeGraph:
      case LayoutDocEntry::FileIncludedByGraph: 
      case LayoutDocEntry::FileSourceLink:
419
      case LayoutDocEntry::FileInlineClasses:
420
      case LayoutDocEntry::GroupClasses: 
Dimitri van Heesch's avatar
Dimitri van Heesch committed
421
      case LayoutDocEntry::GroupInlineClasses: 
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447
      case LayoutDocEntry::GroupNamespaces:
      case LayoutDocEntry::GroupDirs: 
      case LayoutDocEntry::GroupNestedGroups: 
      case LayoutDocEntry::GroupFiles:
      case LayoutDocEntry::GroupGraph: 
      case LayoutDocEntry::GroupPageDocs:
      case LayoutDocEntry::AuthorSection:
      case LayoutDocEntry::MemberGroups:
      case LayoutDocEntry::MemberDecl:
      case LayoutDocEntry::MemberDef:
      case LayoutDocEntry::MemberDefStart:
      case LayoutDocEntry::MemberDefEnd:
        err("Internal inconsistency: member %d should not be part of "
            "LayoutDocManager::Directory entry list\n",lde->kind());
        break;
    }
  }

  //---------------------------------------- end flexible part -------------------------------

  if (!Config_getString("GENERATE_TAGFILE").isEmpty()) 
  {
    writeDocAnchorsToTagFile();
    Doxygen::tagFile << "  </compound>" << endl;
  }

448
  ol.endContents();
449

450
  endFileWithNavPath(this,ol);
451

452
  ol.popGeneratorState();
453 454
}

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
void DirDef::setLevel()
{
  if (m_level==-1) // level not set before
  {
    DirDef *p = parent();
    if (p)
    {
      p->setLevel();
      m_level = p->level()+1;
    }
    else
    {
      m_level = 0;
    }
  }
}

/** Add as "uses" dependency between \a this dir and \a dir,
 *  that was caused by a dependency on file \a fd.
 */ 
475 476
void DirDef::addUsesDependency(DirDef *dir,FileDef *srcFd,
                               FileDef *dstFd,bool inherited)
477 478
{
  if (this==dir) return; // do not add self-dependencies
479 480 481 482 483 484
  //static int count=0;
  //printf("  %d add dependency %s->%s due to %s->%s\n",
  //    count++,shortName().data(),
  //    dir->shortName().data(),
  //    srcFd->name().data(),
  //    dstFd->name().data());
485 486 487 488 489 490

  // levels match => add direct dependency
  bool added=FALSE;
  UsedDir *usedDir = m_usedDirs->find(dir->getOutputFileBase());
  if (usedDir) // dir dependency already present
  {
491 492 493
     FilePair *usedPair = usedDir->findFilePair(
         srcFd->getOutputFileBase()+dstFd->getOutputFileBase());
     if (usedPair==0) // new file dependency
494 495
     {
       //printf("  => new file\n");
496
       usedDir->addFileDep(srcFd,dstFd); 
497 498 499 500 501 502 503 504 505 506 507
       added=TRUE;
     }
     else
     {
       // dir & file dependency already added
     }
  }
  else // new directory dependency
  {
    //printf("  => new file\n");
    usedDir = new UsedDir(dir,inherited);
508
    usedDir->addFileDep(srcFd,dstFd); 
509 510 511
    m_usedDirs->insert(dir->getOutputFileBase(),usedDir);
    added=TRUE;
  }
512
  if (added)
513
  {
514 515 516 517 518 519 520 521 522 523
    if (dir->parent())
    {
      // add relation to parent of used dir
      addUsesDependency(dir->parent(),srcFd,dstFd,inherited);
    }
    if (parent())
    {
      // add relation for the parent of this dir as well
      parent()->addUsesDependency(dir,srcFd,dstFd,TRUE);
    }
524 525 526 527 528 529 530 531 532 533 534 535 536 537
  }
}

/** Computes the dependencies between directories
 */
void DirDef::computeDependencies()
{
  FileList *fl = m_fileList;
  if (fl) 
  {
    QListIterator<FileDef> fli(*fl);
    FileDef *fd;
    for (fli.toFirst();(fd=fli.current());++fli) // foreach file in dir dd
    {
538
      //printf("  File %s\n",fd->name().data());
539 540 541 542 543 544 545 546 547
      //printf("** dir=%s file=%s\n",shortName().data(),fd->name().data());
      QList<IncludeInfo> *ifl = fd->includeFileList();
      if (ifl)
      {
        QListIterator<IncludeInfo> ifli(*ifl); 
        IncludeInfo *ii;
        for (ifli.toFirst();(ii=ifli.current());++ifli) // foreach include file
        {
          //printf("  > %s\n",ii->includeName.data());
548
          //printf("    #include %s\n",ii->includeName.data());
549 550 551 552 553 554
          if (ii->fileDef && ii->fileDef->isLinkable()) // linkable file
          {
            DirDef *usedDir = ii->fileDef->getDirDef();
            if (usedDir)
            {
              // add dependency: thisDir->usedDir
555 556
              //static int count=0;
              //printf("      %d: add dependency %s->%s\n",count++,name().data(),usedDir->name().data());
557
              addUsesDependency(usedDir,fd,ii->fileDef,FALSE);
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
            }
          } 
        }
      }
    }
  }
}

bool DirDef::isParentOf(DirDef *dir) const
{
  if (dir->parent()==this) // this is a parent of dir 
    return TRUE;
  else if (dir->parent()) // repeat for the parent of dir
    return isParentOf(dir->parent()); 
  else
    return FALSE;
}

576 577 578 579 580 581 582
bool DirDef::depGraphIsTrivial() const
{
  return FALSE;
}

//----------------------------------------------------------------------

583
int FilePairDict::compareItems(QCollection::Item item1,QCollection::Item item2)
584 585 586
{
  FilePair *left  = (FilePair*)item1;
  FilePair *right = (FilePair*)item2;
Dimitri van Heesch's avatar
Dimitri van Heesch committed
587 588
  int orderHi = qstricmp(left->source()->name(),right->source()->name());
  int orderLo = qstricmp(left->destination()->name(),right->destination()->name());
589 590 591
  return orderHi==0 ? orderLo : orderHi;
}

592 593 594
//----------------------------------------------------------------------

UsedDir::UsedDir(DirDef *dir,bool inherited) :
595
   m_dir(dir), m_filePairs(7), m_inherited(inherited)
596
{
597
  m_filePairs.setAutoDelete(TRUE);
598 599 600 601 602 603
}

UsedDir::~UsedDir()
{
}

604

605
void UsedDir::addFileDep(FileDef *srcFd,FileDef *dstFd)
606
{
607 608
  m_filePairs.inSort(srcFd->getOutputFileBase()+dstFd->getOutputFileBase(),
                     new FilePair(srcFd,dstFd));
609 610
}

611
FilePair *UsedDir::findFilePair(const char *name)
612 613
{
  QCString n=name;
614
  return n.isEmpty() ? 0 : m_filePairs.find(n);
615 616
}

617 618 619
DirDef *DirDef::createNewDir(const char *path)
{
  ASSERT(path!=0);
620
  DirDef *dir = Doxygen::directories->find(path);
621 622 623 624
  if (dir==0) // new dir
  {
    //printf("Adding new dir %s\n",path);
    dir = new DirDef(path);
625
    //printf("createNewDir %s short=%s\n",path,dir->shortName().data());
626
    Doxygen::directories->inSort(path,dir);
627 628 629 630 631 632 633 634 635 636
  }
  return dir;
}

bool DirDef::matchPath(const QCString &path,QStrList &l)
{
  const char *s=l.first();
  while (s)
  {
    QCString prefix = s;
Dimitri van Heesch's avatar
Dimitri van Heesch committed
637
    if (qstricmp(prefix.left(path.length()),path)==0) // case insensitive compare
638 639 640 641 642 643 644 645 646 647 648 649 650
    {
      return TRUE;
    }
    s = l.next();
  }
  return FALSE;
}

/*! strip part of \a path if it matches
 *  one of the paths in the Config_getList("STRIP_FROM_PATH") list
 */
DirDef *DirDef::mergeDirectoryInTree(const QCString &path)
{
651
  //printf("DirDef::mergeDirectoryInTree(%s)\n",path.data());
652 653 654 655 656
  int p=0,i=0;
  DirDef *dir=0;
  while ((i=path.find('/',p))!=-1)
  {
    QCString part=path.left(i+1);
657
    if (!matchPath(part,Config_getList("STRIP_FROM_PATH")) && (part!="/" && part!="//"))
658 659 660 661 662 663 664 665
    {
      dir=createNewDir(part); 
    }
    p=i+1;
  }
  return dir;
}

666
void DirDef::writeDepGraph(FTextStream &t)
667
{
Dimitri van Heesch's avatar
Dimitri van Heesch committed
668
    writeDotDirDepGraph(t,this);
669 670
}

671 672 673 674 675 676 677
//----------------------------------------------------------------------

static void writePartialDirPath(OutputList &ol,const DirDef *root,const DirDef *target)
{
  if (target->parent()!=root) 
  {
    writePartialDirPath(ol,root,target->parent());
678
    ol.writeString("&#160;/&#160;");
679 680 681 682 683 684 685 686 687
  }
  ol.writeObjectLink(target->getReference(),target->getOutputFileBase(),0,target->shortName());
}

static void writePartialFilePath(OutputList &ol,const DirDef *root,const FileDef *fd)
{
  if (fd->getDirDef() && fd->getDirDef()!=root)
  {
    writePartialDirPath(ol,root,fd->getDirDef());
688
    ol.writeString("&#160;/&#160;");
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
  }
  if (fd->isLinkable())
  {
    ol.writeObjectLink(fd->getReference(),fd->getOutputFileBase(),0,fd->name());
  }
  else
  {
    ol.startBold();
    ol.docify(fd->name());
    ol.endBold();
  }
}

void DirRelation::writeDocumentation(OutputList &ol)
{
704
  static bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
705 706 707
  ol.pushGeneratorState();
  ol.disableAllBut(OutputGenerator::Html);

Dimitri van Heesch's avatar
Dimitri van Heesch committed
708 709 710 711 712 713
  QCString shortTitle=theTranslator->trDirRelation(
                      m_src->shortName()+" &rarr; "+
                      m_dst->dir()->shortName());
  QCString title=theTranslator->trDirRelation(
                 m_src->displayName()+" -> "+
                 m_dst->dir()->shortName());
714 715
  startFile(ol,getOutputFileBase(),getOutputFileBase(),
            title,HLI_None,!generateTreeView,m_src->getOutputFileBase());
716

717 718 719 720 721 722
  if (!generateTreeView)
  {
    // write navigation path
    m_src->writeNavigationPath(ol);
    ol.endQuickIndices();
  }
723
  ol.startContents();
724 725 726 727

  ol.writeString("<h3>"+shortTitle+"</h3>");
  ol.writeString("<table class=\"dirtab\">");
  ol.writeString("<tr class=\"dirtab\">");
728 729
  ol.writeString("<th class=\"dirtab\">");
  ol.parseText(theTranslator->trFileIn(m_src->pathFragment()));
730
  ol.writeString("</th>");
731 732
  ol.writeString("<th class=\"dirtab\">");
  ol.parseText(theTranslator->trIncludesFileIn(m_dst->dir()->pathFragment()));
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
  ol.writeString("</th>");
  ol.writeString("</tr>");

  SDict<FilePair>::Iterator fpi(m_dst->filePairs());
  FilePair *fp;
  for (fpi.toFirst();(fp=fpi.current());++fpi)
  {
    ol.writeString("<tr class=\"dirtab\">");
    ol.writeString("<td class=\"dirtab\">");
    writePartialFilePath(ol,m_src,fp->source());
    ol.writeString("</td>");
    ol.writeString("<td class=\"dirtab\">");
    writePartialFilePath(ol,m_dst->dir(),fp->destination());
    ol.writeString("</td>");
    ol.writeString("</tr>");
  }
  ol.writeString("</table>");
750 751

  ol.endContents();
752
  
753
  endFileWithNavPath(m_src,ol);
754

755 756 757
  ol.popGeneratorState();
}

758 759 760
//----------------------------------------------------------------------
// external functions

761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
/** In order to create stable, but unique directory names,
 *  we compute the common part of the path shared by all directories.
 */
static void computeCommonDirPrefix()
{
  QCString path;
  DirDef *dir;
  DirSDict::Iterator sdi(*Doxygen::directories);
  if (Doxygen::directories->count()>0) // we have at least one dir
  {
    // start will full path of first dir
    sdi.toFirst();
    dir=sdi.current();
    path=dir->name();
    int i=path.findRev('/',path.length()-2);
    path=path.left(i+1);
    bool done=FALSE;
    if (i==-1) 
    {
      path="";
    }
    else
    {
      while (!done)
      {
        int l = path.length();
        int count=0;
        for (sdi.toFirst();(dir=sdi.current());++sdi)
        {
          QCString dirName = dir->name();
          if (dirName.length()>path.length())
          {
Dimitri van Heesch's avatar
Dimitri van Heesch committed
793
            if (qstrncmp(dirName,path,l)!=0) // dirName does not start with path
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
            {
              int i=path.findRev('/',l-2);
              if (i==-1) // no unique prefix -> stop
              {
                path="";
                done=TRUE;
              }
              else // restart with shorter path
              {
                path=path.left(i+1);
                break;
              }
            }
          }
          else // dir is shorter than path -> take path of dir as new start
          {
            path=dir->name();
            int i=path.findRev('/',l-2);
            if (i==-1) // no unique prefix -> stop
            {
              path="";
              done=TRUE;
            }
            else // restart with shorter path
            {
              path=path.left(i+1);
            }
            break;
          }
          count++;
        }
        if (count==Doxygen::directories->count())
          // path matches for all directories -> found the common prefix
        {
          done=TRUE;
        }
      }
    }
  }
  for (sdi.toFirst();(dir=sdi.current());++sdi)
  {
    QCString diskName = dir->name().right(dir->name().length()-path.length());
    dir->setDiskName(diskName);
    //printf("set disk name: %s -> %s\n",dir->name().data(),diskName.data());
  }
}

841 842 843
void buildDirectories()
{
  // for each input file
844
  FileNameListIterator fnli(*Doxygen::inputNameList); 
845 846 847 848 849 850 851
  FileName *fn;
  for (fnli.toFirst();(fn=fnli.current());++fnli)
  {
    FileNameIterator fni(*fn);
    FileDef *fd;
    for (;(fd=fni.current());++fni)
    {
852
      //printf("buildDirectories %s\n",fd->name().data());
853
      if (fd->getReference().isEmpty() && !fd->isDocumentationFile())
854 855
      {
        DirDef *dir;
856
        if ((dir=Doxygen::directories->find(fd->getPath()))==0) // new directory
857 858 859 860 861 862 863 864 865 866 867 868
        {
          dir = DirDef::mergeDirectoryInTree(fd->getPath());
        }
        if (dir) dir->addFile(fd);
      }
      else
      {
        // do something for file imported via tag files.
      }
    }
  }

869
  //DirDef *root = new DirDef("root:");
870 871
  // compute relations between directories => introduce container dirs.
  DirDef *dir;
872
  DirSDict::Iterator sdi(*Doxygen::directories);
873 874
  for (sdi.toFirst();(dir=sdi.current());++sdi)
  {
875
    //printf("New dir %s\n",dir->displayName().data());
876 877
    QCString name = dir->name();
    int i=name.findRev('/',name.length()-2);
878
    if (i>0)
879
    {
880
      DirDef *parent = Doxygen::directories->find(name.left(i+1));
881
      //if (parent==0) parent=root;
882 883 884 885 886 887
      if (parent) 
      {
        parent->addSubDir(dir); 
        //printf("DirDef::addSubdir(): Adding subdir\n%s to\n%s\n",
        //  dir->displayName().data(), parent->displayName().data());
      }
888 889
    }
  }
890
  computeCommonDirPrefix();
891 892
}

893 894 895
void computeDirDependencies()
{
  DirDef *dir;
896
  DirSDict::Iterator sdi(*Doxygen::directories);
897 898 899 900 901 902 903 904
  // compute nesting level for each directory
  for (sdi.toFirst();(dir=sdi.current());++sdi)
  {
    dir->setLevel();
  }
  // compute uses dependencies between directories
  for (sdi.toFirst();(dir=sdi.current());++sdi)
  {
905
    //printf("computeDependencies for %s: #dirs=%d\n",dir->name().data(),Doxygen::directories.count());
906 907 908 909 910
    dir->computeDependencies();
  }

}

911 912 913
void generateDirDocs(OutputList &ol)
{
  DirDef *dir;
914
  DirSDict::Iterator sdi(*Doxygen::directories);
915 916 917 918
  for (sdi.toFirst();(dir=sdi.current());++sdi)
  {
    dir->writeDocumentation(ol);
  }
919 920 921 922 923 924 925 926 927
  if (Config_getBool("DIRECTORY_GRAPH"))
  {
    SDict<DirRelation>::Iterator rdi(Doxygen::dirRelations);
    DirRelation *dr;
    for (rdi.toFirst();(dr=rdi.current());++rdi)
    {
      dr->writeDocumentation(ol);
    }
  }
928 929
}