OSDN Git Service

Removing redundant error checking related to booking declaration.
[tjqt4port/tj2qt4.git] / taskjuggler / XMLReport.cpp
1 /*
2  * XMLReport.cpp - TaskJuggler
3  *
4  * Copyright (c) 2002 by Chris Schlaeger <cs@kde.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of version 2 of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * $Id$
11  */
12
13 #include "XMLReport.h"
14
15 #include <zlib.h>
16 #include <unistd.h>
17
18 #include <qmap.h>
19
20 #include "tjlib-internal.h"
21 #include "Project.h"
22 #include "Scenario.h"
23 #include "Account.h"
24 #include "Resource.h"
25 #include "BookingList.h"
26 #include "Allocation.h"
27 #include "XMLReport.h"
28 #include "ExpressionTree.h"
29 #include "Operation.h"
30 #include "CustomAttributeDefinition.h"
31 #include "TextAttribute.h"
32 #include "ReferenceAttribute.h"
33
34 static QMap<QString, int> TaskAttributeDict;
35 typedef enum TADs {
36     TA_UNDEFINED = 0,
37     TA_COMPLETE,
38     TA_DEPENDS,
39     TA_DURATION,
40     TA_EFFORT,
41     TA_FLAGS,
42     TA_LENGTH,
43     TA_MAXEND,
44     TA_MAXSTART,
45     TA_MINEND,
46     TA_MINSTART,
47     TA_NOTE,
48     TA_PRIORITY,
49     TA_RESPONSIBLE,
50     TA_STATUS,
51     TA_STATUSNOTE,
52     TA_ACCOUNT
53 } TADs;
54
55 XMLReport::XMLReport(Project* p, const QString& f,
56                            const QString& df, int dl) :
57     Report(p, f, df, dl),
58     doc(0),
59     accountAttributes(),
60     taskAttributes()
61 {
62     if (TaskAttributeDict.empty())
63     {
64         TaskAttributeDict[KW("complete")] = TA_COMPLETE;
65         TaskAttributeDict[KW("depends")] = TA_DEPENDS;
66         TaskAttributeDict[KW("duration")] = TA_DURATION;
67         TaskAttributeDict[KW("effort")] = TA_EFFORT;
68         TaskAttributeDict[KW("flags")] = TA_FLAGS;
69         TaskAttributeDict[KW("length")] = TA_LENGTH;
70         TaskAttributeDict[KW("maxend")] = TA_MAXEND;
71         TaskAttributeDict[KW("maxstart")] = TA_MAXSTART;
72         TaskAttributeDict[KW("minend")] = TA_MINEND;
73         TaskAttributeDict[KW("minstart")] = TA_MINSTART;
74         TaskAttributeDict[KW("note")] = TA_NOTE;
75         TaskAttributeDict[KW("priority")] = TA_PRIORITY;
76         TaskAttributeDict[KW("responsible")] = TA_RESPONSIBLE;
77         TaskAttributeDict[KW("status")] = TA_STATUS;
78         TaskAttributeDict[KW("statusnote")] = TA_STATUSNOTE;
79         TaskAttributeDict[KW("account")] = TA_ACCOUNT;
80     }
81     // show all tasks
82     hideTask = new ExpressionTree(new Operation(0));
83     // show all resources
84     hideResource = new ExpressionTree(new Operation(0));
85     // show all accounts
86     hideAccount = new ExpressionTree(new Operation(0));
87
88     taskSortCriteria[0] = CoreAttributesList::TreeMode;
89     taskSortCriteria[1] = CoreAttributesList::StartUp;
90     taskSortCriteria[2] = CoreAttributesList::EndUp;
91     resourceSortCriteria[0] = CoreAttributesList::TreeMode;
92     resourceSortCriteria[1] = CoreAttributesList::IdUp;
93     accountSortCriteria[0] = CoreAttributesList::TreeMode;
94     accountSortCriteria[1] = CoreAttributesList::IdUp;
95
96     // All XML reports default to just showing the first scenario.
97     scenarios.append(0);
98 }
99
100 XMLReport::~XMLReport()
101 {
102     delete doc;
103 }
104
105 bool
106 XMLReport::generate()
107 {
108     if (!open())
109         return false;
110
111     doc = new QDomDocument
112         ("taskjuggler PUBLIC "
113          "\"-//The TaskJuggler Project//DTD TaskJuggler 2.0//EN\""
114          " \"http://www.taskjuggler.org/dtds/TaskJuggler-2.0.dtd\"");
115
116     doc->appendChild(doc->createProcessingInstruction
117                      ("xml", "version=\"1.0\" encoding=\"UTF-8\" "
118                       "standalone=\"no\""));
119
120     QDomElement tjEl = doc->createElement("taskjuggler");
121     doc->appendChild(tjEl);
122
123     if (timeStamp)
124     {
125         doc->appendChild(doc->createComment(
126             QString("This file has been generated by TaskJuggler ") +
127             VERSION + " at " + time2ISO(time(0)) + "."));
128         doc->appendChild(doc->createComment(
129             QString("For details about TaskJuggler see ") + TJURL));
130     }
131
132     TaskList filteredTaskList;
133     if (!filterTaskList(filteredTaskList, 0, hideTask, rollUpTask))
134         return false;
135     sortTaskList(filteredTaskList);
136
137     ResourceList filteredResourceList;
138     if (!filterResourceList(filteredResourceList, 0, hideResource,
139                             rollUpResource))
140         return false;
141     sortResourceList(filteredResourceList);
142
143     AccountList filteredAccountList;
144     if (!filterAccountList(filteredAccountList, AllAccounts, hideAccount,
145                            rollUpAccount))
146         return false;
147     sortAccountList(filteredAccountList);
148
149     if (!generateProjectProperty(&tjEl))
150         return false;
151     if (!generateGlobalVacationList(&tjEl))
152         return false;
153     if (!generateShiftList(&tjEl))
154         return false;
155     if (!generateResourceList(&tjEl, filteredResourceList, filteredTaskList))
156         return false;
157     if (!generateAccountList(&tjEl, filteredAccountList, filteredTaskList))
158         return false;
159     if (!generateTaskList(&tjEl, filteredTaskList, filteredResourceList))
160         return false;
161     if (!generateBookingList(&tjEl, filteredTaskList, filteredResourceList))
162        return false;
163
164     gzFile zf = gzdopen(dup(f.handle()), "wb");
165     if (!zf)
166     {
167         tjWarning(i18n("Cannot open compressed file %1 for writing.")
168                  .arg(fileName));
169         return false;
170     }
171     int bytes;
172     if ((bytes = gzputs(zf, static_cast<const char*>(doc->toCString()))) == 0)
173     {
174         tjWarning(i18n("Compression of %1 failed").arg(fileName));
175         return false;
176     }
177     int zError;
178     if ((zError = gzclose(zf)) != 0)
179     {
180         tjWarning(i18n("Closing of file %1 failed: %2").arg(fileName)
181                  .arg(gzerror(zf, &zError)));
182         return false;
183     }
184
185     return close();
186 }
187
188 bool
189 XMLReport::generateProjectProperty(QDomElement* n)
190 {
191     QDomElement el = doc->createElement("project");
192     n->appendChild(el);
193
194     genTextAttr(&el, "id", project->getId());
195     genTextAttr(&el, "name", project->getName());
196     genTextAttr(&el, "version", project->getVersion());
197     genDateElement(&el, "start", getStart());
198     genDateElement(&el, "end", getEnd() + 1);
199
200     // Generate custom attribute definitions
201     if (!generateCustomAttributeDeclaration
202         (&el, "task", project->getTaskAttributeDict()))
203         return false;
204     if (!generateCustomAttributeDeclaration
205         (&el, "resource", project->getResourceAttributeDict()))
206         return false;
207     if (!generateCustomAttributeDeclaration
208         (&el, "account", project->getAccountAttributeDict()))
209         return false;
210
211     // Generate date/time related settings
212     genLongAttr(&el, "weekStartMonday",
213                    project->getWeekStartsMonday() ? 1 : 0);
214     if (!project->getTimeZone().isEmpty())
215         genTextAttr(&el, "timezone", project->getTimeZone());
216     genDoubleAttr(&el, "dailyWorkingHours",
217                      project->getDailyWorkingHours());
218     genDoubleAttr(&el, "yearlyWorkingDays",
219                      project->getYearlyWorkingDays());
220     genLongAttr(&el, "timingResolution", project->getScheduleGranularity());
221     genDateElement(&el, "now", project->getNow());
222     genTextAttr(&el, "timeFormat", project->getTimeFormat());
223     genTextAttr(&el, "shortTimeFormat", project->getShortTimeFormat());
224
225     // Generate currency settings
226     RealFormat rf = project->getCurrencyFormat();
227     QDomElement cfEl = doc->createElement("currencyFormat");
228     el.appendChild(cfEl);
229     genTextAttr(&cfEl, "signPrefix", rf.getSignPrefix());
230     genTextAttr(&cfEl, "signSuffix", rf.getSignSuffix());
231     genTextAttr(&cfEl, "thousandSep", rf.getThousandSep());
232     genTextAttr(&cfEl, "fractionSep", rf.getFractionSep());
233     genLongAttr(&cfEl, "fracDigits", rf.getFracDigits());
234     if (!project->getCurrency().isEmpty())
235         genTextAttr(&el, "currency", project->getCurrency());
236
237     generateWorkingHours(&el, project->getWorkingHours());
238
239     generateScenario(&el, project->getScenario(0));
240
241     return true;
242 }
243
244 bool
245 XMLReport::generateCustomAttributeDeclaration(QDomElement* parentEl,
246     const QString& propertyName,
247     QDictIterator<CustomAttributeDefinition> it)
248 {
249     if (!it.current())
250         return true;
251     QDomElement el = doc->createElement("extend");
252     parentEl->appendChild(el);
253     genTextAttr(&el, "property", propertyName);
254
255     for ( ; it.current(); ++it)
256     {
257         QString exElType;
258         switch (it.current()->getType())
259         {
260             case CAT_Text:
261                 exElType = "text";
262                 break;
263             case CAT_Reference:
264                 exElType = "reference";
265                 break;
266             default:
267                 qFatal("XMLReport::generateCustomAttributeDeclaration: "
268                        "Unknown CAT %d", it.current()->getType());
269                 return false;
270         }
271         QDomElement exEl = doc->createElement("extendAttributeDefinition");
272         el.appendChild(exEl);
273         genTextAttr(&exEl, "id", it.currentKey());
274         genTextAttr(&exEl, "name", it.current()->getName());
275         genTextAttr(&exEl, "type", exElType);
276     }
277
278     return true;
279 }
280
281 bool
282 XMLReport::generateScenario(QDomElement* parentEl, Scenario* scenario)
283 {
284     QDomElement el = doc->createElement("scenario");
285     parentEl->appendChild(el);
286
287     genTextAttr(&el, "id", scenario->getId());
288     genTextAttr(&el, "name", scenario->getName());
289     genTextAttr(&el, "disabled", scenario->getEnabled() ? "0" : "1");
290     genTextAttr(&el, "projectionMode",
291                 scenario->getProjectionMode() ? "1" : "0");
292
293     for (ScenarioListIterator sci(scenario->getSubListIterator());
294          *sci != 0; ++sci)
295         generateScenario(&el, *sci);
296
297     return true;
298 }
299
300 bool
301 XMLReport::generateGlobalVacationList(QDomElement* parentNode)
302 {
303     VacationList::Iterator vli(project->getVacationListIterator());
304
305     if (*vli != 0)
306     {
307         QDomElement el = doc->createElement("vacationList");
308         parentNode->appendChild(el);
309
310         for ( ; *vli != 0; ++vli)
311         {
312             QDomElement vEl = doc->createElement("vacation");
313             el.appendChild(vEl);
314
315             genDateElement(&vEl, "start", (*vli)->getStart());
316             genDateElement(&vEl, "end", (*vli)->getEnd() + 1);
317             genTextAttr(&vEl, "name", (*vli)->getName());
318         }
319     }
320
321     return true;
322 }
323
324 bool
325 XMLReport::generateShiftList(QDomElement* parentNode)
326 {
327     QDomElement el = doc->createElement("shiftList");
328     parentNode->appendChild(el);
329
330     for (ShiftListIterator sli(project->getShiftListIterator());
331          *sli != 0; ++sli)
332     {
333         if ((*sli)->getParent() == 0)
334             if (!generateShift(&el, *sli))
335                 return false;
336     }
337
338     return true;
339 }
340
341 bool
342 XMLReport::generateShift(QDomElement* parentEl, const Shift* shift)
343 {
344     QDomElement el = doc->createElement("shift");
345     parentEl->appendChild(el);
346
347     genTextAttr(&el, "id", shift->getId());
348     genTextAttr(&el, "name", shift->getName());
349     generateWorkingHours(&el, shift->getWorkingHours());
350
351     for (ShiftListIterator sli(shift->getSubListIterator()); *sli; ++sli)
352         if (!generateShift(&el, *sli))
353             return false;
354
355     return true;
356 }
357
358 bool
359 XMLReport::generateWorkingHours(QDomElement* parentEl,
360                                 const QPtrList<Interval>* const* wh)
361 {
362     QDomElement el = doc->createElement("workingHours");
363     parentEl->appendChild(el);
364
365     for (int i = 0; i < 7; ++i)
366     {
367         if (wh[i]->isEmpty())
368             continue;
369
370         QDomElement dayEl = doc->createElement("weekdayWorkingHours");
371         genTextAttr(&dayEl, "weekday", QString().sprintf("%d", i));
372         el.appendChild(dayEl);
373         QPtrListIterator<Interval> it(*wh[i]);
374         for ( ; *it; ++it)
375         {
376             QDomElement ivEl = doc->createElement("timeInterval");
377             dayEl.appendChild(ivEl);
378             genTimeElement(&ivEl, "start", (*it)->getStart());
379             genTimeElement(&ivEl, "end", (*it)->getEnd() + 1);
380         }
381     }
382
383     return true;
384 }
385
386 bool
387 XMLReport::generateResourceList(QDomElement* parentNode,
388                                 ResourceList& filteredResourceList,
389                                 TaskList& filteredTaskList)
390 {
391     QDomElement el = doc->createElement("resourceList");
392     parentNode->appendChild(el);
393
394     for (ResourceListIterator rli(filteredResourceList); *rli != 0; ++rli)
395         if ((*rli)->getParent() == 0)
396             if (!generateResource(&el, filteredResourceList,
397                                   filteredTaskList, *rli))
398                 return false;
399
400     return true;
401 }
402
403 bool
404 XMLReport::generateResource(QDomElement* parentEl,
405                             ResourceList& filteredResourceList,
406                             TaskList& filteredTaskList,
407                             const Resource* resource)
408 {
409     QDomElement el = doc->createElement("resource");
410     parentEl->appendChild(el);
411
412     genTextAttr(&el, "id", resource->getId());
413     genTextAttr(&el, "name", resource->getName());
414
415     QStringList fl = resource->getFlagList();
416     for (QStringList::Iterator jt = fl.begin(); jt != fl.end(); ++jt)
417         genTextElement(&el, "flag", *jt);
418
419     for (ResourceListIterator srli(resource->getSubListIterator());
420          *srli != 0; ++srli)
421     {
422         if (filteredResourceList.findRef(*srli) >= 0)
423         {
424             if (!generateResource(&el, filteredResourceList, filteredTaskList,
425                                   *srli))
426                 return false;
427         }
428     }
429
430     QPtrListIterator<Interval> vli(resource->getVacationListIterator());
431     if (*vli != 0)
432     {
433         QDomElement vlEl = doc->createElement("vacationList");
434         el.appendChild(vlEl);
435         for ( ; *vli != 0; ++vli)
436         {
437             QDomElement vEl = doc->createElement("vacation");
438             vlEl.appendChild(vEl);
439             genDateElement(&vEl, "start", (*vli)->getStart());
440             genDateElement(&vEl, "end", (*vli)->getEnd() + 1);
441         }
442     }
443
444     generateWorkingHours(&el, resource->getWorkingHours());
445     for (ShiftSelectionList::Iterator sli(*resource->getShiftList()); *sli;
446          ++sli)
447     {
448         QDomElement sSel = doc->createElement("shiftSelection");
449         el.appendChild(sSel);
450
451         genTextAttr(&sSel, "shiftId", (*sli)->getShift()->getId());
452         genDateElement(&sSel, "start", (*sli)->getPeriod().getStart());
453         genDateElement(&sSel, "end", (*sli)->getPeriod().getEnd() + 1);
454     }
455
456     return true;
457 }
458
459 bool
460 XMLReport::generateAccountList(QDomElement* parentNode,
461                                AccountList& filteredAccountList,
462                                TaskList& filteredTaskList)
463 {
464     QDomElement el = doc->createElement("accountList");
465     parentNode->appendChild(el);
466
467     for (AccountListIterator ali(filteredAccountList); *ali != 0; ++ali)
468     {
469         if ((*ali)->getParent() == 0)
470             if (!generateAccount(&el, filteredAccountList,
471                                  filteredTaskList, *ali))
472                 return false;
473     }
474     return true;
475 }
476
477 bool
478 XMLReport::generateAccount(QDomElement* parentEl,
479                            AccountList& filteredAccountList,
480                            TaskList& filteredTaskList,
481                            const Account* account)
482 {
483     QDomElement el = doc->createElement("account");
484     parentEl->appendChild(el);
485
486     genTextAttr(&el, "id", account->getId());
487     genTextAttr(&el, "name", account->getName());
488
489     switch (account->getAcctType())
490     {
491     case Cost:
492         genTextAttr(&el, "type", "cost");
493         break;
494     case Revenue:
495         genTextAttr(&el, "type", "revenue");
496         break;
497     default:
498         qFatal("XMLReport::generateAccount: Unknown AccountType %d",
499                account->getAcctType());
500         return false;
501     }
502
503     for (QStringList::Iterator it = accountAttributes.begin();
504          it != accountAttributes.end(); ++it)
505     {
506         if (account->getCustomAttribute(*it))
507             generateCustomAttributeValue(&el, *it, account);
508     }
509
510     for (AccountListIterator srli(account->getSubListIterator());
511          *srli != 0; ++srli)
512     {
513         if (filteredAccountList.findRef(*srli) >= 0)
514         {
515             if (!generateAccount(&el, filteredAccountList, filteredTaskList,
516                                  *srli))
517                 return false;
518         }
519     }
520     return true;
521 }
522
523 bool
524 XMLReport::generateTaskList(QDomElement* parentNode, TaskList& filteredTaskList,
525                             ResourceList&)
526 {
527     QDomElement el = doc->createElement("taskList");
528     parentNode->appendChild(el);
529
530     for (TaskListIterator tli(filteredTaskList); *tli != 0; ++tli)
531         if ((*tli)->getParent() == 0 ||
532             (*tli)->getParent()->getId() + "." == taskRoot)
533             if (!generateTask(&el, filteredTaskList, *tli))
534                 return false;
535
536     return true;
537 }
538
539 bool
540 XMLReport::generateTask(QDomElement* parentEl, TaskList& filteredTaskList,
541                         const Task* task)
542 {
543     QDomElement el = doc->createElement("task");
544     parentEl->appendChild(el);
545
546     QString taskId = task->getId();
547     if (!taskRoot.isEmpty())
548         taskId = stripTaskRoot(taskId);
549     genTextAttr(&el, "id", taskId);
550     genTextAttr(&el, "name", task->getName());
551     genTextAttr(&el, "projectId", task->getProjectId());
552
553     for (QStringList::Iterator it = taskAttributes.begin();
554          it != taskAttributes.end(); ++it)
555     {
556         if (!TaskAttributeDict.contains(*it))
557         {
558             if (task->getCustomAttribute(*it))
559                 generateCustomAttributeValue(&el, *it, task);
560             continue;
561         }
562         switch (TaskAttributeDict[*it])
563         {
564             case TA_FLAGS:
565                 {
566                     QStringList fl = task->getFlagList();
567                     for (QStringList::Iterator jt = fl.begin();
568                          jt != fl.end(); ++jt)
569                     {
570                         genTextElement(&el, "flag", *jt);
571                     }
572                     break;
573                 }
574             case TA_NOTE:
575                 if (!task->getNote().isEmpty())
576                     genTextElement(&el, "note", task->getNote());
577                 break;
578             case TA_PRIORITY:
579                 genLongAttr(&el, "priority", task->getPriority());
580                 break;
581             case TA_EFFORT:
582             case TA_LENGTH:
583             case TA_DURATION:
584             case TA_MINSTART:
585             case TA_MAXSTART:
586             case TA_MINEND:
587             case TA_MAXEND:
588             case TA_COMPLETE:
589             case TA_STATUS:
590             case TA_STATUSNOTE:
591                 // handled further down as scenario specific value.
592                 break;
593             case TA_RESPONSIBLE:
594                 if (task->getResponsible())
595                     genTextAttr(&el, "responsible",
596                                 task->getResponsible()->getId());
597                 break;
598             case TA_DEPENDS:
599                 generateDepList(&el, filteredTaskList, task,
600                                 task->getDependsIterator(), true);
601                 generateDepList(&el, filteredTaskList, task,
602                                 task->getPrecedesIterator(), false);
603                 break;
604             case TA_ACCOUNT:
605                 if (task->getAccount())
606                     genTextAttr(&el, "account",
607                                 task->getAccount()->getId());
608                 break;
609             default:
610                 qDebug("XMLReport::generateTask(): "
611                        "Unknown task attribute %s", (*it).latin1());
612                 return false;
613         }
614
615     }
616
617     /* If a container task has sub tasks that are exported as well, we do
618      * not export start/end date for those container tasks. */
619     bool taskHasNoSubTasks = true;
620     for (TaskListIterator stli(task->getSubListIterator());
621          *stli != 0; ++stli)
622     {
623         if (filteredTaskList.findRef(*stli) >= 0)
624         {
625             taskHasNoSubTasks = false;
626             if (!generateTask(&el, filteredTaskList, *stli))
627                 return false;
628         }
629     }
630
631     for (QValueListIterator<int> it = scenarios.begin();
632          it != scenarios.end(); ++it)
633     {
634         QDomElement scEl = doc->createElement("taskScenario");
635         el.appendChild(scEl);
636         genTextAttr(&scEl, "scenarioId", project->getScenarioId(*it));
637
638         if (task->getStart(*it))
639             genDateElement(&scEl, "start", task->getStart(*it));
640         if (task->getEnd(*it) && !task->isMilestone())
641             genDateElement(&scEl, "end", task->getEnd(*it) + 1);
642         genLongAttr(&scEl, "criticalpath", task->isOnCriticalPath(*it) ? 1 : 0);
643         genLongAttr(&scEl, "scheduled", task->getScheduled(*it) ? 1 : 0);
644
645         for (QStringList::Iterator atIt = taskAttributes.begin();
646              atIt != taskAttributes.end(); ++atIt)
647         {
648             if (!TaskAttributeDict.contains(*atIt))
649                 continue;
650             switch (TaskAttributeDict[*atIt])
651             {
652                 case TA_EFFORT:
653                     if (task->getEffort(*it) != 0 &&
654                         (task->getStart(*it) == 0 || task->getEnd(*it) == 0))
655                         genDoubleAttr(&scEl, "effort", task->getEffort(*it));
656                     break;
657                 case TA_LENGTH:
658                     if (task->getLength(*it) != 0 &&
659                         (task->getStart(*it) == 0 || task->getEnd(*it) == 0))
660                         genDoubleAttr(&scEl, "length", task->getLength(*it));
661                     break;
662                 case TA_DURATION:
663                     if (task->getDuration(*it) != 0 &&
664                         (task->getStart(*it) == 0 || task->getEnd(*it) == 0))
665                         genDoubleAttr(&scEl, "duration",
666                                     task->getDuration(*it));
667                     break;
668                 case TA_MINSTART:
669                     if (task->getMinStart(*it) != 0)
670                         genDateElement(&scEl, "minStart",
671                                        task->getMinStart(*it));
672                     break;
673                 case TA_MAXSTART:
674                     if (task->getMaxStart(*it) != 0)
675                         genDateElement(&scEl, "maxStart",
676                                        task->getMaxStart(*it));
677                     break;
678                 case TA_MINEND:
679                     if (task->getMinEnd(*it) != 0)
680                         genDateElement(&scEl, "minEnd",
681                                        task->getMinEnd(*it) + 1);
682                     break;
683                 case TA_MAXEND:
684                     if (task->getMaxEnd(*it) != 0)
685                         genDateElement(&scEl, "maxEnd",
686                                        task->getMaxEnd(*it) + 1);
687                     break;
688                 case TA_COMPLETE:
689                     genDoubleAttr(&scEl, "complete", task->getComplete(*it));
690                     break;
691                 case TA_STATUS:
692                     if (task->getStatus(*it) > 0)
693                         genLongAttr(&scEl, "status", task->getStatus(*it));
694                     break;
695                 case TA_STATUSNOTE:
696                     if (!task->getStatusNote(*it).isEmpty())
697                         genTextElement(&scEl, "statusNote",
698                                        task->getStatusNote(*it));
699                     break;
700             }
701         }
702     }
703
704     genLongAttr(&el, "milestone", task->isMilestone() ? 1 : 0);
705     genLongAttr(&el, "asapScheduling",
706                 task->getScheduling() == Task::ASAP ? 1 : 0);
707
708     generateAllocate(&el, task);
709
710     return true;
711 }
712
713 bool
714 XMLReport::generateDepList(QDomElement* parentEl, TaskList& filteredTaskList,
715                            const Task* task,
716                            QPtrListIterator<TaskDependency> depIt,
717                            bool prev)
718 {
719     for ( ; *depIt != 0; ++depIt)
720     {
721         /* Save current list item since findRef() modifies
722          * it. Remember, we are still iterating the list. */
723         CoreAttributes* curr = filteredTaskList.current();
724         if (filteredTaskList.findRef((*depIt)->getTaskRef()) > -1 &&
725             !(task->getParent() != 0 &&
726               (prev ? task->getParent()->hasPrevious((*depIt)->getTaskRef()) :
727                task->getParent()->hasFollower((*depIt)->getTaskRef()))))
728         {
729             QDomElement te= doc->createElement(prev ? "depends" : "precedes");
730             /* Putting the task ID as PCDATA in the depends/precedes element
731              * was a mistake. We now store this information as 'task'
732              * attribute. The PCDATA is now deprecated and should no longer be
733              * used. It will be removed at some point with future versions of
734              * the software. */
735             te.appendChild(doc->createTextNode
736                            (stripTaskRoot(((*depIt)->getTaskRef())->getId())));
737             parentEl->appendChild(te);
738
739             genTextAttr(&te, "task",
740                         stripTaskRoot((*depIt)->getTaskRef()->getId()));
741
742             for (int sc = 0; sc < project->getMaxScenarios(); ++sc)
743                 if ((*depIt)->getGapDuration(sc) != 0 ||
744                     (*depIt)->getGapLength(sc) != 0)
745                 {
746                     QDomElement dgs = doc->createElement
747                         ("dependencyGapScenario");
748                     te.appendChild(dgs);
749                     genTextAttr(&dgs, "scenarioId",
750                                 project->getScenarioId(sc));
751                     if ((*depIt)->getGapDuration(sc) != 0)
752                         genLongAttr(&dgs, "gapDuration",
753                                     (*depIt)->getGapDuration(sc));
754                     if ((*depIt)->getGapLength(sc) != 0)
755                         genLongAttr(&dgs, "gapLength",
756                                     (*depIt)->getGapLength(sc));
757                 }
758         }
759         /* Restore current list item to continue
760          * iteration. */
761         filteredTaskList.findRef(curr);
762     }
763
764     return true;
765 }
766
767 bool
768 XMLReport::generateCustomAttributeValue(QDomElement* parentEl,
769                                         const QString& id,
770                                         const CoreAttributes* property)
771 {
772     QDomElement el = doc->createElement("customAttribute");
773     parentEl->appendChild(el);
774
775     genTextAttr(&el, "id", id);
776
777     const CustomAttribute* ca = property->getCustomAttribute(id);
778     switch (ca->getType())
779     {
780         case CAT_Text:
781         {
782             QDomElement cEl = doc->createElement("textAttribute");
783             el.appendChild(cEl);
784
785             genTextAttr(&cEl, "text", static_cast<const TextAttribute*>(ca)->getText());
786             break;
787         }
788         case CAT_Reference:
789         {
790             QDomElement cEl = doc->createElement("referenceAttribute");
791             el.appendChild(cEl);
792
793             const ReferenceAttribute* a =
794                 static_cast<const ReferenceAttribute*>(ca);
795             genTextAttr(&cEl, "url", a->getURL());
796             genTextAttr(&cEl, "label", a->getLabel());
797             break;
798         }
799         default:
800             qFatal("XMLReport::"
801                    "generateCustomAttributeValue: "
802                    "Unknown CA Type %d",
803                    ca->getType());
804     }
805
806     return true;
807 }
808
809 bool
810 XMLReport::generateAllocate(QDomElement* parentEl, const Task* t)
811 {
812     for (QPtrListIterator<Allocation> ai = t->getAllocationIterator();
813          *ai; ++ai)
814     {
815         QDomElement el = doc->createElement("allocate");
816         parentEl->appendChild(el);
817
818         for (QPtrListIterator<Resource> ri = (*ai)->getCandidatesIterator();
819              ri != 0; ++ri)
820         {
821             QDomElement aEl = doc->createElement("candidate");
822             el.appendChild(aEl);
823             genTextAttr(&aEl, "resourceId", (*ri)->getId());
824         }
825     }
826
827     return true;
828 }
829
830 bool
831 XMLReport::generateBookingList(QDomElement* parentEl,
832                                TaskList& filteredTaskList,
833                                ResourceList& filteredResourceList)
834 {
835     QDomElement el = doc->createElement("bookingList");
836     parentEl->appendChild(el);
837
838     for (ResourceListIterator rli(filteredResourceList); *rli != 0; ++rli)
839     {
840         for (QValueListIterator<int> sit = scenarios.begin();
841              sit != scenarios.end(); ++sit)
842         {
843             QDomElement scEl = doc->createElement("resourceBooking");
844             el.appendChild(scEl);
845             genTextAttr(&scEl, "resourceId", (*rli)->getId());
846             genTextAttr(&scEl, "scenarioId", project->getScenarioId(*sit));
847
848             BookingList bl = (*rli)->getJobs(*sit);
849             bl.setAutoDelete(true);
850             if (bl.isEmpty())
851                 continue;
852
853             for (BookingList::Iterator bli(bl); *bli != 0; ++bli)
854             {
855                 if (filteredTaskList.findRef((*bli)->getTask()) >= 0)
856                 {
857                     QDomElement bEl = doc->createElement("booking");
858                     scEl.appendChild(bEl);
859
860                     genDateElement(&bEl, "start", (*bli)->getStart());
861                     genDateElement(&bEl, "end", (*bli)->getEnd() + 1);
862                     genTextAttr(&bEl, "taskId",
863                                 stripTaskRoot((*bli)->getTask()->getId()));
864                 }
865             }
866         }
867     }
868     return true;
869 }
870
871 bool
872 XMLReport::addAccountAttribute(const QString& aa)
873 {
874     if (aa == KW("all"))
875     {
876         for (QDictIterator<CustomAttributeDefinition>
877              it(project->getAccountAttributeDict()); *it; ++it)
878         {
879             accountAttributes.append(it.currentKey());
880         }
881
882         return true;
883     }
884
885     /* Make sure the 'ta' is a valid attribute name and that we don't
886      * insert it twice into the list. Trying to insert it twice it not an
887      * error though. */
888     if (project->getAccountAttribute(aa) == 0)
889         return false;
890
891     if (accountAttributes.findIndex(aa) >= 0)
892         return true;
893     accountAttributes.append(aa);
894     return true;
895 }
896
897 bool
898 XMLReport::addTaskAttribute(const QString& ta)
899 {
900     if (ta == KW("all"))
901     {
902         QMap<QString, int>::ConstIterator it;
903         for (it = TaskAttributeDict.begin(); it != TaskAttributeDict.end();
904              ++it)
905         {
906             if (taskAttributes.findIndex(it.key()) < 0)
907                 taskAttributes.append(it.key());
908         }
909         for (QDictIterator<CustomAttributeDefinition>
910              it(project->getTaskAttributeDict()); *it; ++it)
911             taskAttributes.append(it.currentKey());
912
913         return true;
914     }
915
916     /* Make sure the 'ta' is a valid attribute name and that we don't
917      * insert it twice into the list. Trying to insert it twice it not an
918      * error though. */
919     if (TaskAttributeDict.find(ta) == TaskAttributeDict.end() &&
920         project->getTaskAttribute(ta) == 0)
921         return false;
922
923     if (taskAttributes.findIndex(ta) >= 0)
924         return true;
925     taskAttributes.append(ta);
926     return true;
927 }
928
929 void
930 XMLReport::genTextAttr(QDomElement* parentEl, const QString& name,
931                        const QString& text)
932 {
933    QDomAttr at = doc->createAttribute(name);
934    at.setValue(text);
935    parentEl->setAttributeNode(at);
936 }
937
938 void
939 XMLReport::genDoubleAttr(QDomElement* parentEl, const QString& name,
940                          double val)
941 {
942    QDomAttr at = doc->createAttribute(name);
943    at.setValue(QString::number(val));
944    parentEl->setAttributeNode(at);
945 }
946
947 void
948 XMLReport::genLongAttr(QDomElement* parentEl, const QString& name, long val)
949 {
950    QDomAttr at = doc->createAttribute(name);
951    at.setValue(QString::number(val));
952    parentEl->setAttributeNode(at);
953 }
954
955 void
956 XMLReport::genTextElement(QDomElement* parentEl, const QString& name,
957                           const QString& text)
958 {
959     QDomElement el = doc->createElement(name);
960     el.appendChild(doc->createTextNode(text));
961     parentEl->appendChild(el);
962 }
963
964 void
965 XMLReport::genDateElement(QDomElement* parentEl, const QString& name,
966                           time_t val)
967 {
968    QDomElement el = doc->createElement(name);
969    parentEl->appendChild(el);
970    QDomText tEl = doc->createTextNode(QString::number(val));
971    el.appendChild(tEl);
972
973    QDomAttr at = doc->createAttribute("humanReadable");
974    at.setValue(time2user(val, timeFormat));
975    el.setAttributeNode(at);
976
977    parentEl->appendChild(el);
978 }
979
980 void
981 XMLReport::genTimeElement(QDomElement* parentEl, const QString& name,
982                           time_t val)
983 {
984    QDomElement el = doc->createElement(name);
985    parentEl->appendChild(el);
986    QDomText tEl = doc->createTextNode(QString::number(val));
987    el.appendChild(tEl);
988
989    QDomAttr at = doc->createAttribute("humanReadable");
990    at.setValue(time2user(val, shortTimeFormat, false));
991    el.setAttributeNode(at);
992
993    parentEl->appendChild(el);
994 }
995