00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 #include <config.h>
00020 #endif
00021
00022 using namespace std;
00023
00024 #include "project.h"
00025 #include "reporter.h"
00026
00027 static NETWORK_CELL **network_cols;
00028 static int numX;
00029 static int numY;
00030
00031
00032
00033 void Reporter::constructStartFinish( Project *project )
00034 {
00035 mStartTask = new TASK("", "START", 0);
00036 mStartTask->setStart(0);
00037 mStartTask->nx = 0;
00038 mStartTask->ny = project->networkStartY();
00039
00040 mFinishTask = new TASK("", "FINISH", 0);
00041 mFinishTask->setStart(0);
00042 mFinishTask->nx = numX - 1;
00043 mFinishTask->ny = project->networkFinishY();
00044 }
00045
00046
00047
00048 static int canAssignX(TASK *task)
00049 {
00050 if ( task->nx != -1)
00051 return 0;
00052
00053 if ( task->isVacation() )
00054 return 0;
00055
00056 for ( TASK::PTRLIST::const_iterator pt = task->begin_depends();
00057 pt != task->end_depends();
00058 pt++ )
00059 if ( (*pt)->nx == -1 )
00060 return 0;
00061
00062 return 1;
00063 }
00064
00065
00066
00067 static void assignX(TASK *task)
00068 {
00069
00070
00071 int max_depend = 0;
00072 for ( TASK::PTRLIST::const_iterator pt = task->begin_depends();
00073 pt != task->end_depends();
00074 pt++ )
00075 if ( (*pt)->nx > max_depend )
00076 max_depend = (*pt)->nx;
00077
00078 task->nx = max_depend + 1;
00079 }
00080
00081
00082
00083 int Reporter::maximumX(Project *project)
00084 {
00085 int maxX = -1;
00086 for ( Project::TPLCI pt = project->beginTaskList() ;
00087 pt != project->endTaskList() ;
00088 pt++ )
00089 {
00090 if ( (*pt)->isVacation() )
00091 continue;
00092
00093 if ( (*pt)->nx > maxX )
00094 maxX = (*pt)->nx;
00095 }
00096 if ( maxX == -1 )
00097 Error("Can't find maxX in maximuX()");
00098
00099 return maxX;
00100 }
00101
00102
00103 static int nextAvailableY(NETWORK_CELL *clist, int y)
00104 {
00105 NETWORK_CELL *pc;
00106 int ny;
00107
00108 ny = y;
00109 while (1)
00110 {
00111 ny++;
00112 for ( pc = clist; pc != NULL; pc = pc->next )
00113 if ( pc->task->ny == ny )
00114 break;
00115 if ( pc == NULL )
00116 return ny;
00117 }
00118 return 0;
00119 }
00120
00121
00122
00123 void Reporter::assignY(Project *project)
00124 {
00125 int y;
00126 int x;
00127 NETWORK_CELL *pc;
00128 NETWORK_CELL *cell;
00129
00130
00131 numX = maximumX(project);
00132
00133
00134
00135 numX++;
00136
00137 numX++;
00138
00139 if ((network_cols = (NETWORK_CELL **)malloc(sizeof(NETWORK_CELL *) * numX)) == NULL)
00140 Error("assignY: Couldn't alloc network_cols");
00141 for ( x = 0; x < numX ; x++ )
00142 network_cols[x] = NULL;
00143
00144
00145 for ( Project::TPLCI pt = project->beginTaskList() ;
00146 pt != project->endTaskList() ;
00147 pt++ )
00148 {
00149 if ( (*pt)->isVacation() )
00150 continue;
00151
00152 x = (*pt)->nx;
00153
00154 if ( ( cell = (NETWORK_CELL *)malloc(sizeof(NETWORK_CELL))) == NULL)
00155 Error("assignY: Can't alloc network cell");
00156 cell->task = (*pt);
00157 cell->isSpace = 0;
00158 cell->prev = NULL;
00159 cell->next = NULL;
00160
00161 if ( network_cols[x] == NULL )
00162 network_cols[x] = cell;
00163 else
00164 {
00165 for ( pc = network_cols[x]; pc->next != NULL; pc = pc->next )
00166 ;
00167 cell->prev = pc;
00168 pc->next = cell;
00169 }
00170 }
00171
00172
00173 for ( x = 0; x < numX; x++ )
00174 {
00175 y = nextAvailableY(network_cols[x], -1);
00176 for ( pc = network_cols[x]; pc != NULL; pc = pc->next )
00177 if ( pc->task->ny == -1 )
00178 {
00179 pc->task->ny = y;
00180 y = nextAvailableY(network_cols[x], y);
00181 }
00182 }
00183
00184
00185 numY = 0;
00186 for ( x = 0; x < numX; x++ )
00187 for ( pc = network_cols[x]; pc != NULL; pc = pc->next )
00188 if ( pc->task->ny > numY )
00189 numY = pc->task->ny;
00190 numY++;
00191 }
00192
00193
00194 FILE *Reporter::openNetworkDiagram( Project *project,
00195 const char *filename,
00196 int llx, int lly, int urx, int ury)
00197 {
00198 FILE *f;
00199
00200 if ( ( f = fopen(filename, "w") ) == NULL )
00201 {
00202 Error("Cannot open file [%s]",filename);
00203 }
00204
00205 fprintf(f, "%%!\n");
00206 fprintf(f, "%%%%BoundingBox: %d %d %d %d\n",llx,lly,urx,ury);
00207
00208 fprintf(f, "/OUTLINE\n");
00209 fprintf(f, "{\n");
00210 fprintf(f, " /y2 exch def /y1 exch def /x2 exch def /x1 exch def\n");
00211 fprintf(f, " x1 y1 moveto\n");
00212 fprintf(f, " x2 y1 lineto\n");
00213 fprintf(f, " x2 y2 lineto\n");
00214 fprintf(f, " x1 y2 lineto\n");
00215 fprintf(f, " closepath\n");
00216 fprintf(f, " 0 setgray\n");
00217 fprintf(f, " stroke\n");
00218 fprintf(f, "} def\n");
00219
00220 fprintf(f, "/BACKGROUND\n");
00221 fprintf(f, "{\n");
00222 fprintf(f, " /y2 exch def /y1 exch def /x2 exch def /x1 exch def\n");
00223 fprintf(f, " x1 y1 moveto\n");
00224 fprintf(f, " x2 y1 lineto\n");
00225 fprintf(f, " x2 y2 lineto\n");
00226 fprintf(f, " x1 y2 lineto\n");
00227 fprintf(f, " closepath\n");
00228 fprintf(f, " %f setgray\n", tg_white);
00229 fprintf(f, " fill\n");
00230 fprintf(f, "} def\n");
00231
00232 fprintf(f, "/%s findfont\n", pc_fontname1);
00233 fprintf(f, "dup length dict begin\n");
00234 fprintf(f, " { 1 index /FID ne\n");
00235 fprintf(f, " {def}\n");
00236 fprintf(f, " {pop pop}\n");
00237 fprintf(f, " ifelse\n");
00238 fprintf(f, " } forall\n");
00239 fprintf(f, " /Encoding ISOLatin1Encoding def\n");
00240 fprintf(f, " currentdict\n");
00241 fprintf(f, "end\n");
00242 fprintf(f, "/%s-ISOLatin1 exch definefont pop\n", pc_fontname1);
00243 fprintf(f, "/%s findfont %f scalefont setfont\n",
00244 pc_fontname1, pc_fontsize1 );
00245
00246 fprintf(f, "0 setgray\n");
00247 fprintf(f, "0.01 setlinewidth\n");
00248
00249 return f;
00250 }
00251
00252
00253 NETWORK_CELL *Reporter::findCellInColumn(int x, const char *id)
00254 {
00255 NETWORK_CELL *cell;
00256
00257 for ( cell = network_cols[x] ; cell != NULL ; cell = cell->next )
00258 {
00259 if ( cell->isSpace )
00260 continue;
00261 if ( strcmp( cell->task->id(), id ) == 0 )
00262 return cell;
00263 }
00264
00265 Error("Asked for cell (%s) in col (%d) but not there", id, x );
00266 return NULL;
00267 }
00268
00269
00270 void Reporter::write_milestones( Project *project,
00271 FILE *fp, int ax, int bx, int ay, int by)
00272 {
00273 for ( Project::MPLCI ml = project->beginMilestoneList() ;
00274 ml != project->endMilestoneList() ;
00275 ml++ )
00276 {
00277 MILESTONE * m = *ml;
00278 TASK * t = m->critical();
00279
00280 int px = ax * t->nx + bx + pc_width;
00281 int py = ay * t->ny + by + pc_height;
00282
00283 fprintf(fp, "%d %d moveto ", px + pc_height / 8, py + pc_height / 4);
00284 fprintf(fp, "%d %d lineto ", px, py);
00285 fprintf(fp, "%d %d lineto ", px - pc_height / 8, py + pc_height / 4);
00286 fprintf(fp, "%d %d lineto ", px + pc_width / 3, py + pc_height / 4);
00287 fprintf(fp, "stroke\n");
00288
00289 fprintf(fp, "%d %d moveto ", px - pc_height / 8,
00290 py + pc_height / 4 + pc_textup );
00291 char buf[1024];
00292 if (milestone_ids)
00293 sprintf(buf, "%s %s", m->id(), m->name());
00294 else
00295 sprintf(buf, "%s", m->name());
00296 fprintf(fp, "(%s) show\n", buf);
00297 }
00298 }
00299
00300
00301
00302 void Reporter::write_chart( Project *project,
00303 int start, int finish, const char *filename)
00304 {
00305 int minX;
00306 int maxX;
00307 int minY;
00308 int maxY;
00309 int sizeX;
00310 int sizeY;
00311 int x;
00312 NETWORK_CELL *cell;
00313 int px, py;
00314 int ax, bx, ay, by;
00315 int llx, lly, urx, ury;
00316 FILE *fp;
00317 char buf[1024];
00318 int pxd, pyd;
00319 NETWORK_CELL *pc;
00320 int c0, c1, c2;
00321 int r0, r1, r2, r3;
00322 double dTextHeight;
00323
00324
00325 if ( start > 0 )
00326 minX = start;
00327 else
00328 minX = 0;
00329 if ( finish < numX )
00330 maxX = finish;
00331 else
00332 maxX = numX - 1;
00333 sizeX = maxX - minX + 1;
00334 minY = numY;
00335 maxY = 0;
00336 for ( x = minX ; x <= maxX ; x++)
00337 for ( cell = network_cols[x] ; cell != NULL ; cell = cell->next )
00338 {
00339 if ( cell->task->ny < minY )
00340 minY = cell->task->ny;
00341 if ( cell->task->ny > maxY )
00342 maxY = cell->task->ny;
00343 }
00344 sizeY = maxY - minY + 1;
00345
00346
00347
00348
00349
00350
00351 ax = pc_width + pc_space;
00352 bx = -ax * minX;
00353 ay = -( pc_height + pc_space );
00354 by = ( pc_height + pc_space ) * maxY;
00355
00356
00357 llx = 0;
00358 lly = -1;
00359 urx = ax * maxX + bx + pc_width + 1;
00360 ury = ay * minY + by + pc_height;
00361
00362
00363 urx += pc_width / 3;
00364 ury += pc_height / 2;
00365
00366 fp = openNetworkDiagram(project, filename, llx, lly, urx, ury);
00367
00368
00369 for ( x = minX ; x <= maxX ; x++)
00370 {
00371 px = ax * x + bx;
00372 for ( cell = network_cols[x] ; cell != NULL ; cell = cell->next )
00373 {
00374 if ( cell->isSpace )
00375 continue;
00376
00377 py = ay * cell->task->ny + by;
00378
00379 if ( cell->task->begin_depends() == cell->task->end_depends() )
00380 {
00381 if ( minX == 0 )
00382 {
00383 pxd = ax * mStartTask->nx + bx;
00384 pyd = ay * mStartTask->ny + by;
00385
00386 fprintf(fp, "%d %d moveto\n", px, py + pc_height / 2 );
00387 fprintf(fp, "%d %d lineto\n",
00388 pxd + pc_width, pyd + pc_height / 2 );
00389 fprintf(fp, "stroke\n" );
00390 }
00391 }
00392 else
00393 {
00394 for ( TASK::PTRLIST::const_iterator pt = cell->task->begin_depends();
00395 pt != cell->task->end_depends();
00396 pt++ )
00397 {
00398 pc = findCellInColumn( (*pt)->nx , (*pt)->id() );
00399 pxd = ax * pc->task->nx + bx;
00400 pyd = ay * pc->task->ny + by;
00401
00402 fprintf(fp, "%d %d moveto\n", px, py + pc_height / 2 );
00403 fprintf(fp, "%d %d lineto\n",
00404 pxd + pc_width, pyd + pc_height / 2 );
00405 fprintf(fp, "stroke\n" );
00406 }
00407 }
00408 }
00409 }
00410 if ( maxX == numX - 1 )
00411 {
00412 px = ax * maxX + bx;
00413 py = ay * mFinishTask->ny + by;
00414 for ( x = minX ; x <= maxX ; x++)
00415 {
00416 for ( cell = network_cols[x] ; cell != NULL ; cell = cell->next )
00417 {
00418 if ( cell->isSpace )
00419 continue;
00420
00421 if ( cell->task->begin_follows() == cell->task->end_follows() )
00422 {
00423 pxd = ax * cell->task->nx + bx;
00424 pyd = ay * cell->task->ny + by;
00425
00426 fprintf(fp, "%d %d moveto\n", px, py + pc_height / 2 );
00427 fprintf(fp, "%d %d lineto\n",
00428 pxd + pc_width, pyd + pc_height / 2 );
00429 fprintf(fp, "stroke\n" );
00430 }
00431 }
00432 }
00433 }
00434
00435
00436 c0 = 0;
00437 c1 = pc_width / 3;
00438 c2 = 2 * pc_width / 3;
00439 dTextHeight = 0.25 * ( pc_height - 7 * pc_textup );
00440 r0 = 0;
00441 r1 = 2 * pc_textup + (int)dTextHeight;
00442 r2 = 3 * pc_textup + (int)( 2.0 * dTextHeight );
00443 r3 = 5 * pc_textup + (int)( 3.0 * dTextHeight );
00444
00445 fprintf(fp,"1.0 setlinewidth\n");
00446
00447
00448 if ( minX == 0 )
00449 {
00450 x = 0;
00451 px = ax * x + bx;
00452 py = ay * mStartTask->ny + by;
00453 fprintf(fp, "%d %d %d %d BACKGROUND\n",
00454 px, px + pc_width, py, py + pc_height);
00455
00456 fprintf(fp, "%d %d %d %d OUTLINE\n",
00457 px, px + pc_width, py, py + pc_height);
00458
00459 fprintf(fp, "%d %d moveto ", px, py + r1 );
00460 fprintf(fp, "%d %d lineto ", px + pc_width, py + r1 );
00461 fprintf(fp, "stroke\n");
00462
00463 fprintf(fp, "%d %d moveto ", px, py + r3 );
00464 fprintf(fp, "%d %d lineto ", px + pc_width, py + r3 );
00465 fprintf(fp, "stroke\n");
00466
00467 fprintf(fp, "%d %d moveto ", px + c1, py );
00468 fprintf(fp, "%d %d lineto ", px + c1, py + r1 );
00469 fprintf(fp, "stroke\n");
00470
00471 fprintf(fp, "%d %d moveto ", px + c1, py + r3 );
00472 fprintf(fp, "%d %d lineto ", px + c1, py + pc_height );
00473 fprintf(fp, "stroke\n");
00474
00475 fprintf(fp, "%d %d moveto ", px + c2, py );
00476 fprintf(fp, "%d %d lineto ", px + c2, py + r1 );
00477 fprintf(fp, "stroke\n");
00478
00479 fprintf(fp, "%d %d moveto ", px + c2, py + r3 );
00480 fprintf(fp, "%d %d lineto ", px + c2, py + pc_height );
00481 fprintf(fp, "stroke\n");
00482
00483 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r2 + pc_textup );
00484 fprintf(fp, "(START) show\n");
00485
00486 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r3 + pc_textup );
00487 fprintf(fp, "(%s) show\n", project->sStartDay());
00488 }
00489
00490 for ( x = minX ; x <= maxX ; x++)
00491 {
00492 px = ax * x + bx;
00493 for ( cell = network_cols[x] ; cell != NULL ; cell = cell->next )
00494 {
00495 if ( cell->isSpace )
00496 continue;
00497
00498 py = ay * cell->task->ny + by;
00499
00500 fprintf(fp, "%d %d %d %d BACKGROUND\n",
00501 px, px + pc_width, py, py + pc_height);
00502
00503 fprintf(fp, "%d %d %d %d OUTLINE\n",
00504 px, px + pc_width, py, py + pc_height);
00505
00506 fprintf(fp, "%d %d moveto ", px, py + r1 );
00507 fprintf(fp, "%d %d lineto ", px + pc_width, py + r1 );
00508 fprintf(fp, "stroke\n");
00509
00510 fprintf(fp, "%d %d moveto ", px, py + r3 );
00511 fprintf(fp, "%d %d lineto ", px + pc_width, py + r3 );
00512 fprintf(fp, "stroke\n");
00513
00514 fprintf(fp, "%d %d moveto ", px + c1, py );
00515 fprintf(fp, "%d %d lineto ", px + c1, py + r1 );
00516 fprintf(fp, "stroke\n");
00517
00518 fprintf(fp, "%d %d moveto ", px + c1, py + r3 );
00519 fprintf(fp, "%d %d lineto ", px + c1, py + pc_height );
00520 fprintf(fp, "stroke\n");
00521
00522 fprintf(fp, "%d %d moveto ", px + c2, py );
00523 fprintf(fp, "%d %d lineto ", px + c2, py + r1 );
00524 fprintf(fp, "stroke\n");
00525
00526 fprintf(fp, "%d %d moveto ", px + c2, py + r3 );
00527 fprintf(fp, "%d %d lineto ", px + c2, py + pc_height );
00528 fprintf(fp, "stroke\n");
00529
00530 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r2 + pc_textup );
00531 if (task_ids)
00532 sprintf(buf, "%s %s", cell->task->id(), cell->task->name());
00533 else
00534 sprintf(buf, "%s", cell->task->name());
00535 fprintf(fp, "(%s) show\n", buf);
00536
00537 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r1 + pc_textup );
00538 fprintf(fp, "(%s) show\n", cell->task->assigned()->id());
00539
00540 fprintf(fp, "%d %d moveto ", px + c1 + pc_textin,
00541 py + r3 + pc_textup );
00542 sprintf(buf, "%10d", cell->task->fullduration());
00543 fprintf(fp, "(%s) show\n", buf);
00544
00545 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r3 + pc_textup );
00546 fprintf(fp, "(%s) show\n", project->sDays(cell->task->start()));
00547
00548 fprintf(fp, "%d %d moveto ", px + c2 + pc_textin, py + r3 + pc_textup );
00549 fprintf(fp, "(%s) show\n", project->sDays(cell->task->finish()));
00550
00551 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r0 + pc_textup );
00552 fprintf(fp, "(%s) show\n", project->sDays(cell->task->lstart()));
00553
00554 fprintf(fp, "%d %d moveto ", px + c1 + pc_textin,
00555 py + r0 + pc_textup );
00556 sprintf(buf, "%10d", cell->task->slack());
00557 fprintf(fp, "(%s) show\n", buf);
00558
00559 fprintf(fp, "%d %d moveto ", px + c2 + pc_textin, py + r0 + pc_textup );
00560 fprintf(fp, "(%s) show\n", project->sDays(cell->task->lfinish()));
00561 }
00562 }
00563
00564
00565 if ( maxX == numX - 1 )
00566 {
00567 x = numX - 1;
00568 px = ax * x + bx;
00569 py = ay * mFinishTask->ny + by;
00570 fprintf(fp, "%d %d %d %d BACKGROUND\n",
00571 px, px + pc_width, py, py + pc_height);
00572
00573 fprintf(fp, "%d %d %d %d OUTLINE\n",
00574 px, px + pc_width, py, py + pc_height);
00575
00576 fprintf(fp, "%d %d moveto ", px, py + r1 );
00577 fprintf(fp, "%d %d lineto ", px + pc_width, py + r1 );
00578 fprintf(fp, "stroke\n");
00579
00580 fprintf(fp, "%d %d moveto ", px, py + r3 );
00581 fprintf(fp, "%d %d lineto ", px + pc_width, py + r3 );
00582 fprintf(fp, "stroke\n");
00583
00584 fprintf(fp, "%d %d moveto ", px + c1, py );
00585 fprintf(fp, "%d %d lineto ", px + c1, py + r1 );
00586 fprintf(fp, "stroke\n");
00587
00588 fprintf(fp, "%d %d moveto ", px + c1, py + r3 );
00589 fprintf(fp, "%d %d lineto ", px + c1, py + pc_height );
00590 fprintf(fp, "stroke\n");
00591
00592 fprintf(fp, "%d %d moveto ", px + c2, py );
00593 fprintf(fp, "%d %d lineto ", px + c2, py + r1 );
00594 fprintf(fp, "stroke\n");
00595
00596 fprintf(fp, "%d %d moveto ", px + c2, py + r3 );
00597 fprintf(fp, "%d %d lineto ", px + c2, py + pc_height );
00598 fprintf(fp, "stroke\n");
00599
00600 fprintf(fp, "%d %d moveto ", px + c0 + pc_textin, py + r2 + pc_textup );
00601 fprintf(fp, "(FINISH) show\n");
00602
00603 fprintf(fp, "%d %d moveto ", px + c2 + pc_textin, py + r3 + pc_textup );
00604 fprintf(fp, "(%s) show\n", project->sFinishDay());
00605 }
00606
00607
00608 write_milestones(project, fp, ax, bx, ay, by);
00609
00610 fprintf(fp, "showpage\n");
00611 fclose(fp);
00612 }
00613
00614
00615 void Reporter::NetworkDiagram(Project *project,
00616 int start, int finish, const char *filename)
00617 {
00618 TASK *task;
00619
00620
00621 do
00622 {
00623 task = NULL;
00624 for ( Project::TPLCI pt = project->beginTaskList() ;
00625 pt != project->endTaskList() ;
00626 pt++ )
00627 if ( canAssignX(*pt) )
00628 {
00629 task = (*pt);
00630 break;
00631 }
00632
00633 if ( task != NULL )
00634 assignX(task);
00635 }
00636 while ( task != NULL );
00637
00638
00639
00640 for ( Project::TPLCI pt = project->beginTaskList() ;
00641 pt != project->endTaskList() ;
00642 pt++ )
00643 {
00644 if ( (*pt)->isVacation() )
00645 continue;
00646 if ( (*pt)->nx == -1 )
00647 Error("NetworkDiagram: task %s still has nx == -1",
00648 (*pt)->id());
00649 }
00650
00651
00652 assignY(project);
00653
00654
00655 constructStartFinish(project);
00656
00657
00658 write_chart(project, start, finish, filename);
00659
00660
00661
00662
00663 }
00664