OSDN Git Service

adjust integer's signedness
[tjqt4port/tj2qt4.git] / taskjuggler / XMLFile.cpp
1 /*
2  * XMLFile.cpp - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
5  * by Chris Schlaeger <cs@kde.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * $Id$
12  */
13
14 #include "XMLFile.h"
15
16 #include <unistd.h>
17 #include <zlib.h>
18
19 #include <q3textstream.h>
20 //Added by qt3to4:
21 #include <Q3PtrList>
22
23 #include "tjlib-internal.h"
24 #include "ParserNode.h"
25 #include "ParserTreeContext.h"
26 #include "Project.h"
27 #include "Allocation.h"
28 #include "Booking.h"
29 #include "CustomAttributeDefinition.h"
30 #include "ReferenceAttribute.h"
31 #include "TextAttribute.h"
32
33 ParserNode* XMLFile::parserRootNode = 0;
34
35 XMLFile::XMLFile(Project* p) :
36     masterFile(),
37     project(p),
38     doc()
39 {
40     if (!parserRootNode)
41         createParseTree();
42 }
43
44 XMLFile::~XMLFile()
45 {
46     delete doc;
47 }
48
49 void
50 XMLFile::createParseTree()
51 {
52     /* Build the tree that describes how we expect the DOM tree to look like.
53      * Each node of the tree can have an arbitrary number of elements. Each
54      * element may then again have a node, when it has sub-elements. The
55      * structure of the tree built here very closely resembles the
56      * taskjuggler.dtd. */
57     parserRootNode = new ParserNode();
58     ParserElement* pe =
59         new ParserElement("taskjuggler", &XMLFile::doTaskJuggler,
60                           parserRootNode);
61     ParserNode* taskjugglerNode = new ParserNode(pe);
62     {
63         // Project Element
64         pe = new ParserElement("project", &XMLFile::doProject, taskjugglerNode);
65         ParserNode* projectNode = new ParserNode(pe);
66         {
67             new ParserElement("start", &XMLFile::doProjectStart, projectNode);
68             new ParserElement("end", &XMLFile::doProjectEnd, projectNode);
69             new ParserElement("now", &XMLFile::doProjectNow, projectNode);
70             pe = new ParserElement("extend", &XMLFile::doExtend, projectNode);
71             ParserNode* extendNode = new ParserNode(pe);
72             {
73                 new ParserElement("extendAttributeDefinition",
74                                   &XMLFile::doExtendAttribute,
75                                   extendNode);
76             }
77             new ParserElement("currencyFormat", &XMLFile::doCurrencyFormat,
78                               projectNode);
79             pe = new ParserElement("workingHours", 0, projectNode);
80             createSubTreeWorkingHours
81                 (&XMLFile::doProjectWeekdayWorkingHours, pe,
82                  &XMLFile::doProjectWeekdayWorkingHoursPost);
83             pe = new ParserElement("scenario", &XMLFile::doScenario,
84                                    projectNode);
85             ParserNode* scenarioNode = new ParserNode(pe);
86             {
87                 scenarioNode->add(pe, "scenario");
88             }
89         }
90
91         // vacationlist element
92         createSubTreeVacationList(&XMLFile::doProjectVacation,
93                                   taskjugglerNode);
94
95         // shiftList element
96         pe = new ParserElement("shiftList", &XMLFile::doShiftList,
97                                taskjugglerNode);
98         ParserNode* shiftListNode = new ParserNode(pe);
99         {
100             pe = new ParserElement("shift", &XMLFile::doShift,
101                                    shiftListNode);
102             ParserNode* shiftNode = new ParserNode(pe);
103             {
104                 shiftNode->add(pe, "shift");    // recursive link
105                 pe = new ParserElement("workingHours", 0, shiftNode);
106                 createSubTreeWorkingHours
107                     (&XMLFile::doShiftWeekdayWorkingHours, pe,
108                      &XMLFile::doShiftWeekdayWorkingHoursPost);
109             }
110         }
111
112         // resourceList element
113         pe = new ParserElement("resourceList", &XMLFile::doResourceList,
114                                taskjugglerNode);
115         ParserNode* resourceListNode = new ParserNode(pe);
116         {
117             pe = new ParserElement("resource", &XMLFile::doResource,
118                                    resourceListNode);
119             ParserNode* resourceNode = new ParserNode(pe);
120             {
121                 resourceNode->add(pe, "resource");  // recursive link
122                 new ParserElement("flag", &XMLFile::doFlag, resourceNode);
123                 pe = new ParserElement("workingHours", 0, resourceNode);
124                 createSubTreeWorkingHours
125                     (&XMLFile::doResourceWeekdayWorkingHours, pe,
126                      &XMLFile::doResourceWeekdayWorkingHoursPost);
127                 createSubTreeVacationList(&XMLFile::doResourceVacation,
128                                           resourceNode);
129                 createSubTreeTimeInterval("shiftSelection",
130                                           &XMLFile::doShiftSelection,
131                                           resourceNode);
132                 createSubTreeCustomAttribute(resourceNode);
133             }
134         }
135
136         // accountList element
137         pe = new ParserElement("accountList", &XMLFile::doAccountList,
138                                taskjugglerNode);
139         ParserNode* accountListNode = new ParserNode(pe);
140         {
141             pe = new ParserElement("account", &XMLFile::doAccount,
142                                    accountListNode);
143             ParserNode* accountNode = new ParserNode(pe);
144             {
145                 accountNode->add(pe, "account"); // recursive link
146                 new ParserElement("flag", &XMLFile::doFlag, accountNode);
147                 createSubTreeCustomAttribute(accountNode);
148             }
149         }
150
151         // taskList element
152         pe = new ParserElement("taskList", &XMLFile::doTaskList,
153                                taskjugglerNode);
154         ParserNode* taskListNode = new ParserNode(pe);
155         {
156             pe = new ParserElement("task", &XMLFile::doTask, taskListNode);
157             ParserNode* taskNode = new ParserNode(pe);
158
159             taskNode->add(pe, "task");   // recursive link
160             pe = new ParserElement("taskScenario", &XMLFile::doTaskScenario,
161                                    taskNode);
162             ParserNode* taskScenarioNode = new ParserNode(pe);
163             {
164                 new ParserElement("customScenario", 0, taskScenarioNode);
165                 new ParserElement("start", &XMLFile::doTaskScenarioStart,
166                                   taskScenarioNode);
167                 new ParserElement("end", &XMLFile::doTaskScenarioEnd,
168                                   taskScenarioNode);
169                 new ParserElement("maxEnd", &XMLFile::doTaskScenarioMaxEnd,
170                                   taskScenarioNode);
171                 new ParserElement("maxStart", &XMLFile::doTaskScenarioMaxStart,
172                                   taskScenarioNode);
173                 new ParserElement("minEnd", &XMLFile::doTaskScenarioMinEnd,
174                                   taskScenarioNode);
175                 new ParserElement("minStart", &XMLFile::doTaskScenarioMinStart,
176                                   taskScenarioNode);
177
178             }
179             pe = new ParserElement("allocate", &XMLFile::doAllocate,
180                                    taskNode);
181             ParserNode* allocateNode = new ParserNode(pe);
182             {
183                 new ParserElement("candidate", &XMLFile::doCandidate,
184                                   allocateNode);
185             }
186             new ParserElement("flag", &XMLFile::doFlag, taskNode);
187             pe = new ParserElement("depends", &XMLFile::doDepends, taskNode);
188             ParserNode* dependencyGapScenarioNode = new ParserNode(pe);
189             {
190                 new ParserElement("dependencyGapScenario",
191                                   &XMLFile::doDependencyGapScenario,
192                                   dependencyGapScenarioNode);
193             }
194             pe = new ParserElement("precedes", &XMLFile::doPrecedes, taskNode);
195             dependencyGapScenarioNode = new ParserNode(pe);
196             {
197                 new ParserElement("dependencyGapScenario",
198                                   &XMLFile::doDependencyGapScenario,
199                                   dependencyGapScenarioNode);
200             }
201             new ParserElement("note", &XMLFile::doNote, taskNode);
202             createSubTreeCustomAttribute(taskNode);
203         }
204
205         // bookingList element
206         pe = new ParserElement("bookingList", 0, taskjugglerNode);
207         ParserNode* bookingListNode = new ParserNode(pe);
208         {
209             pe = new ParserElement("resourceBooking",
210                                    &XMLFile::doResourceBooking,
211                                    bookingListNode);
212             ParserNode* resourceBookingNode = new ParserNode(pe);
213             {
214                 createSubTreeTimeInterval("booking", &XMLFile::doBooking,
215                                           resourceBookingNode,
216                                           &XMLFile::doBookingPost);
217             }
218         }
219     }
220 }
221
222 void
223 XMLFile::createSubTreeTimeInterval(const QString& id,
224                                    ParserFunctionPtr preFunc,
225                                    ParserNode* parentNode,
226                                    ParserFunctionPtr postFunc)
227 {
228     ParserElement* pe = new ParserElement(id, preFunc, parentNode, postFunc);
229     ParserNode* timeIntervalNode = new ParserNode(pe);
230     {
231         new ParserElement("start", &XMLFile::doTimeIntervalStart,
232                           timeIntervalNode);
233         new ParserElement("end", &XMLFile::doTimeIntervalEnd,
234                           timeIntervalNode);
235     }
236 }
237
238 void
239 XMLFile::createSubTreeWorkingHours(ParserFunctionPtr func,
240                                    ParserElement* parentEl,
241                                    ParserFunctionPtr postFunc)
242 {
243     ParserNode* workingHoursNode = new ParserNode(parentEl);
244     {
245         ParserElement* pe =
246             new ParserElement("weekdayWorkingHours", func, workingHoursNode,
247                               postFunc);
248         ParserNode* weekdayWorkingHoursNode = new ParserNode(pe);
249         {
250             createSubTreeTimeInterval("timeInterval",
251                                    &XMLFile::doTimeInterval,
252                                    weekdayWorkingHoursNode);
253         }
254     }
255 }
256
257 void
258 XMLFile::createSubTreeVacationList(ParserFunctionPtr func,
259                                    ParserNode* parentNode)
260 {
261     ParserElement* pe = new ParserElement("vacationList", 0, parentNode);
262     ParserNode* vacationListNode = new ParserNode(pe);
263     {
264         createSubTreeTimeInterval("vacation", func, vacationListNode);
265     }
266 }
267
268 void
269 XMLFile::createSubTreeCustomAttribute(ParserNode* parentNode)
270 {
271     ParserElement* pe =
272         new ParserElement("customAttribute", &XMLFile::doCustomAttribute,
273                           parentNode);
274     ParserNode* customAttributeNode = new ParserNode(pe);
275     {
276         new ParserElement("textAttribute", &XMLFile::doTextAttribute,
277                           customAttributeNode);
278         new ParserElement("referenceAttribute",
279                           &XMLFile::doReferenceAttribute,
280                           customAttributeNode);
281     }
282 }
283
284 bool
285 XMLFile::readDOM(const QString& file, const QString&, const QString&,
286                  bool masterfile)
287 {
288     if (masterfile)
289     {
290         project->setProgressBar(0, 100);
291         masterFile = file;
292     }
293
294     gzFile zf;
295     if (file == ".")
296     {
297         if ((zf = gzdopen(dup(STDIN_FILENO), "rb")) == NULL)
298         {
299             tjWarning(i18n("Cannot open compressed STDIN for reading."));
300             return false;
301         }
302     }
303     else
304     {
305         if ((zf = gzopen(file, "rb")) == NULL)
306         {
307             tjWarning(i18n("Cannot open compressed file %1 for "
308                           "reading.").arg(file));
309             return false;
310         }
311     }
312
313     if (DEBUGLEVEL > 0)
314         tjWarning(i18n("Processing file \'%1\'").arg(file));
315
316     QString buf;
317     while (!gzeof(zf))
318     {
319         char cbuf[1024];
320         gzgets(zf, cbuf, 1024);
321         buf += cbuf;
322     }
323     int zError;
324     if ((zError = gzclose(zf)) != 0)
325     {
326         tjWarning(i18n("Cannot close compressed file %1: %2")
327                  .arg(file).arg(gzerror(zf, &zError)));
328         return false;
329     }
330
331     doc = new QDomDocument(file);
332     if (!doc->setContent(buf))
333     {
334         tjWarning(i18n("Syntax error in XML file '%1'.").arg(file));
335         return false;
336     }
337
338     return true;
339 }
340
341 bool
342 XMLFile::parse()
343 {
344     QDomNode n = doc->firstChild();
345
346     ParserTreeContext ptc;
347     ptc.setTask(0);
348
349     return parseNode(parserRootNode, n, ptc);
350 }
351
352 bool
353 XMLFile::parseNode(const ParserNode* pn, QDomNode n, ParserTreeContext ptc)
354 {
355     bool ret = true;
356
357     while (!n.isNull())
358     {
359         QDomElement el = n.toElement();
360         if (!el.isNull())
361         {
362             const ParserElement* pEl = pn->getElement(el.tagName());
363             if (!pEl)
364             {
365                 tjWarning(i18n("Unsupported XML element %1").arg(el.tagName()));
366                 ret = false;
367             }
368             else
369             {
370                 /* Create a copy of the current ptc. The node function may
371                  * modify this copy to pass contextual information to the
372                  * elements of this node. */
373                 ParserTreeContext ptcCopy = ptc;
374                 /* If a node pre function has been specified, call this function
375                  * and pass it the ptc. */
376                 if (pEl->getPreFunc())
377                     if (!((*this).*(pEl->getPreFunc()))(n, ptcCopy))
378                         return false;
379                 /* If sub-elements of this node have been defined in the
380                  * parse tree, call this function again to process the
381                  * sub-elements. */
382                 if (pEl->getNode())
383                     if (!parseNode(pEl->getNode(), n.firstChild(), ptcCopy))
384                         return false;
385                 /* If a node post function has been specified, call this
386                  * function and pass it the ptc. */
387                 if (pEl->getPostFunc())
388                     if (!((*this).*(pEl->getPostFunc()))(n, ptcCopy))
389                         return false;
390             }
391         }
392         n = n.nextSibling();
393     }
394
395     return ret;
396 }
397
398 bool
399 XMLFile::doTaskJuggler(QDomNode&, ParserTreeContext&)
400 {
401     return true;
402 }
403
404 bool
405 XMLFile::doProject(QDomNode& n, ParserTreeContext& ptc)
406 {
407     QDomElement el = n.toElement();
408     // mandatory attributes
409     project->addId(el.attribute("id"));
410     project->setName(el.attribute("name"));
411     project->setVersion(el.attribute("version"));
412     if (el.hasAttribute("timezone") && !el.attribute("timezone").isEmpty())
413         project->setTimeZone(el.attribute("timezone"));
414
415     // optional attributes
416     project->setScheduleGranularity
417         (el.attribute("timingResolution", "3600").toInt());
418     project->setDailyWorkingHours
419         (el.attribute("dailyWorkingHours", "8").toDouble());
420     project->setYearlyWorkingDays
421         (el.attribute("yearlyWorkingDays", "260.714").toDouble());
422     project->setWeekStartsMonday
423         (el.attribute("weekStartMonday", "1").toInt());
424     project->setTimeFormat(el.attribute("timeFormat", "%Y-%m-%d %H:%M"));
425     project->setShortTimeFormat(el.attribute("shortTimeFormat", "%H:%M"));
426
427     /* Delete all default working hours since not all days have to be present
428      * in the working hour specificiation. A missing day is a day off. */
429     Q3PtrList<Interval> iv;
430     for (int i = 0; i < 7; ++i)
431         project->setWorkingHours(i, iv);
432
433     ptc.setScenario(0);
434
435     return true;
436 }
437
438 bool
439 XMLFile::doProjectStart(QDomNode& n, ParserTreeContext&)
440 {
441     project->setStart(n.toElement().text().toLong());
442     return true;
443 }
444
445 bool
446 XMLFile::doProjectEnd(QDomNode& n, ParserTreeContext&)
447 {
448     project->setEnd(n.toElement().text().toLong() - 1);
449     return true;
450 }
451
452 bool
453 XMLFile::doProjectNow(QDomNode& n, ParserTreeContext&)
454 {
455     project->setNow(n.toElement().text().toLong());
456     return true;
457 }
458
459 bool
460 XMLFile::doScenario(QDomNode& n, ParserTreeContext& ptc)
461 {
462     QDomElement el = n.toElement();
463
464     /* The project has a default scenario called plan. The XML always brings
465      * it's own scenario definition. So we have to clear the default. */
466     if (!ptc.getScenario())
467         delete project->getScenario(0);
468     Scenario* scenario = new Scenario(project, el.attribute("id"),
469                                       el.attribute("name"), ptc.getScenario());
470     ptc.setScenario(scenario);
471
472     return true;
473 }
474
475 bool
476 XMLFile::doCurrencyFormat(QDomNode& n, ParserTreeContext&)
477 {
478     QDomElement el = n.toElement();
479
480     project->setCurrencyFormat
481         (RealFormat(el.attribute("signPrefix"), el.attribute("signSuffix"),
482                     el.attribute("thousandSep"), el.attribute("fractionSep"),
483                     el.attribute("fracDigits").toInt()));
484     return true;
485 }
486
487 bool
488 XMLFile::doExtend(QDomNode& n, ParserTreeContext& ptc)
489 {
490     ptc.setExtendProperty(n.toElement().attribute("property"));
491     return true;
492 }
493
494 bool
495 XMLFile::doExtendAttribute(QDomNode& n, ParserTreeContext& ptc)
496 {
497     QDomElement el = n.toElement();
498     QString type = el.attribute("type");
499     CustomAttributeType cat = CAT_Undefined;
500     if (type == "text")
501         cat = CAT_Text;
502     else if (type == "reference")
503         cat = CAT_Reference;
504     CustomAttributeDefinition* ca =
505         new CustomAttributeDefinition(el.attribute("name"), cat);
506     if (!ca)
507     {
508         tjWarning(i18n("Unknown custom attribute %1")
509                  .arg(el.attribute("name")));
510         return false;
511     }
512     ca->setInherit(el.attribute("inherit").toInt());
513     if (ptc.getExtendProperty() == "task")
514         project->addTaskAttribute(el.attribute("id"), ca);
515     else if (ptc.getExtendProperty() == "resource")
516         project->addResourceAttribute(el.attribute("id"), ca);
517     else if (ptc.getExtendProperty() == "account")
518         project->addAccountAttribute(el.attribute("id"), ca);
519
520     return true;
521 }
522
523 bool
524 XMLFile::doProjectWeekdayWorkingHours(QDomNode& n, ParserTreeContext& ptc)
525 {
526     QDomElement el = n.toElement();
527
528     Q3PtrList<Interval>* wi = new Q3PtrList<Interval>;
529     wi->setAutoDelete(true);
530     ptc.setWorkingHours(wi);
531     ptc.setWeekday(el.attribute("weekday").toInt());
532
533     return true;
534 }
535
536 bool
537 XMLFile::doProjectWeekdayWorkingHoursPost(QDomNode&, ParserTreeContext& ptc)
538 {
539     project->setWorkingHours(ptc.getWeekday(), *ptc.getWorkingHours());
540     delete ptc.getWorkingHours();
541     return true;
542 }
543
544 bool
545 XMLFile::doShiftWeekdayWorkingHours(QDomNode& n, ParserTreeContext& ptc)
546 {
547     QDomElement el = n.toElement();
548
549     Q3PtrList<Interval>* wi = new Q3PtrList<Interval>;
550     wi->setAutoDelete(true);
551     ptc.setWorkingHours(wi);
552     ptc.setWeekday(el.attribute("weekday").toInt());
553
554     return true;
555 }
556
557 bool
558 XMLFile::doShiftWeekdayWorkingHoursPost(QDomNode&, ParserTreeContext& ptc)
559 {
560     ptc.getShift()->setWorkingHours(ptc.getWeekday(), *ptc.getWorkingHours());
561     delete ptc.getWorkingHours();
562     return true;
563 }
564
565 bool
566 XMLFile::doResourceWeekdayWorkingHours(QDomNode& n, ParserTreeContext& ptc)
567 {
568     QDomElement el = n.toElement();
569
570     Q3PtrList<Interval>* wi = new Q3PtrList<Interval>;
571     wi->setAutoDelete(true);
572     ptc.setWorkingHours(wi);
573     ptc.setWeekday(el.attribute("weekday").toInt());
574
575     return true;
576 }
577
578 bool
579 XMLFile::doResourceWeekdayWorkingHoursPost(QDomNode&, ParserTreeContext& ptc)
580 {
581     ptc.getResource()->setWorkingHours
582         (ptc.getWeekday(), *ptc.getWorkingHours());
583     delete ptc.getWorkingHours();
584     return true;
585 }
586
587 bool
588 XMLFile::doTimeInterval(QDomNode&, ParserTreeContext& ptc)
589 {
590     Interval* iv = new Interval();
591     ptc.getWorkingHours()->append(iv);
592     ptc.setInterval(iv);
593
594     return true;
595 }
596
597 bool
598 XMLFile::doTimeIntervalStart(QDomNode& n, ParserTreeContext& ptc)
599 {
600     ptc.getInterval()->setStart(n.toElement().text().toLong());
601     return true;
602 }
603
604 bool
605 XMLFile::doTimeIntervalEnd(QDomNode& n, ParserTreeContext& ptc)
606 {
607     ptc.getInterval()->setEnd(n.toElement().text().toLong() - 1);
608     return true;
609 }
610
611 bool
612 XMLFile::doProjectVacation(QDomNode& n, ParserTreeContext& ptc)
613 {
614     QDomElement el = n.toElement();
615     VacationInterval* vi = new VacationInterval();
616     vi->setName(el.attribute("name"));
617     ptc.setVacationInterval(vi);
618     project->addVacation(vi);
619     return true;
620 }
621
622 bool
623 XMLFile::doResourceVacation(QDomNode& n, ParserTreeContext& ptc)
624 {
625     QDomElement el = n.toElement();
626     Interval* vi = new Interval();
627     ptc.setInterval(vi);
628     ptc.getResource()->addVacation(vi);
629     return true;
630 }
631
632 bool
633 XMLFile::doCustomAttribute(QDomNode& n, ParserTreeContext& ptc)
634 {
635     ptc.setExtendProperty(n.toElement().attribute("id"));
636     return true;
637 }
638
639 bool
640 XMLFile::doTextAttribute(QDomNode& n, ParserTreeContext& ptc)
641 {
642     QDomElement el = n.toElement();
643     TextAttribute* ta =
644         new TextAttribute(el.attribute("text"));
645     ptc.getCoreAttributes()->addCustomAttribute(ptc.getExtendProperty(), ta);
646     return true;
647 }
648
649 bool
650 XMLFile::doReferenceAttribute(QDomNode& n, ParserTreeContext& ptc)
651 {
652     QDomElement el = n.toElement();
653     ReferenceAttribute* ra =
654         new ReferenceAttribute(el.attribute("url"), el.attribute("label"));
655     ptc.getCoreAttributes()->addCustomAttribute(ptc.getExtendProperty(), ra);
656     return true;
657 }
658
659 bool
660 XMLFile::doShiftList(QDomNode&, ParserTreeContext& ptc)
661 {
662     ptc.setShift(0);
663     return true;
664 }
665
666 bool
667 XMLFile::doShift(QDomNode& n, ParserTreeContext& ptc)
668 {
669     QDomElement el = n.toElement();
670     Shift* shift = new Shift(project, el.attribute("id"),
671                              el.attribute("name"), ptc.getShift());
672     ptc.setShift(shift);
673
674     /* Delete all default working hours since not all days have to be present
675      * in the working hour specificiation. A missing day is a day off. */
676     Q3PtrList<Interval> iv;
677     for (int i = 0; i < 7; ++i)
678         shift->setWorkingHours(i, iv);
679
680     return true;
681 }
682
683 bool
684 XMLFile::doResourceList(QDomNode&, ParserTreeContext& ptc)
685 {
686     ptc.setResource(0);
687     return true;
688 }
689
690 bool
691 XMLFile::doResource(QDomNode& n, ParserTreeContext& ptc)
692 {
693     QDomElement el = n.toElement();
694     Resource* r = new Resource(project, el.attribute("id"),
695                                el.attribute("name"), ptc.getResource());
696
697     /* Delete all default working hours since not all days have to be present
698      * in the working hour specificiation. A missing day is a day off. */
699     Q3PtrList<Interval> iv;
700     for (int i = 0; i < 7; ++i)
701         r->setWorkingHours(i, iv);
702
703     ptc.setResource(r);
704
705     return true;
706 }
707
708 bool
709 XMLFile::doShiftSelection(QDomNode& n, ParserTreeContext& ptc)
710 {
711     Interval* iv = new Interval();
712     ptc.setInterval(iv);
713     ShiftSelection* ss =
714         new ShiftSelection
715         (iv, project->getShift(n.toElement().attribute("shiftId")));
716     ptc.getResource()->addShift(ss);
717
718     return true;
719 }
720
721 bool
722 XMLFile::doAccountList(QDomNode&, ParserTreeContext& ptc)
723 {
724     ptc.setAccount(0);
725     return true;
726 }
727
728 bool
729 XMLFile::doAccount(QDomNode& n, ParserTreeContext& ptc)
730 {
731     QDomElement el = n.toElement();
732     Account* a = new Account(project, el.attribute("id"),
733                              el.attribute("name"), ptc.getAccount(),
734                              ptc.getAccount() ?
735                              ptc.getAccount()->getAcctType() :
736                              el.attribute("type") == "cost" ?
737                              Cost : Revenue);
738     ptc.setAccount(a);
739
740     return true;
741 }
742
743 bool
744 XMLFile::doTaskList(QDomNode&, ParserTreeContext& ptc)
745 {
746     ptc.setTask(0);
747     return true;
748 }
749
750 bool
751 XMLFile::doTask(QDomNode& n, ParserTreeContext& ptc)
752 {
753     QDomElement el = n.toElement();
754     Task* t = new Task(project, el.attribute("id"), el.attribute("name"),
755                        ptc.getTask(), "", 0);
756     ptc.setTask(t);
757     t->setProjectId(el.attribute("projectId"));
758     t->setMilestone(el.attribute("milestone").toInt());
759     t->setScheduling(el.attribute("asapScheduling").toInt() ?
760                      Task::ASAP : Task::ALAP);
761     t->setPriority(el.attribute("priority").toInt());
762
763     // Optional attributes
764     if (!el.attribute("responsible").isEmpty())
765         t->setResponsible(project->getResource(el.attribute("responsible")));
766     if (!el.attribute("account").isEmpty())
767         t->setAccount(project->getAccount(el.attribute("account")));
768
769     return true;
770 }
771
772 bool
773 XMLFile::doTaskScenario(QDomNode& n, ParserTreeContext& ptc)
774 {
775     QDomElement el = n.toElement();
776     int sc = project->getScenarioIndex(el.attribute("scenarioId")) - 1;
777     ptc.setScenarioIndex(sc);
778     Task* t = ptc.getTask();
779     t->setEffort(sc, el.attribute("effort", "0.0").toDouble());
780     t->setDuration(sc, el.attribute("duration", "0.0").toDouble());
781     t->setLength(sc, el.attribute("length", "0.0").toDouble());
782     t->setScheduled(sc, el.attribute("scheduled", "0").toInt());
783     t->setComplete(sc, el.attribute("complete", "-1").toDouble());
784     /* The scenario status will be ignored as it is computed after the file is
785      * read in. */
786     t->setStatusNote(sc, el.attribute("statusNote", ""));
787
788     return true;
789 }
790
791 bool
792 XMLFile::doTaskScenarioStart(QDomNode& n, ParserTreeContext& ptc)
793 {
794     ptc.getTask()->setSpecifiedStart(ptc.getScenarioIndex(),
795                                      n.toElement().text().toLong());
796     return true;
797 }
798
799 bool
800 XMLFile::doTaskScenarioEnd(QDomNode& n, ParserTreeContext& ptc)
801 {
802     ptc.getTask()->setSpecifiedEnd(ptc.getScenarioIndex(),
803                                    n.toElement().text().toLong() - 1);
804     return true;
805 }
806
807 bool
808 XMLFile::doTaskScenarioMaxEnd(QDomNode& n, ParserTreeContext& ptc)
809 {
810     ptc.getTask()->setMaxEnd(ptc.getScenarioIndex(),
811                              n.toElement().text().toLong() - 1);
812     return true;
813 }
814
815 bool
816 XMLFile::doTaskScenarioMinEnd(QDomNode& n, ParserTreeContext& ptc)
817 {
818     ptc.getTask()->setMinEnd(ptc.getScenarioIndex(),
819                              n.toElement().text().toLong() - 1);
820     return true;
821 }
822
823 bool
824 XMLFile::doTaskScenarioMaxStart(QDomNode& n, ParserTreeContext& ptc)
825 {
826     ptc.getTask()->setMaxStart(ptc.getScenarioIndex(),
827                                n.toElement().text().toLong());
828     return true;
829 }
830
831 bool
832 XMLFile::doTaskScenarioMinStart(QDomNode& n, ParserTreeContext& ptc)
833 {
834     ptc.getTask()->setMinStart(ptc.getScenarioIndex(),
835                                n.toElement().text().toLong());
836     return true;
837 }
838
839 bool
840 XMLFile::doAllocate(QDomNode&, ParserTreeContext& ptc)
841 {
842     Allocation* a = new Allocation();
843     ptc.getTask()->addAllocation(a);
844     ptc.setAllocation(a);
845
846     return true;
847 }
848
849 bool
850 XMLFile::doCandidate(QDomNode& n, ParserTreeContext& ptc)
851 {
852     QDomElement el = n.toElement();
853     ptc.getAllocation()->addCandidate
854         (project->getResource(el.attribute("resourceId")));
855
856     return true;
857 }
858
859 bool
860 XMLFile::doFlag(QDomNode& n, ParserTreeContext& ptc)
861 {
862     QDomElement el = n.toElement();
863
864     ptc.getCoreAttributes()->addFlag(el.text());
865
866     return true;
867 }
868
869 bool
870 XMLFile::doDepends(QDomNode& n, ParserTreeContext& ptc)
871 {
872     ptc.setTaskDependency
873         (ptc.getTask()->addDepends(n.toElement().text()));
874     return true;
875 }
876
877 bool
878 XMLFile::doPrecedes(QDomNode& n, ParserTreeContext& ptc)
879 {
880     ptc.setTaskDependency
881         (ptc.getTask()->addPrecedes(n.toElement().text()));
882     return true;
883 }
884
885 bool
886 XMLFile::doDependencyGapScenario(QDomNode& n, ParserTreeContext& ptc)
887 {
888     QDomElement el = n.toElement();
889     int sc = project->getScenarioIndex(el.attribute("scenarioId")) - 1;
890     ptc.getTaskDependency()->setGapDuration
891         (sc, el.attribute("gapDuration", "0").toLong());
892     ptc.getTaskDependency()->setGapLength
893         (sc, el.attribute("gapLength", "0").toLong());
894
895     return true;
896 }
897
898 bool
899 XMLFile::doNote(QDomNode& n, ParserTreeContext& ptc)
900 {
901     ptc.getTask()->setNote(n.toElement().text());
902     return true;
903 }
904
905 bool
906 XMLFile::doResourceBooking(QDomNode& n, ParserTreeContext& ptc)
907 {
908     QDomElement el = n.toElement();
909     Resource* resource = project->getResource(el.attribute("resourceId"));
910     if (!resource)
911     {
912         tjWarning(i18n("Booking for unknown resource %1")
913                  .arg(el.attribute("resourceId")));
914         return false;
915     }
916     ptc.setResource(resource);
917     int sc = project->getScenarioIndex(el.attribute("scenarioId")) - 1;
918     if (sc < 0)
919     {
920         tjWarning(i18n("Booking for unknown scenario %1")
921                  .arg(el.attribute("scenarioId")));
922         return false;
923     }
924     ptc.setScenarioIndex(sc);
925     return true;
926 }
927
928 bool
929 XMLFile::doBooking(QDomNode&, ParserTreeContext& ptc)
930 {
931     Interval* iv = new Interval();
932     ptc.setInterval(iv);
933     return true;
934 }
935
936 bool
937 XMLFile::doBookingPost(QDomNode& n, ParserTreeContext& ptc)
938 {
939     Task* t = project->getTask(n.toElement().attribute("taskId"));
940     if (!t)
941     {
942         tjWarning(i18n("Booking for unknown task %1")
943                  .arg(n.toElement().attribute("taskId")));
944         return false;
945     }
946     ptc.getResource()->addBooking(ptc.getScenarioIndex(),
947                                   new Booking(ptc.getInterval(), t));
948
949     return true;
950 }
951