Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/diagram.cpp

Source at commit 1322 created 9 years 5 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 * $Id: diagram.cpp,v 1.30 2001/03/19 19:27:40 root Exp $
4 *
5 *
6 * Copyright (C) 1997-2011 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 "ftextstream.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
39const uint maxTreeWidth = 8;
40const int gridWidth = 100;
41const int gridHeight = 100;
42
43const uint labelHorSpacing = 10; // horizontal distance between labels
44const uint labelVertSpacing = 32; // vertical distance between labels
45const uint labelHorMargin = 6; // horiz. spacing between label and box
46const 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
60static 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
72static 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
84static 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
96static 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
108static 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
126static 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
145static void writeVectorBox(FTextStream &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
154static void writeMapArea(FTextStream &t,ClassDef *cd,QCString relPath,
155 int x,int y,int w,int h)
156{
157 if (cd->isLinkable())
158 {
159 QCString ref=cd->getReference();
160 t << "<area ";
161 if (!ref.isEmpty())
162 {
163 t << externalLinkTarget() << externalRef(relPath,ref,FALSE);
164 }
165 t << "href=\"";
166 t << externalRef(relPath,ref,TRUE);
167 t << cd->getOutputFileBase() << Doxygen::htmlFileExtension;
168 if (!cd->anchor().isEmpty())
169 {
170 t << "#" << cd->anchor();
171 }
172 t << "\" ";
173 QCString tooltip = cd->briefDescriptionAsTooltip();
174 if (!tooltip.isEmpty())
175 {
176 t << "title=\"" << tooltip << "\" ";
177 }
178 t << "alt=\"" << convertToXML(cd->displayName());
179 t << "\" shape=\"rect\" coords=\"" << x << "," << y << ",";
180 t << (x+w) << "," << (y+h) << "\"/>" << endl;
181 }
182}
183//-----------------------------------------------------------------------------
184
185DiagramItem::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
200DiagramItem::~DiagramItem()
201{
202 delete children;
203}
204
205QCString 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
222QCString DiagramItem::fileName() const
223{
224 return classDef->getOutputFileBase();
225}
226
227int 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
241int DiagramItem::numChildren() const
242{
243 return children->count();
244}
245
246void DiagramItem::addChild(DiagramItem *di)
247{
248 children->append(di);
249}
250
251void 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
303TreeDiagram::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
311TreeDiagram::~TreeDiagram()
312{
313}
314
315
316void 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
328bool 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 = layoutTree(di,r+1);
363 di=dil->next();
364 }
365 }
366 return moved;
367}
368
369void 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
417uint 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
447uint 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
467void 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
488void TreeDiagram::drawBoxes(FTextStream &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
619void TreeDiagram::drawConnectors(FTextStream &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
931void 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
941ClassDiagram::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
965ClassDiagram::~ClassDiagram()
966{
967 delete base;
968 delete super;
969}
970
971void ClassDiagram::writeFigure(FTextStream &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 FTextStream 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 portable_sysTimerStart();
1257 if (portable_system("epstopdf",epstopdfArgs)!=0)
1258 {
1259 err("error: Problems running epstopdf. Check your TeX installation!\n");
1260 portable_sysTimerStop();
1261 return;
1262 }
1263 portable_sysTimerStop();
1264 }
1265}
1266
1267
1268void ClassDiagram::writeImage(FTextStream &t,const char *path,
1269 const char *relPath,const char *fileName,
1270 bool generateMap) const
1271{
1272 uint baseRows=base->computeRows();
1273 uint superRows=super->computeRows();
1274 uint rows=baseRows+superRows-1;
1275
1276 uint lb,ls,xb,xs;
1277 base->computeExtremes(&lb,&xb);
1278 super->computeExtremes(&ls,&xs);
1279
1280 uint cellWidth = QMAX(lb,ls)+labelHorMargin*2;
1281 uint maxXPos = QMAX(xb,xs);
1282 uint labelVertMargin = 6; //QMAX(6,(cellWidth-fontHeight)/6); // aspect at least 1:3
1283 uint cellHeight = labelVertMargin*2+fontHeight;
1284 uint imageWidth = (maxXPos+gridWidth)*cellWidth/gridWidth+
1285 (maxXPos*labelHorSpacing)/gridWidth;
1286 uint imageHeight = rows*cellHeight+(rows-1)*labelVertSpacing;
1287
1288 Image image(imageWidth,imageHeight);
1289
1290 base->drawBoxes(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap);
1291 super->drawBoxes(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight,relPath,generateMap);
1292 base->drawConnectors(t,&image,TRUE,TRUE,baseRows,superRows,cellWidth,cellHeight);
1293 super->drawConnectors(t,&image,FALSE,TRUE,baseRows,superRows,cellWidth,cellHeight);
1294
1295#define IMAGE_EXT ".png"
1296 image.save((QCString)path+"/"+fileName+IMAGE_EXT);
1297 Doxygen::indexList.addImageFile(QCString(fileName)+IMAGE_EXT);
1298
1299 if (generateMap) t << "</map>" << endl;
1300}
1301
1302

Archive Download this file

Revision: 1322