2 * Project.cpp - TaskJuggler
4 * Copyright (c) 2001 by Chris Schlaeger <cs@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms version 2 of the GNU General Public License as
8 * published by the Free Software Foundation.
21 #define COL_DEFAULT "#fffadd"
22 #define COL_WEEKEND "#ffec80"
23 #define COL_BOOKED "#ffc0a3"
24 #define COL_HEADER "#a5c2ff"
25 #define COL_MILESTONE "#ff2a2a"
29 taskList.setAutoDelete(TRUE);
36 /* The 'closed' flag may be used for container classes to hide all
38 addAllowedFlag("closed");
39 // The 'hidden' flag may be used to hide the task in all reports.
40 addAllowedFlag("hidden");
42 htmlTaskReportStart = 0;
43 htmlTaskReportEnd = 0;
44 htmlResourceReport = "";
45 htmlResourceReportStart = 0;
46 htmlResourceReportEnd = 0;
50 Project::addTask(Task* t)
62 // Create hash to map task IDs to pointers.
63 for (Task* t = taskList.first(); t != 0; t = taskList.next())
65 idHash.insert(t->getId(), t);
68 // Create cross links from dependency lists.
69 for (Task* t = taskList.first(); t != 0; t = taskList.next())
75 TaskList sortedTasks(taskList);
76 sortedTasks.setSorting(TaskList::PrioDown);
79 const time_t scheduleGranularity = ONEHOUR;
80 for (int day = start; day < end; day += scheduleGranularity)
86 for (Task* t = sortedTasks.first(); t != 0; t = sortedTasks.next())
87 if (!t->schedule(day, scheduleGranularity))
92 if (unscheduledTasks() > 0)
94 fprintf(stderr, "Can't schedule some tasks. Giving up!\n");
103 Project::reportHTMLHeader(FILE* f)
105 fprintf(f, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n"
106 "<! Generated by TaskJuggler v"VERSION">"
109 "<title>Task Report</title>\n"
116 Project::reportHTMLFooter(FILE* f)
118 fprintf(f, "<br><font size=\"-2\">%s - TaskJuggler v"
119 VERSION"</font></body>\n"
120 "</html>\n", version.latin1());
125 Project::reportHTMLTaskList()
127 /* TODO: This is pretty much a quick hack. Using FILE is bad. latin1()
128 * does not work for non ASCII characters! */
129 if (htmlTaskReport == "")
132 if (htmlTaskReportStart == 0)
133 htmlTaskReportStart = start;
134 if (htmlTaskReportEnd == 0)
135 htmlTaskReportEnd = 0;
138 if ((f = fopen(htmlTaskReport, "w")) == NULL)
140 fprintf(stderr, "Cannot open report file %s!\n",
141 htmlTaskReport.latin1());
145 fprintf(f, "<table border=\"0\" cellpadding=\"1\">\n");
147 for (QStringList::Iterator it = htmlTaskReportColumns.begin();
148 it != htmlTaskReportColumns.end(); ++it )
151 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
152 "<h2>No.</h2></td>");
153 else if (*it == "taskId")
154 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
155 "<h2>Task ID</h2></td>");
156 else if (*it == "name")
157 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
158 "<h2>Task</h2></td>");
159 else if (*it == "start")
160 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
161 "<h2>Start</h2></td>");
162 else if (*it == "end")
163 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
164 "<h2>End</h2></td>");
165 else if (*it == "minStart")
166 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
167 "<h2>Min. Start</h2></td>");
168 else if (*it == "maxStart")
169 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
170 "<h2>Max. Start</h2></td>");
171 else if (*it == "resources")
172 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
173 "<h2>Resources</h2></td>");
174 else if (*it == "depends")
175 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
176 "<h2>Dependencies</h2></td>");
177 else if (*it == "follows")
178 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
179 "<h2>Following Tasks</h2></td>");
180 else if (*it == "note")
181 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
182 "<h2>Note</h2></td>");
183 else if (*it == "daily")
185 fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\"></td>");
186 htmlMonthHeader(f, htmlTaskReportStart, htmlTaskReportEnd);
190 fprintf(stderr, "Unknown Column '%s' for HTML Task Report\n",
197 for (QStringList::Iterator it = htmlTaskReportColumns.begin();
198 it != htmlTaskReportColumns.end(); ++it )
201 htmlDayHeader(f, htmlTaskReportStart, htmlTaskReportEnd);
203 fprintf(f, "</tr>\n");
207 idxDict.setAutoDelete(TRUE);
208 for (Task* t = taskList.first(); t != 0; t = taskList.next(), ++i)
209 idxDict.insert(t->getId(), new int(i));
212 for (Task* t = taskList.first(); t != 0; t = taskList.next(), ++i)
214 if (t->hasFlag("hidden"))
217 fprintf(f, "<tr valign=\"center\">");
218 for (QStringList::Iterator it = htmlTaskReportColumns.begin();
219 it != htmlTaskReportColumns.end(); ++it )
222 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
224 else if (*it == "taskId")
225 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\""
226 " nowrap>%s</td>", t->getId().latin1());
227 else if (*it == "name")
230 Task* tp = t->getParent();
232 for (indent = 0; tp != 0; ++indent)
234 spaces += " ";
235 tp = tp->getParent();
237 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\""
238 " nowrap>%s<font size=\"%c%d\">%s</font></td>\n",
239 spaces.latin1(), 2 - indent < 0 ? '-' : '+',
240 2 - indent < 0 ? -(2 - indent) : 2 - indent,
241 t->getName().latin1());
243 else if (*it == "start")
244 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\" %s>"
246 t->isStartOk() ? "" : "bgcolor=\"red\"",
247 t->getStartISO().latin1());
248 else if (*it == "end")
249 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\" %s>"
251 t->isEndOk() ? "" : "bgcolor=\"red\"",
252 t->getEndISO().latin1());
253 else if (*it == "minStart")
254 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
256 time2ISO(t->getMinStart()).latin1());
257 else if (*it == "maxStart")
258 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
260 time2ISO(t->getMaxStart()).latin1());
261 else if (*it == "resources")
263 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
264 "<font size=\"-2\">");
266 for (Resource* r = t->firstBookedResource(); r != 0;
267 r = t->nextBookedResource())
269 fprintf(f, "%s%s", first ? "" : ", ",
270 r->getName().latin1());
273 fprintf(f, "</font></td>\n");
275 else if (*it == "depends")
277 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
278 "<font size=\"-2\">");
280 for (Task* d = t->firstPrevious(); d != 0;
281 d = t->nextPrevious())
283 fprintf(f, "%s%d", first ? "" : ", ",
284 *(idxDict[d->getId()]));
287 fprintf(f, "</font></td>\n");
289 else if (*it == "follows")
291 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
292 "<font size=\"-2\">");
294 for (Task* d = t->firstFollower(); d != 0;
295 d = t->nextFollower())
297 fprintf(f, "%s%d", first ? "" : ", ",
298 *(idxDict[d->getId()]));
301 fprintf(f, "</font></td>\n");
303 else if (*it == "note")
305 fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
306 "<font size=\"-2\">%s</font></td>\n",
307 htmlFilter(t->getNote()).latin1());
309 else if (*it == "daily")
311 fprintf(f, "<td bgcolor=\""COL_HEADER"\"><font size=\"-4\">"
313 const int oneDay = 60 * 60 * 24;
314 for (time_t day = htmlTaskReportStart;
315 day < htmlTaskReportEnd; day += oneDay)
317 double load = t->getLoadOnDay(day);
318 QString bgCol = COL_DEFAULT;
319 if (t->isMilestone() && t->isActiveToday(day))
320 bgCol = COL_MILESTONE;
321 else if (isWeekend(day))
323 else if (t->isActiveToday(day))
327 "<td bgcolor=\"%s\"><font size=\"-3\">%3.1f</font></td>",
328 bgCol.latin1(), load);
330 fprintf(f, "<td bgcolor=\"%s\"></td>",
337 fprintf(f, "<tr>\n");
338 for (QStringList::Iterator it = htmlTaskReportColumns.begin();
339 it != htmlTaskReportColumns.end(); ++it )
343 fprintf(f, "<td bgcolor=\""COL_HEADER"\"><font size=\"-4\">"
344 "Actual</font></td>");
345 const int oneDay = 60 * 60 * 24;
346 for (time_t day = htmlTaskReportStart;
347 day < htmlTaskReportEnd; day += oneDay)
348 fprintf(f, "<td bgcolor=\"%s\"></td>",
349 isWeekend(day) ? COL_WEEKEND : COL_DEFAULT);
352 fprintf(f, "</tr>\n");
354 fprintf(f, "</table>");
362 Project::reportHTMLResourceList()
364 /* TODO: This is pretty much a quick hack. Using FILE is bad. latin1()
365 * does not work for non ASCII characters! */
366 if (htmlResourceReport == "")
369 if ((f = fopen(htmlResourceReport, "w")) == NULL)
371 fprintf(stderr, "Cannot open report file %s!\n",
372 htmlResourceReport.latin1());
376 fprintf(f, "<table border=\"1\" cellpadding=\"3\">\n");
378 fprintf(f, "<td rowspan=\"2\"></td>");
379 htmlMonthHeader(f, htmlResourceReportStart, htmlResourceReportEnd);
380 fprintf(f, "</tr>\n");
383 htmlDayHeader(f, htmlResourceReportStart, htmlResourceReportEnd);
384 fprintf(f, "</tr>\n");
386 const int oneDay = 60 * 60 * 24;
387 for (Resource* r = resourceList.first(); r != 0;
388 r = resourceList.next())
391 fprintf(f, "<td nowrap><b>%s</b></td>", r->getName().latin1());
392 for (time_t day = htmlResourceReportStart; day < htmlResourceReportEnd;
395 double load = r->getLoadOnDay(day);
398 s.sprintf("%3.1f", load);
399 fprintf(f, "<td %s>%s</td>",
400 isWeekend(day) ? "bgcolor=\""COL_WEEKEND"\"" : "",
403 fprintf(f, "</tr>\n");
405 for (Task* t = taskList.first(); t != 0; t = taskList.next())
406 if (r->isAssignedTo(t))
409 fprintf(f, "<td nowrap> <font size=\"-1\">%s</font></td>",
410 t->getName().latin1());
411 for (time_t day = htmlResourceReportStart;
412 day < htmlResourceReportEnd; day += oneDay)
414 double load = r->getLoadOnDay(day, t);
417 s.sprintf("%3.1f", load);
418 fprintf(f, "<td %s><font size=\"-1\">%s</font></td>",
419 isWeekend(day) ? "bgcolor=\""COL_WEEKEND"\"" : "",
422 fprintf(f, "</tr>\n");
426 fprintf(f, "</table>");
434 Project::htmlDayHeader(FILE* f, time_t s, time_t e)
436 const int oneDay = 60 * 60 * 24;
438 for (time_t day = s; day < e; day += oneDay)
440 int dom = dayOfMonth(day);
441 fprintf(f, "<td bgcolor=\"%s\"><font size=\"-2\">"
442 " %s%d</font></td>",
443 isWeekend(day) ? COL_WEEKEND : COL_HEADER,
444 dom < 10 ? " " : "", dom);
449 Project::htmlMonthHeader(FILE* f, time_t s, time_t e)
451 const int oneDay = 60 * 60 * 24;
453 for (time_t day = s; day < e; day += oneDay * daysLeftInMonth(day))
455 int left = daysLeftInMonth(day);
456 if (left > (e - day) / oneDay)
457 left = (e - day) / oneDay;
458 fprintf(f, "<td bgcolor=\""COL_HEADER"\" colspan=\"%d\" "
459 "align=\"center\"><font size=\"+2\"><b>%s</b></font></td>",
460 left, monthAndYear(day));
467 printf("ID Task Name Start End\n");
469 for (Task* t = taskList.first(); t != 0; t = taskList.next(), ++i)
471 printf("%2d. %-12s %10s %10s\n",
472 i, t->getName().latin1(),
473 t->getStartISO().latin1(), t->getEndISO().latin1());
477 resourceList.printText();
481 Project::unscheduledTasks()
484 for (Task* t = taskList.first(); t != 0; t = taskList.next())
485 if (!t->isScheduled())
492 Project::checkSchedule()
494 for (Task* t = taskList.first(); t != 0; t = taskList.next())
495 if (!t->scheduleOK())
502 Project::htmlFilter(const QString& s)
504 // TODO: All special characters must be html-ized.