Root/
Source at commit 1322 created 12 years 8 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 | ␊ |
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(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 | ␊ |
154 | static 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 | ␊ |
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 = 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(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 | ␊ |
619 | void 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 | ␊ |
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(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 | ␊ |
1268 | void 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 |