|
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 |