Orb/Doxygen/src/diagram.cpp
changeset 0 42188c7ea2d9
child 4 468f4c8d3d5b
equal deleted inserted replaced
-1:000000000000 0:42188c7ea2d9
       
     1 /******************************************************************************
       
     2  *
       
     3  * 
       
     4  *
       
     5  *
       
     6  * Copyright (C) 1997-2008 by Dimitri van Heesch.
       
     7  *
       
     8  * Permission to use, copy, modify, and distribute this software and its
       
     9  * documentation under the terms of the GNU General Public License is hereby 
       
    10  * granted. No representations are made about the suitability of this software 
       
    11  * for any purpose. It is provided "as is" without express or implied warranty.
       
    12  * See the GNU General Public License for more details.
       
    13  *
       
    14  * Documents produced by Doxygen are derivative works derived from the
       
    15  * input used in their production; they are not affected by this license.
       
    16  *
       
    17  */
       
    18 
       
    19 #include "qtbc.h"
       
    20 #include <stdio.h>
       
    21 #include <stdlib.h>
       
    22 #include <qlist.h>
       
    23 #include <qarray.h>
       
    24 #include <qtextstream.h>
       
    25 #include <qfile.h>
       
    26 
       
    27 #include "diagram.h"
       
    28 #include "image.h"
       
    29 #include "classdef.h"
       
    30 #include "config.h"
       
    31 #include "message.h"
       
    32 #include "util.h"
       
    33 #include "doxygen.h"
       
    34 #include "portable.h"
       
    35 #include "index.h"
       
    36 
       
    37 //-----------------------------------------------------------------------------
       
    38 
       
    39 const uint maxTreeWidth = 8;
       
    40 const int gridWidth  = 100;
       
    41 const int gridHeight = 100;
       
    42 
       
    43 const uint labelHorSpacing  = 10;  // horizontal distance between labels
       
    44 const uint labelVertSpacing = 32;  // vertical distance between labels
       
    45 const uint labelHorMargin   = 6;   // horiz. spacing between label and box
       
    46 const uint fontHeight       = 12;  // height of a character
       
    47 
       
    48 //static QCString escapeLatex(const char *s)
       
    49 //{
       
    50 //  QCString result;
       
    51 //  char c;
       
    52 //  while ((c=*s++))
       
    53 //  {
       
    54 //    if (c=='_') result+="\\_";
       
    55 //           else result+=c;
       
    56 //  }
       
    57 //  return result;
       
    58 //}
       
    59 
       
    60 static uint protToMask(Protection p)
       
    61 {
       
    62   switch(p)
       
    63   {
       
    64     case Public:    return 0xffffffff;
       
    65     case Package: // package is not possible!
       
    66     case Protected: return 0xcccccccc;
       
    67     case Private:   return 0xaaaaaaaa;
       
    68   }
       
    69   return 0;
       
    70 }
       
    71 
       
    72 static uint protToColor(Protection p)
       
    73 {
       
    74   switch(p)
       
    75   {
       
    76     case Public:    return 6;
       
    77     case Package: // package is not possible!
       
    78     case Protected: return 5;
       
    79     case Private:   return 4;
       
    80   }
       
    81   return 0;
       
    82 }
       
    83 
       
    84 static QCString protToString(Protection p)
       
    85 {
       
    86   switch(p)
       
    87   {
       
    88     case Public:    return "solid";
       
    89     case Package: // package is not possible!
       
    90     case Protected: return "dashed";
       
    91     case Private:   return "dotted";
       
    92   }
       
    93   return 0;
       
    94 }
       
    95 
       
    96 static uint virtToMask(Specifier p)
       
    97 {
       
    98   switch(p)
       
    99   {
       
   100     case Normal:    return 0xffffffff;
       
   101     case Virtual:   return 0xf0f0f0f0;
       
   102     default:        return 0;
       
   103   }
       
   104   return 0;
       
   105 }
       
   106 
       
   107 // pre: dil is not empty
       
   108 static Protection getMinProtectionLevel(DiagramItemList *dil)
       
   109 {
       
   110   DiagramItem *di=dil->first();
       
   111   Protection result=di->protection();
       
   112   di=dil->next();
       
   113   while (di)
       
   114   {
       
   115     Protection p=di->protection();
       
   116     if (p!=result) 
       
   117     {
       
   118       if (result==Protected && p==Public) result=p;
       
   119       else if (result==Private) result=p;
       
   120     } 
       
   121     di=dil->next();
       
   122   }
       
   123   return result;
       
   124 }
       
   125 
       
   126 static void writeBitmapBox(DiagramItem *di,Image *image,
       
   127                            int x,int y,int w,int h,bool firstRow,
       
   128                            bool hasDocs,bool children=FALSE)
       
   129 {
       
   130   int colFill = hasDocs ? (firstRow ? 0 : 2) : 7;
       
   131   int colBorder = (firstRow || !hasDocs) ? 1 : 3;
       
   132   int l = Image::stringLength(di->label());
       
   133   uint mask=virtToMask(di->virtualness());
       
   134   image->fillRect(x+1,y+1,w-2,h-2,colFill,mask);
       
   135   image->drawRect(x,y,w,h,colBorder,mask);
       
   136   image->writeString(x+(w-l)/2, y+(h-fontHeight)/2, di->label(),1);
       
   137   if (children)
       
   138   {
       
   139     int i;
       
   140     for (i=0;i<5;i++)
       
   141       image->drawHorzLine(y+h+i-6,x+w-2-i,x+w-2,firstRow?1:3,0xffffffff);
       
   142   }
       
   143 }
       
   144 
       
   145 static void writeVectorBox(QTextStream &t,DiagramItem *di,
       
   146                            float x,float y,bool children=FALSE)
       
   147 {
       
   148   if (di->virtualness()==Virtual) t << "dashed\n";
       
   149   t << " (" << di->label() << ") " << x << " " << y << " box\n";
       
   150   if (children) t << x << " " << y << " mark\n";
       
   151   if (di->virtualness()==Virtual) t << "solid\n";
       
   152 }
       
   153 
       
   154 static void writeMapArea(QTextStream &t,ClassDef *cd,QCString relPath,
       
   155                          int x,int y,int w,int h)
       
   156 {
       
   157   if (cd->isLinkable())
       
   158   {
       
   159     QCString *dest;
       
   160     QCString ref=cd->getReference();
       
   161     t << "<area ";
       
   162     if (!ref.isEmpty()) 
       
   163     {
       
   164       t << "doxygen=\"" << ref << ":";
       
   165       if ((dest=Doxygen::tagDestinationDict[ref])) t << *dest << "/";
       
   166       t << "\" ";
       
   167     }
       
   168     t << "href=\"";
       
   169     if (!ref.isEmpty())
       
   170     {
       
   171       if ((dest=Doxygen::tagDestinationDict[ref])) t << *dest << "/";
       
   172     }
       
   173     else
       
   174     {
       
   175       t << relPath;
       
   176     }
       
   177     t << cd->getOutputFileBase() << Doxygen::htmlFileExtension << "\" ";
       
   178     t << "alt=\"" << convertToXML(cd->displayName()); 
       
   179     t << "\" shape=\"rect\" coords=\"" << x << "," << y << ",";
       
   180     t << (x+w) << "," << (y+h) << "\"/>" << endl;
       
   181   }
       
   182 }
       
   183 //-----------------------------------------------------------------------------
       
   184 
       
   185 DiagramItem::DiagramItem(DiagramItem *p,int number,ClassDef *cd,
       
   186                          Protection pr,Specifier vi,const char *ts) 
       
   187 { 
       
   188   parent=p; 
       
   189   x=y=0; 
       
   190   //name=n;
       
   191   num=number;
       
   192   children = new DiagramItemList;
       
   193   prot=pr;
       
   194   virt=vi;
       
   195   inList=FALSE;
       
   196   classDef=cd;
       
   197   templSpec=ts;
       
   198 }
       
   199  
       
   200 DiagramItem::~DiagramItem() 
       
   201 { 
       
   202   delete children;
       
   203 }
       
   204 
       
   205 QCString DiagramItem::label() const
       
   206 {
       
   207   QCString result;
       
   208   if (!templSpec.isEmpty())
       
   209   {
       
   210     // we use classDef->name() here and not diplayName() in order
       
   211     // to get the name used in the inheritance relation.
       
   212     result=insertTemplateSpecifierInScope(classDef->name(),templSpec);
       
   213   }
       
   214   else
       
   215   {
       
   216     result=classDef->displayName();
       
   217   }
       
   218   if (Config_getBool("HIDE_SCOPE_NAMES")) result=stripScope(result);
       
   219   return result;
       
   220 }
       
   221 
       
   222 QCString DiagramItem::fileName() const
       
   223 {
       
   224   return classDef->getOutputFileBase();
       
   225 }
       
   226 
       
   227 int DiagramItem::avgChildPos() const
       
   228 {
       
   229   DiagramItem *di;
       
   230   int c=children->count();
       
   231   if (c==0) // no children -> don't move
       
   232     return xPos();
       
   233   if ((di=children->getFirst())->isInList()) // children should be in a list
       
   234     return di->xPos();
       
   235   if (c&1) // odd number of children -> get pos of middle child
       
   236     return children->at(c/2)->xPos();
       
   237   else // even number of children -> get middle of most middle children
       
   238     return (children->at(c/2-1)->xPos()+children->at(c/2)->xPos())/2;
       
   239 }
       
   240 
       
   241 int DiagramItem::numChildren() const
       
   242 {
       
   243   return children->count();
       
   244 }
       
   245 
       
   246 void DiagramItem::addChild(DiagramItem *di)
       
   247 {
       
   248   children->append(di);
       
   249 }
       
   250 
       
   251 void DiagramRow::insertClass(DiagramItem *parent,ClassDef *cd,bool doBases,
       
   252                              Protection prot,Specifier virt,const char *ts)
       
   253 {
       
   254   //if (cd->visited) return; // the visit check does not work in case of
       
   255                              // multiple inheritance of the same class!
       
   256   DiagramItem *di=new DiagramItem(parent, diagram->at(level)->count(), 
       
   257                                   cd,prot,virt,ts);
       
   258   //cd->visited=TRUE;
       
   259   if (parent) parent->addChild(di);
       
   260   di->move(count()*gridWidth,level*gridHeight);
       
   261   append(di);
       
   262   BaseClassList *bcl=doBases ? cd->baseClasses() : cd->subClasses();
       
   263   int count=0;
       
   264   if (bcl)
       
   265   {
       
   266     /* there are base/sub classes */
       
   267     BaseClassDef *bcd=bcl->first();
       
   268     while (bcd)
       
   269     {
       
   270       ClassDef *ccd=bcd->classDef;
       
   271       if (ccd && ccd->isVisibleInHierarchy() /*&& !ccd->visited*/) count++;
       
   272       bcd=bcl->next();
       
   273     }
       
   274   }
       
   275   if (count>0 && (prot!=Private || !doBases))
       
   276   {
       
   277     DiagramRow *row=0;
       
   278     if (diagram->count()<=level+1) /* add new row */
       
   279     {
       
   280       row = new DiagramRow(diagram,level+1);
       
   281       diagram->append(row);
       
   282     }
       
   283     else /* get next row */
       
   284     {
       
   285       row=diagram->at(level+1);
       
   286     }
       
   287     /* insert base classes in the next row */
       
   288     BaseClassDef *bcd=bcl->first();
       
   289     while (bcd)
       
   290     {
       
   291       ClassDef *ccd=bcd->classDef;
       
   292       if (ccd && ccd->isVisibleInHierarchy() /*&& !ccd->visited*/)
       
   293       {
       
   294         row->insertClass(di,ccd,doBases,bcd->prot,
       
   295             doBases?bcd->virt:Normal,
       
   296             doBases?bcd->templSpecifiers.data():"");
       
   297       }
       
   298       bcd=bcl->next();
       
   299     }
       
   300   }
       
   301 }
       
   302 
       
   303 TreeDiagram::TreeDiagram(ClassDef *root,bool doBases)
       
   304 {
       
   305   setAutoDelete(TRUE); 
       
   306   DiagramRow *row=new DiagramRow(this,0);
       
   307   append(row);
       
   308   row->insertClass(0,root,doBases,Public,Normal,0);
       
   309 }
       
   310 
       
   311 TreeDiagram::~TreeDiagram()
       
   312 {
       
   313 }
       
   314 
       
   315 
       
   316 void TreeDiagram::moveChildren(DiagramItem *root,int dx)
       
   317 {
       
   318   DiagramItemList *dil=root->getChildren();
       
   319   DiagramItem *di=dil->first();
       
   320   while (di)
       
   321   {
       
   322     di->move(dx,0);
       
   323     moveChildren(di,dx);
       
   324     di=dil->next();
       
   325   }
       
   326 }
       
   327 
       
   328 bool TreeDiagram::layoutTree(DiagramItem *root,int r)
       
   329 {
       
   330   bool moved=FALSE;
       
   331   //printf("layoutTree(%s,%d)\n",root->label().data(),r);
       
   332 
       
   333   DiagramItemList *dil=root->getChildren(); 
       
   334   if (dil->count()>0)
       
   335   {
       
   336     uint k;
       
   337     int pPos=root->xPos();
       
   338     int cPos=root->avgChildPos();
       
   339     if (pPos>cPos) // move children
       
   340     {
       
   341       DiagramRow *row=at(r+1);
       
   342       //printf("Moving children %d-%d in row %d\n",
       
   343       //    dil->getFirst()->number(),row->count()-1,r+1);
       
   344       for (k=dil->getFirst()->number();k<row->count();k++)
       
   345         row->at(k)->move(pPos-cPos,0);
       
   346       moved=TRUE;
       
   347     }
       
   348     else if (pPos<cPos) // move parent
       
   349     {
       
   350       DiagramRow *row=at(r);
       
   351       //printf("Moving parents %d-%d in row %d\n",
       
   352       //    root->number(),row->count()-1,r);
       
   353       for (k=root->number();k<row->count();k++)
       
   354         row->at(k)->move(cPos-pPos,0);
       
   355       moved=TRUE;
       
   356     }
       
   357 
       
   358     // recurse to children
       
   359     DiagramItem *di=dil->first();
       
   360     while (di && !moved && !di->isInList())
       
   361     {
       
   362       moved = moved || layoutTree(di,r+1);
       
   363       di=dil->next();
       
   364     }
       
   365   }
       
   366   return moved;
       
   367 }
       
   368 
       
   369 void TreeDiagram::computeLayout()
       
   370 {
       
   371   DiagramRow *row=first();
       
   372   while (row && row->count()<maxTreeWidth) row=next();
       
   373   if (row)
       
   374   {
       
   375     //printf("computeLayout() list row at %d\n",row->number());
       
   376     DiagramItem *di=row->first();
       
   377     DiagramItem *opi=0;
       
   378     int delta=0;
       
   379     bool first=TRUE;
       
   380     while (di)
       
   381     {
       
   382       DiagramItem *pi=di->parentItem();
       
   383       if (pi==opi && !first) { delta-=gridWidth; }
       
   384       first = pi!=opi;
       
   385       opi=pi;
       
   386       di->move(delta,0); // collapse all items in the same 
       
   387                          // list (except the first)
       
   388       di->putInList();
       
   389       di=row->next();
       
   390     }
       
   391   }
       
   392 
       
   393   // re-organize the diagram items
       
   394   DiagramItem *root=getFirst()->getFirst();
       
   395   while (layoutTree(root,0)) { }
       
   396   
       
   397   // move first items of the lists
       
   398   if (row)
       
   399   {
       
   400     DiagramItem *di=row->first();
       
   401     while (di)
       
   402     {
       
   403       DiagramItem *pi=di->parentItem();
       
   404       if (pi->getChildren()->count()>1)
       
   405       {
       
   406         di->move(gridWidth,0);
       
   407         while (di && di->parentItem()==pi) di=row->next();
       
   408       }
       
   409       else
       
   410       {
       
   411         di=row->next();
       
   412       }
       
   413     }
       
   414   }
       
   415 }
       
   416 
       
   417 uint TreeDiagram::computeRows()
       
   418 {
       
   419   //printf("TreeDiagram::computeRows()=%d\n",count());
       
   420   int count=0;
       
   421   DiagramRow *row=first();
       
   422   while (row && !row->getFirst()->isInList())
       
   423   {
       
   424     count++;
       
   425     row=next();
       
   426   }
       
   427   //printf("count=%d row=%p\n",count,row);
       
   428   if (row)
       
   429   {
       
   430     int maxListLen=0;
       
   431     int curListLen=0;
       
   432     DiagramItem *di=row->first(),*opi=0;
       
   433     while (di)
       
   434     {
       
   435       if (di->parentItem()!=opi) curListLen=1; else curListLen++; 
       
   436       if (curListLen>maxListLen) maxListLen=curListLen;
       
   437       opi=di->parentItem();
       
   438       di=row->next();
       
   439     }
       
   440     //printf("maxListLen=%d\n",maxListLen);
       
   441     count+=maxListLen;
       
   442   }
       
   443   return count;
       
   444 }
       
   445 
       
   446 #if 0
       
   447 uint TreeDiagram::computeCols()
       
   448 {
       
   449   uint count=0;
       
   450   DiagramRow *row=first();
       
   451   while (row && !row->getFirst()->isInList())
       
   452   {
       
   453     if (row->count()>count) count=row->count();
       
   454     row=next();
       
   455   }
       
   456   if (row)
       
   457   {
       
   458     row=prev();
       
   459     uint cols=row->count();
       
   460     if (row->getLast()->getChildren()->count()>1) cols++;
       
   461     if (cols>count) count=cols;
       
   462   }
       
   463   return count;
       
   464 };
       
   465 #endif
       
   466 
       
   467 void TreeDiagram::computeExtremes(uint *maxLabelLen,uint *maxXPos)
       
   468 {
       
   469   uint ml=0,mx=0;
       
   470   DiagramRow *dr=first();
       
   471   bool done=FALSE;
       
   472   while (dr && !done)
       
   473   {
       
   474     DiagramItem *di=dr->first();
       
   475     while (di)
       
   476     {
       
   477       if (di->isInList()) done=TRUE;
       
   478       if (maxXPos) mx=QMAX(mx,(uint)di->xPos());
       
   479       if (maxLabelLen) ml=QMAX(ml,Image::stringLength(di->label()));
       
   480       di=dr->next();
       
   481     }
       
   482     dr=next();
       
   483   }
       
   484   if (maxLabelLen) *maxLabelLen=ml;
       
   485   if (maxXPos)     *maxXPos=mx;
       
   486 }
       
   487 
       
   488 void TreeDiagram::drawBoxes(QTextStream &t,Image *image, 
       
   489                             bool doBase,bool bitmap,
       
   490                             uint baseRows,uint superRows,
       
   491                             uint cellWidth,uint cellHeight,
       
   492                             QCString relPath,
       
   493                             bool generateMap)
       
   494 {
       
   495   DiagramRow *dr=first();
       
   496   if (!doBase) dr=next();
       
   497   bool done=FALSE;
       
   498   bool firstRow = doBase;
       
   499   while (dr && !done)
       
   500   {
       
   501     int x=0,y=0;
       
   502     float xf=0.0,yf=0.0;
       
   503     DiagramItem *di=dr->first();
       
   504     if (di->isInList()) // put boxes in a list
       
   505     {
       
   506       DiagramItem *opi=0;
       
   507       if (doBase) di=dr->last();
       
   508       while (di) 
       
   509       {
       
   510         if (di->parentItem()==opi)
       
   511         {
       
   512           if (bitmap)
       
   513           {
       
   514             if (doBase) y -= cellHeight+labelVertSpacing;
       
   515             else        y += cellHeight+labelVertSpacing;
       
   516           }
       
   517           else
       
   518           {
       
   519             if (doBase) yf += 1.0;
       
   520             else        yf -= 1.0;
       
   521           }
       
   522         }
       
   523         else
       
   524         {
       
   525           if (bitmap)
       
   526           {
       
   527             x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth;
       
   528             if (doBase)
       
   529             {
       
   530               y = image->getHeight()-
       
   531                 superRows*cellHeight-
       
   532                 (superRows-1)*labelVertSpacing-
       
   533                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   534             }
       
   535             else
       
   536             {
       
   537               y = (baseRows-1)*(cellHeight+labelVertSpacing)+
       
   538                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   539             }
       
   540           }
       
   541           else
       
   542           {
       
   543             xf = di->xPos()/(float)gridWidth;
       
   544             if (doBase)
       
   545             {
       
   546               yf = di->yPos()/(float)gridHeight+superRows-1;
       
   547             }
       
   548             else
       
   549             {
       
   550               yf = superRows-1-di->yPos()/(float)gridHeight;
       
   551             }
       
   552           }
       
   553         }
       
   554         opi=di->parentItem();
       
   555         
       
   556         if (bitmap)
       
   557         {
       
   558           bool hasDocs=di->getClassDef()->isLinkable();
       
   559           writeBitmapBox(di,image,x,y,cellWidth,cellHeight,firstRow,
       
   560               hasDocs,di->getChildren()->count()>0); 
       
   561           if (!firstRow && generateMap) 
       
   562             writeMapArea(t,di->getClassDef(),relPath,x,y,cellWidth,cellHeight);
       
   563         }
       
   564         else
       
   565         {
       
   566           writeVectorBox(t,di,xf,yf,di->getChildren()->count()>0);
       
   567         }
       
   568         
       
   569         if (doBase) di=dr->prev(); else di=dr->next();
       
   570       }
       
   571       done=TRUE;
       
   572     }
       
   573     else // draw a tree of boxes
       
   574     {
       
   575       while (di)
       
   576       {
       
   577         if (bitmap)
       
   578         {
       
   579           x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth;
       
   580           if (doBase)
       
   581           {
       
   582             y = image->getHeight()-
       
   583               superRows*cellHeight-
       
   584               (superRows-1)*labelVertSpacing-
       
   585               di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   586           }
       
   587           else
       
   588           {
       
   589             y = (baseRows-1)*(cellHeight+labelVertSpacing)+
       
   590               di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   591           }
       
   592           bool hasDocs=di->getClassDef()->isLinkable();
       
   593           writeBitmapBox(di,image,x,y,cellWidth,cellHeight,firstRow,hasDocs); 
       
   594           if (!firstRow && generateMap) 
       
   595             writeMapArea(t,di->getClassDef(),relPath,x,y,cellWidth,cellHeight);
       
   596         }
       
   597         else
       
   598         {
       
   599           xf=di->xPos()/(float)gridWidth;
       
   600           if (doBase)
       
   601           {
       
   602             yf = di->yPos()/(float)gridHeight+superRows-1;
       
   603           }
       
   604           else
       
   605           {
       
   606             yf = superRows-1-di->yPos()/(float)gridHeight;
       
   607           }
       
   608           writeVectorBox(t,di,xf,yf);
       
   609         }
       
   610 
       
   611         di=dr->next();
       
   612       }
       
   613     }
       
   614     dr=next();
       
   615     firstRow=FALSE;
       
   616   }
       
   617 }
       
   618 
       
   619 void TreeDiagram::drawConnectors(QTextStream &t,Image *image,
       
   620                                  bool doBase,bool bitmap,
       
   621                                  uint baseRows,uint superRows,
       
   622                                  uint cellWidth,uint cellHeight)
       
   623 {
       
   624   DiagramRow *dr=first();
       
   625   bool done=FALSE;
       
   626   while (dr && !done) // for each row
       
   627   {
       
   628     DiagramItem *di=dr->first();
       
   629     if (di->isInList()) // row consists of list connectors
       
   630     {
       
   631       int x=0,y=0,ys=0;
       
   632       float xf=0.0,yf=0.0,ysf=0.0;
       
   633       while (di)
       
   634       {
       
   635         DiagramItem *pi=di->parentItem();
       
   636         DiagramItemList *dil=pi->getChildren();
       
   637         DiagramItem *last=dil->getLast();
       
   638         if (di==last) // single child
       
   639         {
       
   640           if (bitmap) // draw pixels
       
   641           {
       
   642             x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2;
       
   643             if (doBase) // base classes
       
   644             {
       
   645               y = image->getHeight()-
       
   646                 (superRows-1)*(cellHeight+labelVertSpacing)-
       
   647                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   648               image->drawVertArrow(x,y,y+labelVertSpacing/2,
       
   649                                    protToColor(di->protection()),
       
   650                                    protToMask(di->protection()));
       
   651             }
       
   652             else // super classes
       
   653             {
       
   654               y = (baseRows-1)*(cellHeight+labelVertSpacing)-
       
   655                 labelVertSpacing/2+
       
   656                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   657               image->drawVertLine(x,y,y+labelVertSpacing/2,
       
   658                                   protToColor(di->protection()),
       
   659                                   protToMask(di->protection()));
       
   660             }
       
   661           }
       
   662           else // draw vectors
       
   663           {
       
   664             t << protToString(di->protection()) << endl;
       
   665             if (doBase)
       
   666             {
       
   667               t << "1 " << (di->xPos()/(float)gridWidth) << " " 
       
   668                 << (di->yPos()/(float)gridHeight+superRows-1) << " in\n";
       
   669             }
       
   670             else
       
   671             {
       
   672               t << "0 " << (di->xPos()/(float)gridWidth) << " " 
       
   673                 << ((float)superRows-0.25-di->yPos()/(float)gridHeight)
       
   674                 << " in\n";
       
   675             }
       
   676           }
       
   677         }
       
   678         else // multiple children, put them in a vertical list
       
   679         {
       
   680           if (bitmap)
       
   681           {
       
   682             x = di->parentItem()->xPos()*
       
   683               (cellWidth+labelHorSpacing)/gridWidth+cellWidth/2;
       
   684             if (doBase) // base classes
       
   685             {
       
   686               ys = image->getHeight()-
       
   687                 (superRows-1)*(cellHeight+labelVertSpacing)-
       
   688                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   689               y = ys - cellHeight/2;
       
   690             }
       
   691             else // super classes
       
   692             {
       
   693               ys = (baseRows-1)*(cellHeight+labelVertSpacing)+
       
   694                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   695               y = ys + cellHeight/2;
       
   696             }
       
   697           }
       
   698           else
       
   699           {
       
   700             xf = di->parentItem()->xPos()/(float)gridWidth;
       
   701             if (doBase)
       
   702             {
       
   703               ysf = di->yPos()/(float)gridHeight+superRows-1;
       
   704               yf = ysf + 0.5;
       
   705             }
       
   706             else
       
   707             {
       
   708               ysf = (float)superRows-0.25-di->yPos()/(float)gridHeight;
       
   709               yf = ysf - 0.25;
       
   710             }
       
   711           }
       
   712           while (di!=last) // more children to add
       
   713           {
       
   714             if (bitmap)
       
   715             {
       
   716               if (doBase) // base classes
       
   717               {
       
   718                 image->drawHorzArrow(y,x,x+cellWidth/2+labelHorSpacing,
       
   719                     protToColor(di->protection()),
       
   720                     protToMask(di->protection()));
       
   721                 y -= cellHeight+labelVertSpacing;
       
   722               }
       
   723               else // super classes
       
   724               {
       
   725                 image->drawHorzLine(y,x,x+cellWidth/2+labelHorSpacing,
       
   726                     protToColor(di->protection()),
       
   727                     protToMask(di->protection()));
       
   728                 y += cellHeight+labelVertSpacing;
       
   729               }
       
   730             }
       
   731             else
       
   732             {
       
   733               t << protToString(di->protection()) << endl;
       
   734               if (doBase)
       
   735               {
       
   736                 t << "1 " << xf << " " << yf << " hedge\n";
       
   737                 yf += 1.0;
       
   738               }
       
   739               else
       
   740               {
       
   741                 t << "0 " << xf << " " << yf << " hedge\n";
       
   742                 yf -= 1.0;
       
   743               }
       
   744             }
       
   745             di=dr->next();
       
   746           }
       
   747           // add last horizonal line and a vertical connection line
       
   748           if (bitmap)
       
   749           {
       
   750             if (doBase) // base classes
       
   751             {
       
   752               image->drawHorzArrow(y,x,x+cellWidth/2+labelHorSpacing,
       
   753                   protToColor(di->protection()),
       
   754                   protToMask(di->protection()));
       
   755               image->drawVertLine(x,y,ys+labelVertSpacing/2,
       
   756                   protToColor(getMinProtectionLevel(dil)),
       
   757                   protToMask(getMinProtectionLevel(dil)));
       
   758             }
       
   759             else // super classes
       
   760             {
       
   761               image->drawHorzLine(y,x,x+cellWidth/2+labelHorSpacing,
       
   762                   protToColor(di->protection()),
       
   763                   protToMask(di->protection()));
       
   764               image->drawVertLine(x,ys-labelVertSpacing/2,y,
       
   765                   protToColor(getMinProtectionLevel(dil)),
       
   766                   protToMask(getMinProtectionLevel(dil)));
       
   767             }
       
   768           }
       
   769           else
       
   770           {
       
   771             t << protToString(di->protection()) << endl;
       
   772             if (doBase)
       
   773             {
       
   774               t << "1 " << xf << " " << yf << " hedge\n";
       
   775             }
       
   776             else
       
   777             {
       
   778               t << "0 " << xf << " " << yf << " hedge\n";
       
   779             }
       
   780             t << protToString(getMinProtectionLevel(dil)) << endl;
       
   781             if (doBase)
       
   782             {
       
   783               t << xf << " " << ysf << " " << yf << " vedge\n";
       
   784             }
       
   785             else
       
   786             {
       
   787               t << xf << " " << (ysf + 0.25) << " " << yf << " vedge\n";
       
   788             }
       
   789           }
       
   790         }
       
   791         di=dr->next();
       
   792       }
       
   793       done=TRUE; // the tree is drawn now
       
   794     }
       
   795     else // normal tree connector
       
   796     {
       
   797       while (di)
       
   798       {
       
   799         int x=0,y=0;
       
   800         DiagramItemList *dil = di->getChildren();
       
   801         DiagramItem *parent  = di->parentItem();
       
   802         if (parent) // item has a parent -> connect to it
       
   803         {
       
   804           if (bitmap) // draw pixels
       
   805           {
       
   806             x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2;
       
   807             if (doBase) // base classes
       
   808             {
       
   809               y = image->getHeight()-
       
   810                 (superRows-1)*(cellHeight+labelVertSpacing)-
       
   811                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   812               /* write input line */
       
   813               image->drawVertArrow(x,y,y+labelVertSpacing/2,
       
   814                   protToColor(di->protection()),
       
   815                   protToMask(di->protection()));
       
   816             }
       
   817             else // super classes
       
   818             {
       
   819               y = (baseRows-1)*(cellHeight+labelVertSpacing)-
       
   820                 labelVertSpacing/2+
       
   821                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   822               /* write output line */
       
   823               image->drawVertLine(x,y,y+labelVertSpacing/2,
       
   824                   protToColor(di->protection()),
       
   825                   protToMask(di->protection()));
       
   826             }
       
   827           }
       
   828           else // draw pixels
       
   829           {
       
   830             t << protToString(di->protection()) << endl;
       
   831             if (doBase)
       
   832             {
       
   833               t << "1 " << di->xPos()/(float)gridWidth << " " 
       
   834                 << (di->yPos()/(float)gridHeight+superRows-1) << " in\n";
       
   835             }
       
   836             else
       
   837             {
       
   838               t << "0 " << di->xPos()/(float)gridWidth << " " 
       
   839                 << ((float)superRows-0.25-di->yPos()/(float)gridHeight)
       
   840                 << " in\n";
       
   841             }
       
   842           }
       
   843         }
       
   844         if (dil->count()>0)
       
   845         {
       
   846           Protection p=getMinProtectionLevel(dil);
       
   847           uint mask=protToMask(p);
       
   848           uint col=protToColor(p);
       
   849           if (bitmap)
       
   850           {
       
   851             x = di->xPos()*(cellWidth+labelHorSpacing)/gridWidth + cellWidth/2;
       
   852             if (doBase) // base classes
       
   853             {
       
   854               y = image->getHeight()-
       
   855                 (superRows-1)*(cellHeight+labelVertSpacing)-
       
   856                 cellHeight-labelVertSpacing/2-
       
   857                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   858               image->drawVertLine(x,y,y+labelVertSpacing/2-1,col,mask);
       
   859             }
       
   860             else // super classes
       
   861             {
       
   862               y = (baseRows-1)*(cellHeight+labelVertSpacing)+
       
   863                 cellHeight+
       
   864                 di->yPos()*(cellHeight+labelVertSpacing)/gridHeight;
       
   865               image->drawVertArrow(x,y,y+labelVertSpacing/2-1,col,mask);
       
   866             }
       
   867           }
       
   868           else
       
   869           {
       
   870             t << protToString(p) << endl;
       
   871             if (doBase)
       
   872             {
       
   873               t << "0 " << di->xPos()/(float)gridWidth  << " " 
       
   874                 << (di->yPos()/(float)gridHeight+superRows-1) << " out\n";
       
   875             }
       
   876             else
       
   877             {
       
   878               t << "1 " << di->xPos()/(float)gridWidth  << " " 
       
   879                 << ((float)superRows-1.75-di->yPos()/(float)gridHeight)
       
   880                 << " out\n";
       
   881             }
       
   882           }
       
   883           /* write input line */
       
   884           DiagramItem *first = dil->first();
       
   885           DiagramItem *last  = dil->last();
       
   886           if (first!=last && !first->isInList()) /* connect with all base classes */
       
   887           {
       
   888             if (bitmap)
       
   889             {
       
   890               int xs = first->xPos()*(cellWidth+labelHorSpacing)/gridWidth
       
   891                 + cellWidth/2;
       
   892               int xe = last->xPos()*(cellWidth+labelHorSpacing)/gridWidth
       
   893                 + cellWidth/2; 
       
   894               if (doBase) // base classes
       
   895               {
       
   896                 image->drawHorzLine(y,xs,xe,col,mask); 
       
   897               }
       
   898               else // super classes
       
   899               {
       
   900                 image->drawHorzLine(y+labelVertSpacing/2,xs,xe,col,mask); 
       
   901               }
       
   902             }
       
   903             else
       
   904             {
       
   905               t << protToString(p) << endl;
       
   906               if (doBase)
       
   907               {
       
   908                 t << first->xPos()/(float)gridWidth << " " 
       
   909                   << last->xPos()/(float)gridWidth << " "
       
   910                   << (first->yPos()/(float)gridHeight+superRows-1) 
       
   911                   << " conn\n";
       
   912               }
       
   913               else
       
   914               {
       
   915                 t << first->xPos()/(float)gridWidth << " " 
       
   916                   << last->xPos()/(float)gridWidth << " "
       
   917                   << ((float)superRows-first->yPos()/(float)gridHeight)
       
   918                   << " conn\n";
       
   919               }
       
   920             }
       
   921           }
       
   922         }
       
   923         di=dr->next();
       
   924       }
       
   925       dr=next();
       
   926     }
       
   927   }
       
   928 }
       
   929 
       
   930 
       
   931 void clearVisitFlags()
       
   932 {
       
   933   ClassSDict::Iterator cli(*Doxygen::classSDict);
       
   934   ClassDef *cd;
       
   935   for (;(cd=cli.current());++cli)
       
   936   {
       
   937     cd->visited=FALSE;
       
   938   }
       
   939 }
       
   940 
       
   941 ClassDiagram::ClassDiagram(ClassDef *root)
       
   942 {
       
   943   clearVisitFlags();
       
   944   base  = new TreeDiagram(root,TRUE);
       
   945   base->computeLayout();
       
   946   clearVisitFlags();
       
   947   super = new TreeDiagram(root,FALSE);
       
   948   super->computeLayout();
       
   949   DiagramItem *baseItem  = base->first()->first();
       
   950   DiagramItem *superItem = super->first()->first();
       
   951   int xbase  = baseItem->xPos();
       
   952   int xsuper = superItem->xPos();
       
   953   if (xbase>xsuper)
       
   954   {
       
   955     superItem->move(xbase-xsuper,0);
       
   956     super->moveChildren(superItem,xbase-xsuper);
       
   957   }
       
   958   else if (xbase<xsuper)
       
   959   {
       
   960     baseItem->move(xsuper-xbase,0);
       
   961     base->moveChildren(baseItem,xsuper-xbase);
       
   962   }
       
   963 }
       
   964 
       
   965 ClassDiagram::~ClassDiagram()
       
   966 {
       
   967   delete base;
       
   968   delete super;
       
   969 }
       
   970 
       
   971 void ClassDiagram::writeFigure(QTextStream &output,const char *path,
       
   972                                const char *fileName) const
       
   973 {
       
   974   uint baseRows=base->computeRows();
       
   975   uint superRows=super->computeRows();
       
   976   uint baseMaxX, baseMaxLabelWidth, superMaxX, superMaxLabelWidth;
       
   977   base->computeExtremes(&baseMaxLabelWidth,&baseMaxX);
       
   978   super->computeExtremes(&superMaxLabelWidth,&superMaxX);
       
   979 
       
   980   uint rows=baseRows+superRows-1;
       
   981   uint cols=(QMAX(baseMaxX,superMaxX)+gridWidth*2-1)/gridWidth;
       
   982   
       
   983   // Estimate the image aspect width and height in pixels.
       
   984   uint estHeight = rows*40;
       
   985   uint estWidth  = cols*(20+QMAX(baseMaxLabelWidth,superMaxLabelWidth));
       
   986   //printf("Estimated size %d x %d\n",estWidth,estHeight);
       
   987   
       
   988   const float pageWidth = 14.0; // estimated page width in cm.
       
   989                                 // Somewhat lower to deal with estimation
       
   990                                 // errors. 
       
   991   
       
   992   // compute the image height in centimeters based on the estimates
       
   993   float realHeight = QMIN(rows,12); // real height in cm
       
   994   float realWidth  = realHeight * estWidth/(float)estHeight;
       
   995   if (realWidth>pageWidth) // assume that the page width is about 15 cm
       
   996   {
       
   997     realHeight*=pageWidth/realWidth; 
       
   998     realWidth=pageWidth;
       
   999   }
       
  1000 
       
  1001   //output << "}\n";
       
  1002   output << ":\\begin{figure}[H]\n"
       
  1003             "\\begin{center}\n"
       
  1004             "\\leavevmode\n";
       
  1005   output << "\\includegraphics[height=" << realHeight << "cm]{" 
       
  1006                                         << fileName << "}" << endl;
       
  1007   output << "\\end{center}\n"
       
  1008             "\\end{figure}\n";
       
  1009   
       
  1010   //printf("writeFigure rows=%d cols=%d\n",rows,cols);
       
  1011 
       
  1012   QCString epsBaseName=(QCString)path+"/"+fileName;
       
  1013   QCString epsName=epsBaseName+".eps";
       
  1014   QFile f1;
       
  1015   f1.setName(epsName.data());
       
  1016   if (!f1.open(IO_WriteOnly))
       
  1017   {
       
  1018     err("Could not open file %s for writing\n",convertToQCString(f1.name()).data());
       
  1019     exit(1);
       
  1020   }
       
  1021   QTextStream t(&f1);
       
  1022   
       
  1023   //printf("writeEPS() rows=%d cols=%d\n",rows,cols);
       
  1024   
       
  1025   // generate EPS header and postscript variables and procedures
       
  1026   
       
  1027   t << "%!PS-Adobe-2.0 EPSF-2.0\n";
       
  1028   t << "%%Title: ClassName\n";
       
  1029   t << "%%Creator: Doxygen\n";
       
  1030   t << "%%CreationDate: Time\n";
       
  1031   t << "%%For: \n";
       
  1032   t << "%Magnification: 1.00\n";
       
  1033   t << "%%Orientation: Portrait\n";
       
  1034   t << "%%BoundingBox: 0 0 500 " << estHeight*500.0/(float)estWidth << "\n";
       
  1035   t << "%%Pages: 0\n";
       
  1036   t << "%%BeginSetup\n";
       
  1037   t << "%%EndSetup\n";
       
  1038   t << "%%EndComments\n";
       
  1039   t << "\n";
       
  1040   t << "% ----- variables -----\n";
       
  1041   t << "\n";
       
  1042   t << "/boxwidth 0 def\n";
       
  1043   t << "/boxheight 40 def\n";
       
  1044   t << "/fontheight 24 def\n";
       
  1045   t << "/marginwidth 10 def\n";
       
  1046   t << "/distx 20 def\n";
       
  1047   t << "/disty 40 def\n";
       
  1048   t << "/boundaspect " << estWidth/(float)estHeight << " def  % aspect ratio of the BoundingBox (width/height)\n";
       
  1049   t << "/boundx 500 def\n";
       
  1050   t << "/boundy boundx boundaspect div def\n";
       
  1051   t << "/xspacing 0 def\n";
       
  1052   t << "/yspacing 0 def\n";
       
  1053   t << "/rows " << rows << " def\n";
       
  1054   t << "/cols " << cols << " def\n";
       
  1055   t << "/scalefactor 0 def\n";
       
  1056   t << "/boxfont /Times-Roman findfont fontheight scalefont def\n";
       
  1057   t << "\n";
       
  1058   t << "% ----- procedures -----\n";
       
  1059   t << "\n";
       
  1060   t << "/dotted { [1 4] 0 setdash } def\n";
       
  1061   t << "/dashed { [5] 0 setdash } def\n";
       
  1062   t << "/solid  { [] 0 setdash } def\n";
       
  1063   t << "\n";
       
  1064   t << "/max % result = MAX(arg1,arg2)\n";
       
  1065   t << "{\n";
       
  1066   t << "  /a exch def\n";
       
  1067   t << "  /b exch def\n";
       
  1068   t << "  a b gt {a} {b} ifelse\n";
       
  1069   t << "} def\n";
       
  1070   t << "\n";
       
  1071   t << "/xoffset % result = MAX(0,(scalefactor-(boxwidth*cols+distx*(cols-1)))/2)\n";
       
  1072   t << "{\n";
       
  1073   t << "  0 scalefactor boxwidth cols mul distx cols 1 sub mul add sub 2 div max\n";
       
  1074   t << "} def\n";
       
  1075   t << "\n";
       
  1076   t << "/cw % boxwidth = MAX(boxwidth, stringwidth(arg1))\n";
       
  1077   t << "{\n";
       
  1078   t << "  /str exch def\n";
       
  1079   t << "  /boxwidth boxwidth str stringwidth pop max def\n";
       
  1080   t << "} def\n";
       
  1081   t << "\n";
       
  1082   t << "/box % draws a box with text `arg1' at grid pos (arg2,arg3)\n";
       
  1083   t << "{ gsave\n";
       
  1084   t << "  2 setlinewidth\n";
       
  1085   t << "  newpath\n";
       
  1086   t << "  exch xspacing mul xoffset add\n";
       
  1087   t << "  exch yspacing mul\n";
       
  1088   t << "  moveto\n";
       
  1089   t << "  boxwidth 0 rlineto \n";
       
  1090   t << "  0 boxheight rlineto \n";
       
  1091   t << "  boxwidth neg 0 rlineto \n";
       
  1092   t << "  0 boxheight neg rlineto \n";
       
  1093   t << "  closepath\n";
       
  1094   t << "  dup stringwidth pop neg boxwidth add 2 div\n";
       
  1095   t << "  boxheight fontheight 2 div sub 2 div\n";
       
  1096   t << "  rmoveto show stroke\n";
       
  1097   t << "  grestore\n";
       
  1098   t << "} def  \n";
       
  1099   t << "\n";
       
  1100   t << "/mark\n";
       
  1101   t << "{ newpath\n";
       
  1102   t << "  exch xspacing mul xoffset add boxwidth add\n";
       
  1103   t << "  exch yspacing mul\n";
       
  1104   t << "  moveto\n";
       
  1105   t << "  0 boxheight 4 div rlineto\n";
       
  1106   t << "  boxheight neg 4 div boxheight neg 4 div rlineto\n";
       
  1107   t << "  closepath\n";
       
  1108   t << "  eofill\n";
       
  1109   t << "  stroke\n";
       
  1110   t << "} def\n";
       
  1111   t << "\n";
       
  1112   t << "/arrow\n";
       
  1113   t << "{ newpath\n";
       
  1114   t << "  moveto\n";
       
  1115   t << "  3 -8 rlineto\n";
       
  1116   t << "  -6 0 rlineto\n";
       
  1117   t << "  3 8 rlineto\n";
       
  1118   t << "  closepath\n";
       
  1119   t << "  eofill\n";
       
  1120   t << "  stroke\n";
       
  1121   t << "} def\n";
       
  1122   t << "\n";
       
  1123   t << "/out % draws an output connector for the block at (arg1,arg2)\n";
       
  1124   t << "{\n";
       
  1125   t << "  newpath\n";
       
  1126   t << "  exch xspacing mul xoffset add boxwidth 2 div add\n";
       
  1127   t << "  exch yspacing mul boxheight add\n";
       
  1128   t << "  /y exch def\n";
       
  1129   t << "  /x exch def\n";
       
  1130   t << "  x y moveto\n";
       
  1131   t << "  0 disty 2 div rlineto \n";
       
  1132   t << "  stroke\n";
       
  1133   t << "  1 eq { x y disty 2 div add arrow } if\n";
       
  1134   t << "} def\n";
       
  1135   t << "\n";
       
  1136   t << "/in % draws an input connector for the block at (arg1,arg2)\n";
       
  1137   t << "{\n";
       
  1138   t << "  newpath\n";
       
  1139   t << "  exch xspacing mul xoffset add boxwidth 2 div add\n";
       
  1140   t << "  exch yspacing mul disty 2 div sub\n";
       
  1141   t << "  /y exch def\n";
       
  1142   t << "  /x exch def\n";
       
  1143   t << "  x y moveto\n";
       
  1144   t << "  0 disty 2 div rlineto\n";
       
  1145   t << "  stroke\n";
       
  1146   t << "  1 eq { x y disty 2 div add arrow } if\n";
       
  1147   t << "} def\n";
       
  1148   t << "\n";
       
  1149   t << "/hedge\n";
       
  1150   t << "{\n";
       
  1151   t << "  exch xspacing mul xoffset add boxwidth 2 div add\n";
       
  1152   t << "  exch yspacing mul boxheight 2 div sub\n";
       
  1153   t << "  /y exch def\n";
       
  1154   t << "  /x exch def\n";
       
  1155   t << "  newpath\n";
       
  1156   t << "  x y moveto\n";
       
  1157   t << "  boxwidth 2 div distx add 0 rlineto\n";
       
  1158   t << "  stroke\n";
       
  1159   t << "  1 eq\n";
       
  1160   t << "  { newpath x boxwidth 2 div distx add add y moveto\n";
       
  1161   t << "    -8 3 rlineto\n";
       
  1162   t << "    0 -6 rlineto\n";
       
  1163   t << "    8 3 rlineto\n";
       
  1164   t << "    closepath\n";
       
  1165   t << "    eofill\n";
       
  1166   t << "    stroke\n";
       
  1167   t << "  } if\n";
       
  1168   t << "} def\n";
       
  1169   t << "\n";
       
  1170   t << "/vedge\n";
       
  1171   t << "{\n";
       
  1172   t << "  /ye exch def\n";
       
  1173   t << "  /ys exch def\n";
       
  1174   t << "  /xs exch def\n";
       
  1175   t << "  newpath\n";
       
  1176   t << "  xs xspacing mul xoffset add boxwidth 2 div add dup\n";
       
  1177   t << "  ys yspacing mul boxheight 2 div sub\n";
       
  1178   t << "  moveto\n";
       
  1179   t << "  ye yspacing mul boxheight 2 div sub\n";
       
  1180   t << "  lineto\n";
       
  1181   t << "  stroke\n";
       
  1182   t << "} def\n";
       
  1183   t << "\n";
       
  1184   t << "/conn % connections the blocks from col `arg1' to `arg2' of row `arg3'\n";
       
  1185   t << "{\n";
       
  1186   t << "  /ys exch def\n";
       
  1187   t << "  /xe exch def\n";
       
  1188   t << "  /xs exch def\n";
       
  1189   t << "  newpath\n";
       
  1190   t << "  xs xspacing mul xoffset add boxwidth 2 div add\n";
       
  1191   t << "  ys yspacing mul disty 2 div sub\n";
       
  1192   t << "  moveto\n";
       
  1193   t << "  xspacing xe xs sub mul 0\n";
       
  1194   t << "  rlineto\n";
       
  1195   t << "  stroke\n";
       
  1196   t << "} def\n";
       
  1197   t << "\n";
       
  1198   t << "% ----- main ------\n";
       
  1199   t << "\n";
       
  1200   t << "boxfont setfont\n";
       
  1201   t << "1 boundaspect scale\n";
       
  1202 
       
  1203   
       
  1204   bool done=FALSE;
       
  1205   DiagramRow *dr=base->first();
       
  1206   while (dr && !done)
       
  1207   {
       
  1208     DiagramItem *di=dr->first();
       
  1209     while (di)
       
  1210     {
       
  1211       done=di->isInList();
       
  1212       t << "(" << di->label() << ") cw\n";
       
  1213       di=dr->next();
       
  1214     }
       
  1215     dr=base->next();
       
  1216   }
       
  1217   dr=super->first();
       
  1218   dr=super->next();
       
  1219   done=FALSE;
       
  1220   while (dr && !done)
       
  1221   {
       
  1222     DiagramItem *di=dr->first();
       
  1223     while (di)
       
  1224     {
       
  1225       done=di->isInList();
       
  1226       t << "(" << di->label() << ") cw\n";
       
  1227       di=dr->next();
       
  1228     }
       
  1229     dr=super->next();
       
  1230   }
       
  1231   
       
  1232   t << "/boxwidth boxwidth marginwidth 2 mul add def\n"
       
  1233     << "/xspacing boxwidth distx add def\n"
       
  1234     << "/yspacing boxheight disty add def\n"
       
  1235     << "/scalefactor \n"
       
  1236     << "  boxwidth cols mul distx cols 1 sub mul add\n"
       
  1237     << "  boxheight rows mul disty rows 1 sub mul add boundaspect mul \n"
       
  1238     << "  max def\n"
       
  1239     << "boundx scalefactor div boundy scalefactor div scale\n";
       
  1240   
       
  1241   t << "\n% ----- classes -----\n\n";
       
  1242   base->drawBoxes(t,0,TRUE,FALSE,baseRows,superRows,0,0);
       
  1243   super->drawBoxes(t,0,FALSE,FALSE,baseRows,superRows,0,0);
       
  1244   
       
  1245   t << "\n% ----- relations -----\n\n";
       
  1246   base->drawConnectors(t,0,TRUE,FALSE,baseRows,superRows,0,0);
       
  1247   super->drawConnectors(t,0,FALSE,FALSE,baseRows,superRows,0,0);
       
  1248 
       
  1249   f1.close();
       
  1250   if (Config_getBool("USE_PDFLATEX"))
       
  1251   {
       
  1252     QCString epstopdfArgs(4096);
       
  1253     epstopdfArgs.sprintf("\"%s.eps\" --outfile=\"%s.pdf\"",
       
  1254                    epsBaseName.data(),epsBaseName.data());
       
  1255     //printf("Converting eps using `%s'\n",epstopdfCmd.data());
       
  1256     if (portable_system("epstopdf",epstopdfArgs)!=0)
       
  1257     {
       
  1258        err("Error: Problems running epstopdf. Check your TeX installation!\n");
       
  1259        return;
       
  1260     }
       
  1261   }
       
  1262 }
       
  1263 
       
  1264 
       
  1265 void ClassDiagram::writeImage(QTextStream &t,const char *path,
       
  1266                               const char *relPath,const char *fileName, 
       
  1267                               bool generateMap) const
       
  1268 {
       
  1269   uint baseRows=base->computeRows();
       
  1270   uint superRows=super->computeRows();
       
  1271   uint rows=baseRows+superRows-1;
       
  1272 
       
  1273   uint lb,ls,xb,xs;
       
  1274   base->computeExtremes(&lb,&xb);
       
  1275   super->computeExtremes(&ls,&xs);
       
  1276  
       
  1277   uint cellWidth  = QMAX(lb,ls)+labelHorMargin*2;
       
  1278   uint maxXPos    = QMAX(xb,xs);
       
  1279   uint labelVertMargin = 6; //QMAX(6,(cellWidth-fontHeight)/6); // aspect at least 1:3
       
  1280   uint cellHeight = labelVertMargin*2+fontHeight;
       
  1281   uint imageWidth = (maxXPos+gridWidth)*cellWidth/gridWidth+
       
  1282                     (maxXPos*labelHorSpacing)/gridWidth;
       
  1283   uint imageHeight = rows*cellHeight+(rows-1)*labelVertSpacing;
       
  1284 
       
  1285   Image image(imageWidth,imageHeight);
       
  1286 
       
  1287   base->drawBoxes(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap);
       
  1288   super->drawBoxes(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap);
       
  1289   base->drawConnectors(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight);
       
  1290   super->drawConnectors(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight);
       
  1291 
       
  1292 #define IMAGE_EXT ".png"
       
  1293   image.save((QCString)path+"/"+fileName+IMAGE_EXT);
       
  1294   Doxygen::indexList.addImageFile(QCString(fileName)+IMAGE_EXT);
       
  1295   
       
  1296   if (generateMap) t << "</map>" << endl;
       
  1297 }
       
  1298