1 /* This file is part of the KDE project
2 Copyright (C) 2010 Dag Andersen <danders@get2net.dk>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 // clazy:excludeall=qstring-arg
21 #include "KPlatoXmlLoaderBase.h"
22
23 #include "kptlocale.h"
24 #include "kptxmlloaderobject.h"
25 #include "kptnode.h"
26 #include "kptproject.h"
27 #include "kpttask.h"
28 #include "kptcalendar.h"
29 #include "kptschedule.h"
30 #include "kptrelation.h"
31 #include "kptresource.h"
32 #include "kptaccount.h"
33 #include "kptappointment.h"
34
35 #include <KoXmlReader.h>
36
37 #include <KLocalizedString>
38
39 #include <QTimeZone>
40
41
42 using namespace KPlato;
43
KPlatoXmlLoaderBase()44 KPlatoXmlLoaderBase::KPlatoXmlLoaderBase()
45 {
46 }
47
load(Project * project,const KoXmlElement & element,XMLLoaderObject & status)48 bool KPlatoXmlLoaderBase::load(Project *project, const KoXmlElement &element, XMLLoaderObject &status)
49 {
50 debugPlanXml<<"project";
51 // load locale first
52 KoXmlNode n = element.firstChild();
53 for (; ! n.isNull(); n = n.nextSibling()) {
54 if (! n.isElement()) {
55 continue;
56 }
57 KoXmlElement e = n.toElement();
58 if (e.tagName() == "locale") {
59 Locale *l = project->locale();
60 l->setCurrencySymbol(e.attribute("currency-symbol", l->currencySymbol()));
61 //NOTE: decimalplaces missing
62 }
63 }
64 QList<Calendar*> cals;
65 QString s;
66 bool ok = false;
67 project->setName(element.attribute("name"));
68 project->removeId(project->id());
69 project->setId(element.attribute("id"));
70 project->registerNodeId(project);
71 project->setLeader(element.attribute("leader"));
72 project->setDescription(element.attribute("description"));
73 QTimeZone tz(element.attribute("timezone").toLatin1());
74
75 if (tz.isValid()) {
76 project->setTimeZone(tz);
77 } else warnPlanXml<<"No timezone specified, using default (local)";
78 status.setProjectTimeZone(project->timeZone());
79
80 // Allow for both numeric and text
81 s = element.attribute("scheduling", "0");
82 project->setConstraint((Node::ConstraintType) (s.toInt(&ok)));
83 if (! ok)
84 project->setConstraint(s);
85 if (project->constraint() != Node::MustStartOn && project->constraint() != Node::MustFinishOn) {
86 errorPlanXml << "Illegal constraint: " << project->constraintToString();
87 project->setConstraint(Node::MustStartOn);
88 }
89 s = element.attribute("start-time");
90 if (! s.isEmpty()) {
91 project->setConstraintStartTime(DateTime::fromString(s, project->timeZone()));
92 }
93 s = element.attribute("end-time");
94 if (! s.isEmpty()) {
95 project->setConstraintEndTime(DateTime::fromString(s, project->timeZone()));
96 }
97 // Load the project children
98 // Do calendars first, they only reference other calendars
99 //debugPlanXml<<"Calendars--->";
100 n = element.firstChild();
101 for (; ! n.isNull(); n = n.nextSibling()) {
102 if (! n.isElement()) {
103 continue;
104 }
105 KoXmlElement e = n.toElement();
106 if (e.tagName() == "calendar") {
107 // Load the calendar.
108 // Referenced by resources
109 Calendar * child = new Calendar();
110 child->setProject(project);
111 if (load(child, e, status)) {
112 cals.append(child); // temporary, reorder later
113 } else {
114 // TODO: Complain about this
115 errorPlanXml << "Failed to load calendar";
116 delete child;
117 }
118 } else if (e.tagName() == "standard-worktime") {
119 // Load standard worktime
120 StandardWorktime * child = new StandardWorktime();
121 if (load(child, e, status)) {
122 project->setStandardWorktime(child);
123 } else {
124 errorPlanXml << "Failed to load standard worktime";
125 delete child;
126 }
127 }
128 }
129 // calendars references calendars in arbitrary saved order
130 bool added = false;
131 do {
132 added = false;
133 QList<Calendar*> lst;
134 while (!cals.isEmpty()) {
135 Calendar *c = cals.takeFirst();
136 if (c->parentId().isEmpty()) {
137 project->addCalendar(c, status.baseCalendar()); // handle pre 0.6 version
138 added = true;
139 //debugPlanXml<<"added to project:"<<c->name();
140 } else {
141 Calendar *par = project->calendar(c->parentId());
142 if (par) {
143 project->addCalendar(c, par);
144 added = true;
145 //debugPlanXml<<"added:"<<c->name()<<" to parent:"<<par->name();
146 } else {
147 lst.append(c); // treat later
148 //debugPlanXml<<"treat later:"<<c->name();
149 }
150 }
151 }
152 cals = lst;
153 } while (added);
154 if (! cals.isEmpty()) {
155 errorPlanXml<<"All calendars not saved!";
156 }
157 //debugPlanXml<<"Calendars<---";
158 // Resource groups and resources, can reference calendars
159 n = element.firstChild();
160 for (; ! n.isNull(); n = n.nextSibling()) {
161 if (! n.isElement()) {
162 continue;
163 }
164 KoXmlElement e = n.toElement();
165 if (e.tagName() == "resource-group") {
166 // Load the resources
167 // References calendars
168 ResourceGroup * child = new ResourceGroup();
169 if (load(child, e, status)) {
170 project->addResourceGroup(child);
171 } else {
172 // TODO: Complain about this
173 delete child;
174 }
175 }
176 }
177 // The main stuff
178 n = element.firstChild();
179 for (; ! n.isNull(); n = n.nextSibling()) {
180 if (! n.isElement()) {
181 continue;
182 }
183 KoXmlElement e = n.toElement();
184 if (e.tagName() == "project") {
185 //debugPlanXml<<"Sub project--->";
186 /* // Load the subproject
187 Project * child = new Project(this);
188 if (child->load(e)) {
189 if (!addTask(child, this)) {
190 delete child; // TODO: Complain about this
191 }
192 } else {
193 // TODO: Complain about this
194 delete child;
195 }*/
196 } else if (e.tagName() == "task") {
197 //debugPlanXml<<"Task--->";
198 // Load the task (and resourcerequests).
199 // Depends on resources already loaded
200 Task *child = new Task(project);
201 if (load(child, e, status)) {
202 if (! project->addTask(child, project)) {
203 delete child; // TODO: Complain about this
204 }
205 } else {
206 // TODO: Complain about this
207 delete child;
208 }
209 }
210 }
211 // These go last
212 n = element.firstChild();
213 for (; ! n.isNull(); n = n.nextSibling()) {
214 debugPlanXml<<n.isElement();
215 if (! n.isElement()) {
216 continue;
217 }
218 KoXmlElement e = n.toElement();
219 if (e.tagName() == "accounts") {
220 //debugPlanXml<<"Accounts--->";
221 // Load accounts
222 // References tasks
223 if (! load(project->accounts(), e, status)) {
224 errorPlanXml << "Failed to load accounts";
225 }
226 } else if (e.tagName() == "relation") {
227 //debugPlanXml<<"Relation--->";
228 // Load the relation
229 // References tasks
230 Relation * child = new Relation();
231 if (! load(child, e, status)) {
232 // TODO: Complain about this
233 errorPlanXml << "Failed to load relation";
234 delete child;
235 }
236 //debugPlanXml<<"Relation<---";
237 } else if (e.tagName() == "schedules") {
238 debugPlanXml<<"Project schedules & task appointments--->";
239 // References tasks and resources
240 KoXmlNode sn = e.firstChild();
241 for (; ! sn.isNull(); sn = sn.nextSibling()) {
242 if (! sn.isElement()) {
243 continue;
244 }
245 KoXmlElement el = sn.toElement();
246 //debugPlanXml<<el.tagName()<<" Version="<<status.version();
247 ScheduleManager *sm = 0;
248 bool add = false;
249 if (status.version() <= "0.5") {
250 if (el.tagName() == "schedule") {
251 sm = project->findScheduleManagerByName(el.attribute("name"));
252 if (sm == 0) {
253 sm = new ScheduleManager(*project, el.attribute("name"));
254 add = true;
255 }
256 }
257 } else if (el.tagName() == "plan") {
258 sm = new ScheduleManager(*project);
259 add = true;
260 }
261 if (sm) {
262 if (load(sm, el, status)) {
263 if (add)
264 project->addScheduleManager(sm);
265 } else {
266 errorPlanXml << "Failed to load schedule manager";
267 delete sm;
268 }
269 } else {
270 debugPlanXml<<"No schedule manager ?!";
271 }
272 }
273 debugPlanXml<<"Project schedules & task appointments<---";
274 } else if (e.tagName() == "resource-teams") {
275 //debugPlanXml<<"Resource teams--->";
276 // References other resources
277 KoXmlNode tn = e.firstChild();
278 for (; ! tn.isNull(); tn = tn.nextSibling()) {
279 if (! tn.isElement()) {
280 continue;
281 }
282 KoXmlElement el = tn.toElement();
283 if (el.tagName() == "team") {
284 Resource *r = project->findResource(el.attribute("team-id"));
285 Resource *tm = project->findResource(el.attribute("member-id"));
286 if (r == 0 || tm == 0) {
287 errorPlanXml<<"resource-teams: cannot find resources";
288 continue;
289 }
290 if (r == tm) {
291 errorPlanXml<<"resource-teams: a team cannot be a member of itself";
292 continue;
293 }
294 r->addTeamMemberId(tm->id());
295 } else {
296 errorPlanXml<<"resource-teams: unhandled tag"<<el.tagName();
297 }
298 }
299 //debugPlanXml<<"Resource teams<---";
300 } else if (e.tagName() == "wbs-definition") {
301 load(project->wbsDefinition(), e, status);
302 } else if (e.tagName() == "locale") {
303 // handled earlier
304 } else if (e.tagName() == "resource-group") {
305 // handled earlier
306 } else if (e.tagName() == "calendar") {
307 // handled earlier
308 } else if (e.tagName() == "standard-worktime") {
309 // handled earlier
310 } else if (e.tagName() == "project") {
311 // handled earlier
312 } else if (e.tagName() == "task") {
313 // handled earlier
314 } else {
315 warnPlanXml<<"Unhandled tag:"<<e.tagName();
316 }
317 }
318 // set schedule parent
319 foreach (Schedule *s, project->schedules()) {
320 project->setParentSchedule(s);
321 }
322
323 debugPlanXml<<"Project loaded:"<<project<<project->name()<<project->allNodes();
324 return true;
325 }
326
load(Task * task,const KoXmlElement & element,XMLLoaderObject & status)327 bool KPlatoXmlLoaderBase::load(Task *task, const KoXmlElement &element, XMLLoaderObject &status)
328 {
329 debugPlanXml<<"task";
330 QString s;
331 bool ok = false;
332 task->setId(element.attribute("id"));
333
334 task->setName(element.attribute("name"));
335 task->setLeader(element.attribute("leader"));
336 task->setDescription(element.attribute("description"));
337 //debugPlanXml<<m_name<<": id="<<m_id;
338
339 // Allow for both numeric and text
340 QString constraint = element.attribute("scheduling","0");
341 task->setConstraint((Node::ConstraintType)constraint.toInt(&ok));
342 if (! ok) {
343 task->setConstraint(constraint);
344 }
345 s = element.attribute("constraint-starttime");
346 if (! s.isEmpty()) {
347 task->setConstraintStartTime(DateTime::fromString(s, status.projectTimeZone()));
348 }
349 s = element.attribute("constraint-endtime");
350 if (! s.isEmpty()) {
351 task->setConstraintEndTime(DateTime::fromString(s, status.projectTimeZone()));
352 }
353 task->setStartupCost(element.attribute("startup-cost", "0.0").toDouble());
354 task->setShutdownCost(element.attribute("shutdown-cost", "0.0").toDouble());
355
356 // Load the task children
357 KoXmlNode n = element.firstChild();
358 for (; ! n.isNull(); n = n.nextSibling()) {
359 if (! n.isElement()) {
360 continue;
361 }
362 KoXmlElement e = n.toElement();
363 if (e.tagName() == "project") {
364 // Load the subproject
365 /* Project *child = new Project(this, status);
366 if (child->load(e)) {
367 if (!project.addSubTask(child, this)) {
368 delete child; // TODO: Complain about this
369 }
370 } else {
371 // TODO: Complain about this
372 delete child;
373 }*/
374 } else if (e.tagName() == "task") {
375 // Load the task
376 Task *child = new Task(task);
377 if (load(child, e, status)) {
378 if (! status.project().addSubTask(child, task)) {
379 delete child; // TODO: Complain about this
380 }
381 } else {
382 // TODO: Complain about this
383 delete child;
384 }
385 } else if (e.tagName() == "resource") {
386 // tasks don't have resources
387 } else if (e.tagName() == "estimate" || (/*status.version() < "0.6" &&*/ e.tagName() == "effort")) {
388 // Load the estimate
389 load(task->estimate(), e, status);
390 } else if (e.tagName() == "resourcegroup-request") {
391 // Load the resource request
392 // Handle multiple requests to same group gracefully (Not really allowed)
393 ResourceGroupRequest *r = task->requests().findGroupRequestById(e.attribute("group-id"));
394 if (r) {
395 warnPlanXml<<"Multiple requests to same group, loading into existing group";
396 if (! load(r, e, status)) {
397 errorPlanXml<<"Failed to load resource request";
398 }
399 } else {
400 r = new ResourceGroupRequest();
401 if (load(r, e, status)) {
402 task->addRequest(r);
403 } else {
404 errorPlanXml<<"Failed to load resource request";
405 delete r;
406 }
407 }
408 } else if (e.tagName() == "workpackage") {
409 load(task->workPackage(), e, status);
410 } else if (e.tagName() == "progress") {
411 load(task->completion(), e, status);
412 } else if (e.tagName() == "schedules") {
413 KoXmlNode n = e.firstChild();
414 for (; ! n.isNull(); n = n.nextSibling()) {
415 if (! n.isElement()) {
416 continue;
417 }
418 KoXmlElement el = n.toElement();
419 if (el.tagName() == "schedule") {
420 NodeSchedule *sch = new NodeSchedule();
421 if (loadNodeSchedule(sch, el, status)) {
422 sch->setNode(task);
423 task->addSchedule(sch);
424 } else {
425 errorPlanXml<<"Failed to load schedule";
426 delete sch;
427 }
428 }
429 }
430 } else if (e.tagName() == "documents") {
431 load(task->documents(), e, status);
432 } else if (e.tagName() == "workpackage-log") {
433 KoXmlNode n = e.firstChild();
434 for (; ! n.isNull(); n = n.nextSibling()) {
435 if (! n.isElement()) {
436 continue;
437 }
438 KoXmlElement el = n.toElement();
439 if (el.tagName() == "workpackage") {
440 WorkPackage *wp = new WorkPackage(task);
441 if (loadWpLog(wp, el, status)) {
442 task->addWorkPackage(wp);
443 } else {
444 errorPlanXml<<"Failed to load logged workpackage";
445 delete wp;
446 }
447 }
448 }
449 }
450 }
451 //debugPlanXml<<m_name<<" loaded";
452 return true;
453 }
454
load(Calendar * calendar,const KoXmlElement & element,XMLLoaderObject & status)455 bool KPlatoXmlLoaderBase::load(Calendar *calendar, const KoXmlElement &element, XMLLoaderObject &status)
456 {
457 debugPlanXml<<"calendar"<<element.text();
458 //bool ok;
459 calendar->setId(element.attribute("id"));
460 calendar->setParentId(element.attribute("parent"));
461 calendar->setName(element.attribute("name",""));
462 QTimeZone tz(element.attribute("timezone").toLatin1());
463 if (tz.isValid()) {
464 calendar->setTimeZone(tz);
465 } else warnPlanXml<<"No timezone specified, use default (local)";
466 bool dc = (bool)element.attribute("default","0").toInt();
467 if (dc) {
468 status.project().setDefaultCalendar(calendar);
469 }
470 KoXmlNode n = element.firstChild();
471 for (; ! n.isNull(); n = n.nextSibling()) {
472 if (! n.isElement()) {
473 continue;
474 }
475 KoXmlElement e = n.toElement();
476 if (e.tagName() == "weekday") {
477 if (! load(calendar->weekdays(), e, status)) {
478 return false;
479 }
480 }
481 if (e.tagName() == "day") {
482 CalendarDay *day = new CalendarDay();
483 if (load(day, e, status)) {
484 if (! day->date().isValid()) {
485 delete day;
486 errorPlanXml<<calendar->name()<<": Failed to load calendarDay - Invalid date";
487 } else {
488 CalendarDay *d = calendar->findDay(day->date());
489 if (d) {
490 // already exists, keep the new
491 delete calendar->takeDay(d);
492 warnPlanXml<<calendar->name()<<" Load calendarDay - Date already exists";
493 }
494 calendar->addDay(day);
495 }
496 } else {
497 delete day;
498 errorPlanXml<<"Failed to load calendarDay";
499 return true; // don't throw away the whole calendar
500 }
501 }
502 }
503 return true;
504 }
505
load(CalendarDay * day,const KoXmlElement & element,XMLLoaderObject & status)506 bool KPlatoXmlLoaderBase::load(CalendarDay *day, const KoXmlElement &element, XMLLoaderObject &status)
507 {
508 debugPlanXml<<"day";
509 bool ok=false;
510 day->setState(QString(element.attribute("state", "-1")).toInt(&ok));
511 if (day->state() < 0) {
512 return false;
513 }
514 //debugPlanXml<<" state="<<m_state;
515 QString s = element.attribute("date");
516 if (! s.isEmpty()) {
517 day->setDate(QDate::fromString(s, Qt::ISODate));
518 if (! day->date().isValid()) {
519 day->setDate(QDate::fromString(s));
520 }
521 }
522 day->clearIntervals();
523 KoXmlNode n = element.firstChild();
524 for (; ! n.isNull(); n = n.nextSibling()) {
525 if (! n.isElement()) {
526 continue;
527 }
528 KoXmlElement e = n.toElement();
529 if (e.tagName() == "interval") {
530 //debugPlanXml<<"Interval start="<<e.attribute("start")<<" end="<<e.attribute("end");
531 QString st = e.attribute("start");
532 if (st.isEmpty()) {
533 errorPlanXml<<"Empty interval";
534 continue;
535 }
536 QTime start = QTime::fromString(st);
537 int length = 0;
538 if (status.version() <= "0.6.1") {
539 QString en = e.attribute("end");
540 if (en.isEmpty()) {
541 errorPlanXml<<"Invalid interval end";
542 continue;
543 }
544 QTime end = QTime::fromString(en);
545 length = start.msecsTo(end);
546 } else {
547 length = e.attribute("length", "0").toInt();
548 }
549 if (length <= 0) {
550 errorPlanXml<<"Invalid interval length";
551 continue;
552 }
553 day->addInterval(new TimeInterval(start, length));
554 }
555 }
556 return true;
557 }
558
load(CalendarWeekdays * weekdays,const KoXmlElement & element,XMLLoaderObject & status)559 bool KPlatoXmlLoaderBase::load(CalendarWeekdays *weekdays, const KoXmlElement& element, XMLLoaderObject& status)
560 {
561 debugPlanXml<<"weekdays";
562 bool ok;
563 int dayNo = QString(element.attribute("day","-1")).toInt(&ok);
564 if (dayNo < 0 || dayNo > 6) {
565 errorPlanXml<<"Illegal weekday: "<<dayNo;
566 return true; // we continue anyway
567 }
568 CalendarDay *day = weekdays->weekday(dayNo + 1);
569 if (day == 0) {
570 errorPlanXml<<"No weekday: "<<dayNo;
571 return false;
572 }
573 if (! load(day, element, status)) {
574 day->setState(CalendarDay::None);
575 }
576 return true;
577
578 }
579
load(StandardWorktime * swt,const KoXmlElement & element,XMLLoaderObject & status)580 bool KPlatoXmlLoaderBase::load(StandardWorktime *swt, const KoXmlElement &element, XMLLoaderObject &status)
581 {
582 debugPlanXml<<"swt";
583 swt->setYear(Duration::fromString(element.attribute("year"), Duration::Format_Hour));
584 swt->setMonth(Duration::fromString(element.attribute("month"), Duration::Format_Hour));
585 swt->setWeek(Duration::fromString(element.attribute("week"), Duration::Format_Hour));
586 swt->setDay(Duration::fromString(element.attribute("day"), Duration::Format_Hour));
587
588 KoXmlNode n = element.firstChild();
589 for (; ! n.isNull(); n = n.nextSibling()) {
590 if (! n.isElement()) {
591 continue;
592 }
593 KoXmlElement e = n.toElement();
594 if (e.tagName() == "calendar") {
595 // pre 0.6 version stored base calendar in standard worktime
596 if (status.version() >= "0.6") {
597 warnPlanXml<<"Old format, calendar in standard worktime";
598 warnPlanXml<<"Tries to load anyway";
599 }
600 // try to load anyway
601 Calendar *calendar = new Calendar;
602 if (load(calendar, e, status)) {
603 status.project().addCalendar(calendar);
604 calendar->setDefault(true);
605 status.project().setDefaultCalendar(calendar); // hmmm
606 status.setBaseCalendar(calendar);
607 } else {
608 delete calendar;
609 errorPlanXml<<"Failed to load calendar";
610 }
611 }
612 }
613 return true;
614 }
615
load(Relation * relation,const KoXmlElement & element,XMLLoaderObject & status)616 bool KPlatoXmlLoaderBase::load(Relation *relation, const KoXmlElement &element, XMLLoaderObject &status)
617 {
618 debugPlanXml<<"relation";
619 relation->setParent(status.project().findNode(element.attribute("parent-id")));
620 if (relation->parent() == 0) {
621 warnPlanXml<<"Parent node == 0, cannot find id:"<<element.attribute("parent-id");
622 return false;
623 }
624 relation->setChild(status.project().findNode(element.attribute("child-id")));
625 if (relation->child() == 0) {
626 warnPlanXml<<"Child node == 0, cannot find id:"<<element.attribute("child-id");
627 return false;
628 }
629 if (relation->child() == relation->parent()) {
630 warnPlanXml<<"Parent node == child node";
631 return false;
632 }
633 if (! relation->parent()->legalToLink(relation->child())) {
634 warnPlanXml<<"Realation is not legal:"<<relation->parent()->name()<<"->"<<relation->child()->name();
635 return false;
636 }
637 relation->setType(element.attribute("type"));
638
639 relation->setLag(Duration::fromString(element.attribute("lag")));
640
641 if (! relation->parent()->addDependChildNode(relation)) {
642 errorPlanXml<<"Failed to add relation: Child="<<relation->child()->name()<<" parent="<<relation->parent()->name();
643 return false;
644 }
645 if (! relation->child()->addDependParentNode(relation)) {
646 relation->parent()->takeDependChildNode(relation);
647 errorPlanXml<<"Failed to add relation: Child="<<relation->child()->name()<<" parent="<<relation->parent()->name();
648 return false;
649 }
650 //debugPlanXml<<"Added relation: Child="<<relation->child()->name()<<" parent="<<relation->parent()->name();
651 return true;
652 }
653
load(ResourceGroup * rg,const KoXmlElement & element,XMLLoaderObject & status)654 bool KPlatoXmlLoaderBase::load(ResourceGroup *rg, const KoXmlElement &element, XMLLoaderObject &status)
655 {
656 debugPlanXml<<"resource-group";
657 rg->setId(element.attribute("id"));
658 rg->setName(element.attribute("name"));
659 rg->setType(element.attribute("type"));
660
661 KoXmlNode n = element.firstChild();
662 for (; ! n.isNull(); n = n.nextSibling()) {
663 if (! n.isElement()) {
664 continue;
665 }
666 KoXmlElement e = n.toElement();
667 if (e.tagName() == "resource") {
668 // Load the resource
669 Resource *child = new Resource();
670 if (load(child, e, status)) {
671 status.project().addResource(rg, child);
672 } else {
673 // TODO: Complain about this
674 delete child;
675 }
676 }
677 }
678 return true;
679 }
680
load(Resource * resource,const KoXmlElement & element,XMLLoaderObject & status)681 bool KPlatoXmlLoaderBase::load(Resource *resource, const KoXmlElement &element, XMLLoaderObject &status)
682 {
683 debugPlanXml<<"resource";
684 const Locale *locale = status.project().locale();
685 QString s;
686 resource->setId(element.attribute("id"));
687 resource->setName(element.attribute("name"));
688 resource->setInitials(element.attribute("initials"));
689 resource->setEmail(element.attribute("email"));
690 resource->setType(element.attribute("type"));
691 resource->setCalendar(status.project().findCalendar(element.attribute("calendar-id")));
692 resource->setUnits(element.attribute("units", "100").toInt());
693 s = element.attribute("available-from");
694 if (! s.isEmpty()) {
695 resource->setAvailableFrom(DateTime::fromString(s, status.projectTimeZone()));
696 }
697 s = element.attribute("available-until");
698 if (! s.isEmpty()) {
699 resource->setAvailableUntil(DateTime::fromString(s, status.projectTimeZone()));
700 }
701 resource->setNormalRate(locale->readMoney(element.attribute("normal-rate")));
702 resource->setOvertimeRate(locale->readMoney(element.attribute("overtime-rate")));
703 resource->setAccount(status.project().accounts().findAccount(element.attribute("account")));
704
705 KoXmlElement e;
706 KoXmlElement parent = element.namedItem("required-resources").toElement();
707 forEachElement(e, parent) {
708 if (e.nodeName() == "resource") {
709 QString id = e.attribute("id");
710 if (id.isEmpty()) {
711 warnPlanXml<<"Missing resource id";
712 continue;
713 }
714 resource->addRequiredId(id);
715 }
716 }
717 parent = element.namedItem("external-appointments").toElement();
718 forEachElement(e, parent) {
719 if (e.nodeName() == "project") {
720 QString id = e.attribute("id");
721 if (id.isEmpty()) {
722 errorPlanXml<<"Missing project id";
723 continue;
724 }
725 resource->clearExternalAppointments(id); // in case...
726 AppointmentIntervalList lst;
727 load(lst, e, status);
728 Appointment *a = new Appointment();
729 a->setIntervals(lst);
730 a->setAuxcilliaryInfo(e.attribute("name", "Unknown"));
731 resource->addExternalAppointment(id, a);
732 }
733 }
734 return true;
735 }
736
load(Accounts & accounts,const KoXmlElement & element,XMLLoaderObject & status)737 bool KPlatoXmlLoaderBase::load(Accounts &accounts, const KoXmlElement &element, XMLLoaderObject &status)
738 {
739 debugPlanXml<<"accounts";
740 KoXmlNode n = element.firstChild();
741 for (; ! n.isNull(); n = n.nextSibling()) {
742 if (! n.isElement()) {
743 continue;
744 }
745 KoXmlElement e = n.toElement();
746 if (e.tagName() == "account") {
747 Account *child = new Account();
748 if (load(child, e, status)) {
749 accounts.insert(child);
750 } else {
751 // TODO: Complain about this
752 warnPlanXml<<"Loading failed";
753 delete child;
754 }
755 }
756 }
757 if (element.hasAttribute("default-account")) {
758 accounts.setDefaultAccount(accounts.findAccount(element.attribute("default-account")));
759 if (accounts.defaultAccount() == 0) {
760 warnPlanXml<<"Could not find default account.";
761 }
762 }
763 return true;
764 }
765
load(Account * account,const KoXmlElement & element,XMLLoaderObject & status)766 bool KPlatoXmlLoaderBase::load(Account* account, const KoXmlElement& element, XMLLoaderObject& status)
767 {
768 debugPlanXml<<"account";
769 account->setName(element.attribute("name"));
770 account->setDescription(element.attribute("description"));
771 KoXmlNode n = element.firstChild();
772 for (; ! n.isNull(); n = n.nextSibling()) {
773 if (! n.isElement()) {
774 continue;
775 }
776 KoXmlElement e = n.toElement();
777 if (e.tagName() == "costplace") {
778 Account::CostPlace *child = new Account::CostPlace(account);
779 if (load(child, e, status)) {
780 account->append(child);
781 } else {
782 delete child;
783 }
784 } else if (e.tagName() == "account") {
785 Account *child = new Account();
786 if (load(child, e, status)) {
787 account->insert(child);
788 } else {
789 // TODO: Complain about this
790 warnPlanXml<<"Loading failed";
791 delete child;
792 }
793 }
794 }
795 return true;
796 }
797
load(Account::CostPlace * cp,const KoXmlElement & element,XMLLoaderObject & status)798 bool KPlatoXmlLoaderBase::load(Account::CostPlace* cp, const KoXmlElement& element, XMLLoaderObject& status)
799 {
800 debugPlanXml<<"cost-place";
801 cp->setObjectId(element.attribute("object-id"));
802 if (cp->objectId().isEmpty()) {
803 // check old format
804 cp->setObjectId(element.attribute("node-id"));
805 if (cp->objectId().isEmpty()) {
806 errorPlanXml<<"No object id";
807 return false;
808 }
809 }
810 cp->setNode(status.project().findNode(cp->objectId()));
811 if (cp->node() == 0) {
812 cp->setResource(status.project().findResource(cp->objectId()));
813 if (cp->resource() == 0) {
814 errorPlanXml<<"Cannot find object with id: "<<cp->objectId();
815 return false;
816 }
817 }
818 bool on = (bool)(element.attribute("running-cost").toInt());
819 if (on) cp->setRunning(on);
820 on = (bool)(element.attribute("startup-cost").toInt());
821 if (on) cp->setStartup(on);
822 on = (bool)(element.attribute("shutdown-cost").toInt());
823 if (on) cp->setShutdown(on);
824 return true;
825 }
826
load(ScheduleManager * manager,const KoXmlElement & element,XMLLoaderObject & status)827 bool KPlatoXmlLoaderBase::load(ScheduleManager *manager, const KoXmlElement &element, XMLLoaderObject &status)
828 {
829 debugPlanXml<<"schedule-manager";
830 MainSchedule *sch = 0;
831 if (status.version() <= "0.5") {
832 manager->setUsePert(false);
833 MainSchedule *sch = loadMainSchedule(manager, element, status);
834 if (sch && sch->type() == Schedule::Expected) {
835 sch->setManager(manager);
836 manager->setExpected(sch);
837 } else {
838 delete sch;
839 }
840 return true;
841 }
842 manager->setName(element.attribute("name"));
843 manager->setManagerId(element.attribute("id"));
844 manager->setUsePert(element.attribute("distribution").toInt() == 1);
845 manager->setAllowOverbooking((bool)(element.attribute("overbooking").toInt()));
846 manager->setCheckExternalAppointments((bool)(element.attribute("check-external-appointments").toInt()));
847 manager->setSchedulingDirection((bool)(element.attribute("scheduling-direction").toInt()));
848 manager->setBaselined((bool)(element.attribute("baselined").toInt()));
849 manager->setSchedulerPluginId(element.attribute("scheduler-plugin-id"));
850 manager->setRecalculate((bool)(element.attribute("recalculate").toInt()));
851 manager->setRecalculateFrom(DateTime::fromString(element.attribute("recalculate-from"), status.projectTimeZone()));
852 KoXmlNode n = element.firstChild();
853 for (; ! n.isNull(); n = n.nextSibling()) {
854 if (! n.isElement()) {
855 continue;
856 }
857 KoXmlElement e = n.toElement();
858 //debugPlanXml<<e.tagName();
859 if (e.tagName() == "schedule") {
860 sch = loadMainSchedule(manager, e, status);
861 if (sch && sch->type() == Schedule::Expected) {
862 sch->setManager(manager);
863 manager->setExpected(sch); break;
864 } else {
865 delete sch;
866 }
867 } else if (e.tagName() == "plan") {
868 ScheduleManager *sm = new ScheduleManager(status.project());
869 if (load(sm, e, status)) {
870 status.project().addScheduleManager(sm, manager);
871 } else {
872 errorPlanXml<<"Failed to load schedule manager";
873 delete sm;
874 }
875 }
876 }
877 return true;
878 }
879
load(Schedule * schedule,const KoXmlElement & element,XMLLoaderObject &)880 bool KPlatoXmlLoaderBase::load(Schedule *schedule, const KoXmlElement& element, XMLLoaderObject& /*status*/)
881 {
882 debugPlanXml<<"schedule";
883 schedule->setName(element.attribute("name"));
884 schedule->setType(element.attribute("type"));
885 schedule->setId(element.attribute("id").toLong());
886
887 return true;
888 }
889
loadMainSchedule(ScheduleManager *,const KoXmlElement & element,XMLLoaderObject & status)890 MainSchedule* KPlatoXmlLoaderBase::loadMainSchedule(ScheduleManager* /*manager*/, const KoXmlElement& element, XMLLoaderObject& status)
891 {
892 debugPlanXml<<"main-schedule";
893 MainSchedule *sch = new MainSchedule();
894 if (loadMainSchedule(sch, element, status)) {
895 status.project().addSchedule(sch);
896 sch->setNode(&(status.project()));
897 status.project().setParentSchedule(sch);
898 // If it's here, it's scheduled!
899 sch->setScheduled(true);
900 } else {
901 errorPlanXml << "Failed to load schedule";
902 delete sch;
903 sch = 0;
904 }
905 return sch;
906 }
907
loadMainSchedule(MainSchedule * ms,const KoXmlElement & element,XMLLoaderObject & status)908 bool KPlatoXmlLoaderBase::loadMainSchedule(MainSchedule *ms, const KoXmlElement &element, XMLLoaderObject &status)
909 {
910 debugPlanXml;
911 QString s;
912 load(ms, element, status);
913
914 s = element.attribute("start");
915 if (!s.isEmpty()) {
916 ms->startTime = DateTime::fromString(s, status.projectTimeZone());
917 }
918 s = element.attribute("end");
919 if (!s.isEmpty()) {
920 ms->endTime = DateTime::fromString(s, status.projectTimeZone());
921 }
922 ms->duration = Duration::fromString(element.attribute("duration"));
923 ms->constraintError = element.attribute("scheduling-conflict", "0").toInt();
924
925 KoXmlNode n = element.firstChild();
926 for (; ! n.isNull(); n = n.nextSibling()) {
927 if (! n.isElement()) {
928 continue;
929 }
930 KoXmlElement el = n.toElement();
931 if (el.tagName() == "appointment") {
932 // Load the appointments.
933 // Resources and tasks must already be loaded
934 Appointment * child = new Appointment();
935 if (! load(child, el, status, *ms)) {
936 // TODO: Complain about this
937 errorPlanXml << "Failed to load appointment" << endl;
938 delete child;
939 }
940 } else if (el.tagName() == "criticalpath-list") {
941 // Tasks must already be loaded
942 for (KoXmlNode n1 = el.firstChild(); ! n1.isNull(); n1 = n1.nextSibling()) {
943 if (! n1.isElement()) {
944 continue;
945 }
946 KoXmlElement e1 = n1.toElement();
947 if (e1.tagName() != "criticalpath") {
948 continue;
949 }
950 QList<Node*> lst;
951 for (KoXmlNode n2 = e1.firstChild(); ! n2.isNull(); n2 = n2.nextSibling()) {
952 if (! n2.isElement()) {
953 continue;
954 }
955 KoXmlElement e2 = n2.toElement();
956 if (e2.tagName() != "node") {
957 continue;
958 }
959 QString s = e2.attribute("id");
960 Node *node = status.project().findNode(s);
961 if (node) {
962 lst.append(node);
963 } else {
964 errorPlanXml<<"Failed to find node id="<<s;
965 }
966 }
967 ms->m_pathlists.append(lst);
968 }
969 ms->criticalPathListCached = true;
970 }
971 }
972 return true;
973 }
974
loadNodeSchedule(NodeSchedule * schedule,const KoXmlElement & element,XMLLoaderObject & status)975 bool KPlatoXmlLoaderBase::loadNodeSchedule(NodeSchedule* schedule, const KoXmlElement &element, XMLLoaderObject& status)
976 {
977 debugPlanXml<<"node-schedule";
978 QString s;
979 load(schedule, element, status);
980 s = element.attribute("earlystart");
981 if (s.isEmpty()) { // try version < 0.6
982 s = element.attribute("earlieststart");
983 }
984 if (! s.isEmpty()) {
985 schedule->earlyStart = DateTime::fromString(s, status.projectTimeZone());
986 }
987 s = element.attribute("latefinish");
988 if (s.isEmpty()) { // try version < 0.6
989 s = element.attribute("latestfinish");
990 }
991 if (! s.isEmpty()) {
992 schedule->lateFinish = DateTime::fromString(s, status.projectTimeZone());
993 }
994 s = element.attribute("latestart");
995 if (! s.isEmpty()) {
996 schedule->lateStart = DateTime::fromString(s, status.projectTimeZone());
997 }
998 s = element.attribute("earlyfinish");
999 if (! s.isEmpty()) {
1000 schedule->earlyFinish = DateTime::fromString(s, status.projectTimeZone());
1001 }
1002 s = element.attribute("start");
1003 if (! s.isEmpty())
1004 schedule->startTime = DateTime::fromString(s, status.projectTimeZone());
1005 s = element.attribute("end");
1006 if (!s.isEmpty())
1007 schedule->endTime = DateTime::fromString(s, status.projectTimeZone());
1008 s = element.attribute("start-work");
1009 if (!s.isEmpty())
1010 schedule->workStartTime = DateTime::fromString(s, status.projectTimeZone());
1011 s = element.attribute("end-work");
1012 if (!s.isEmpty())
1013 schedule->workEndTime = DateTime::fromString(s, status.projectTimeZone());
1014 schedule->duration = Duration::fromString(element.attribute("duration"));
1015
1016 schedule->inCriticalPath = element.attribute("in-critical-path", "0").toInt();
1017 schedule->resourceError = element.attribute("resource-error", "0").toInt();
1018 schedule->resourceOverbooked = element.attribute("resource-overbooked", "0").toInt();
1019 schedule->resourceNotAvailable = element.attribute("resource-not-available", "0").toInt();
1020 schedule->constraintError = element.attribute("scheduling-conflict", "0").toInt();
1021 schedule->notScheduled = element.attribute("not-scheduled", "1").toInt();
1022
1023 schedule->positiveFloat = Duration::fromString(element.attribute("positive-float"));
1024 schedule->negativeFloat = Duration::fromString(element.attribute("negative-float"));
1025 schedule->freeFloat = Duration::fromString(element.attribute("free-float"));
1026
1027 return true;
1028 }
1029
load(WBSDefinition & def,const KoXmlElement & element,XMLLoaderObject &)1030 bool KPlatoXmlLoaderBase::load(WBSDefinition &def, const KoXmlElement &element, XMLLoaderObject &/*status*/)
1031 {
1032 debugPlanXml<<"wbs-def";
1033 def.setProjectCode(element.attribute("project-code"));
1034 def.setProjectSeparator(element.attribute("project-separator"));
1035 def.setLevelsDefEnabled((bool)element.attribute("levels-enabled", "0").toInt());
1036 KoXmlNode n = element.firstChild();
1037 for (; ! n.isNull(); n = n.nextSibling()) {
1038 if (! n.isElement()) {
1039 continue;
1040 }
1041 KoXmlElement e = n.toElement();
1042 if (e.tagName() == "default") {
1043 def.defaultDef().code = e.attribute("code", "Number");
1044 def.defaultDef().separator = e.attribute("separator", ".");
1045 } else if (e.tagName() == "levels") {
1046 KoXmlNode n = e.firstChild();
1047 for (; ! n.isNull(); n = n.nextSibling()) {
1048 if (! n.isElement()) {
1049 continue;
1050 }
1051 KoXmlElement el = n.toElement();
1052 WBSDefinition::CodeDef d;
1053 d.code = el.attribute("code");
1054 d.separator = el.attribute("separator");
1055 int lvl = el.attribute("level", "-1").toInt();
1056 if (lvl >= 0) {
1057 def.setLevelsDef(lvl, d);
1058 } else errorPlanXml<<"Invalid levels definition";
1059 }
1060 }
1061 }
1062 return true;
1063 }
1064
load(Documents & documents,const KoXmlElement & element,XMLLoaderObject & status)1065 bool KPlatoXmlLoaderBase::load(Documents &documents, const KoXmlElement &element, XMLLoaderObject &status)
1066 {
1067 debugPlanXml<<"documents";
1068 KoXmlNode n = element.firstChild();
1069 for (; ! n.isNull(); n = n.nextSibling()) {
1070 if (! n.isElement()) {
1071 continue;
1072 }
1073 KoXmlElement e = n.toElement();
1074 if (e.tagName() == "document") {
1075 Document *doc = new Document();
1076 if (! load(doc, e, status)) {
1077 warnPlanXml<<"Failed to load document";
1078 status.addMsg(XMLLoaderObject::Errors, "Failed to load document");
1079 delete doc;
1080 } else {
1081 documents.addDocument(doc);
1082 status.addMsg(i18n("Document loaded, URL=%1", doc->url().url()));
1083 }
1084 }
1085 }
1086 return true;
1087 }
1088
load(Document * document,const KoXmlElement & element,XMLLoaderObject & status)1089 bool KPlatoXmlLoaderBase::load(Document *document, const KoXmlElement &element, XMLLoaderObject &status)
1090 {
1091 debugPlanXml<<"document";
1092 Q_UNUSED(status);
1093 document->setUrl(QUrl(element.attribute("url")));
1094 document->setType((Document::Type)(element.attribute("type").toInt()));
1095 document->setStatus(element.attribute("status"));
1096 document->setSendAs((Document::SendAs)(element.attribute("sendas").toInt()));
1097 return true;
1098 }
1099
load(Estimate * estimate,const KoXmlElement & element,XMLLoaderObject & status)1100 bool KPlatoXmlLoaderBase::load(Estimate* estimate, const KoXmlElement& element, XMLLoaderObject& status)
1101 {
1102 debugPlanXml<<"estimate";
1103 estimate->setType(element.attribute("type"));
1104 estimate->setRisktype(element.attribute("risk"));
1105 if (status.version() <= "0.6") {
1106 estimate->setUnit((Duration::Unit)(element.attribute("display-unit", QString().number(Duration::Unit_h)).toInt()));
1107 QList<qint64> s = status.project().standardWorktime()->scales();
1108 estimate->setExpectedEstimate(Estimate::scale(Duration::fromString(element.attribute("expected")), estimate->unit(), s));
1109 estimate->setOptimisticEstimate(Estimate::scale(Duration::fromString(element.attribute("optimistic")), estimate->unit(), s));
1110 estimate->setPessimisticEstimate(Estimate::scale(Duration::fromString(element.attribute("pessimistic")), estimate->unit(), s));
1111 } else {
1112 if (status.version() <= "0.6.2") {
1113 // 0 pos in unit is now Unit_Y, so add 3 to get the correct new unit
1114 estimate->setUnit((Duration::Unit)(element.attribute("unit", QString().number(Duration::Unit_ms - 3)).toInt() + 3));
1115 } else {
1116 estimate->setUnit(Duration::unitFromString(element.attribute("unit")));
1117 }
1118 estimate->setExpectedEstimate(element.attribute("expected", "0.0").toDouble());
1119 estimate->setOptimisticEstimate(element.attribute("optimistic", "0.0").toDouble());
1120 estimate->setPessimisticEstimate(element.attribute("pessimistic", "0.0").toDouble());
1121
1122 estimate->setCalendar(status.project().findCalendar(element.attribute("calendar-id")));
1123 }
1124 return true;
1125 }
1126
load(ResourceGroupRequest * gr,const KoXmlElement & element,XMLLoaderObject & status)1127 bool KPlatoXmlLoaderBase::load(ResourceGroupRequest* gr, const KoXmlElement& element, XMLLoaderObject& status)
1128 {
1129 debugPlanXml<<"resourcegroup-request";
1130 gr->setGroup(status.project().findResourceGroup(element.attribute("group-id")));
1131 if (gr->group() == 0) {
1132 errorPlanXml<<"The referenced resource group does not exist: group id="<<element.attribute("group-id");
1133 return false;
1134 }
1135 gr->group()->registerRequest(gr);
1136
1137
1138 KoXmlNode n = element.firstChild();
1139 for (; ! n.isNull(); n = n.nextSibling()) {
1140 if (! n.isElement()) {
1141 continue;
1142 }
1143 KoXmlElement e = n.toElement();
1144 if (e.tagName() == "resource-request") {
1145 ResourceRequest *r = new ResourceRequest();
1146 if (load(r, e, status)) {
1147 gr->addResourceRequest(r);
1148 } else {
1149 errorPlanXml<<"Failed to load resource request";
1150 delete r;
1151 }
1152 }
1153 }
1154 // meaning of m_units changed
1155 int x = element.attribute("units").toInt() -gr->count();
1156 gr->setUnits(x > 0 ? x : 0);
1157
1158 return true;
1159 }
1160
load(ResourceRequest * rr,const KoXmlElement & element,XMLLoaderObject & status)1161 bool KPlatoXmlLoaderBase::load(ResourceRequest *rr, const KoXmlElement& element, XMLLoaderObject& status)
1162 {
1163 debugPlanXml<<"resource-request";
1164 rr->setResource(status.project().resource(element.attribute("resource-id")));
1165 if (rr->resource() == 0) {
1166 warnPlanXml<<"The referenced resource does not exist: resource id="<<element.attribute("resource-id");
1167 return false;
1168 }
1169 rr->setUnits(element.attribute("units").toInt());
1170
1171 KoXmlElement parent = element.namedItem("required-resources").toElement();
1172 KoXmlElement e;
1173 QList<Resource*> required;
1174 forEachElement(e, parent) {
1175 if (e.nodeName() == "resource") {
1176 QString id = e.attribute("id");
1177 if (id.isEmpty()) {
1178 errorPlanXml<<"Missing project id";
1179 continue;
1180 }
1181 Resource *r = status.project().resource(id);
1182 if (r == 0) {
1183 warnPlanXml<<"The referenced resource does not exist: resource id="<<element.attribute("resource-id");
1184 } else {
1185 if (r != rr->resource()) {
1186 required << r;
1187 }
1188 }
1189 }
1190 }
1191 rr->setRequiredResources(required);
1192 return true;
1193
1194 }
1195
load(WorkPackage & wp,const KoXmlElement & element,XMLLoaderObject & status)1196 bool KPlatoXmlLoaderBase::load(WorkPackage &wp, const KoXmlElement& element, XMLLoaderObject& status)
1197 {
1198 debugPlanXml<<"workpackage";
1199 Q_UNUSED(status);
1200 wp.setOwnerName(element.attribute("owner"));
1201 wp.setOwnerId(element.attribute("owner-id"));
1202 return true;
1203 }
1204
loadWpLog(WorkPackage * wp,KoXmlElement & element,XMLLoaderObject & status)1205 bool KPlatoXmlLoaderBase::loadWpLog(WorkPackage *wp, KoXmlElement& element, XMLLoaderObject& status)
1206 {
1207 debugPlanXml<<"wplog";
1208 wp->setOwnerName(element.attribute("owner"));
1209 wp->setOwnerId(element.attribute("owner-id"));
1210 wp->setTransmitionStatus(wp->transmitionStatusFromString(element.attribute("status")));
1211 wp->setTransmitionTime(DateTime(QDateTime::fromString(element.attribute("time"), Qt::ISODate)));
1212 return load(wp->completion(), element, status);
1213 }
1214
load(Completion & completion,const KoXmlElement & element,XMLLoaderObject & status)1215 bool KPlatoXmlLoaderBase::load(Completion &completion, const KoXmlElement& element, XMLLoaderObject& status)
1216 {
1217 debugPlanXml<<"completion";
1218 QString s;
1219 completion.setStarted((bool)element.attribute("started", "0").toInt());
1220 completion.setFinished((bool)element.attribute("finished", "0").toInt());
1221 s = element.attribute("startTime");
1222 if (!s.isEmpty()) {
1223 completion.setStartTime(DateTime::fromString(s, status.projectTimeZone()));
1224 }
1225 s = element.attribute("finishTime");
1226 if (!s.isEmpty()) {
1227 completion.setFinishTime(DateTime::fromString(s, status.projectTimeZone()));
1228 }
1229 completion.setEntrymode(element.attribute("entrymode"));
1230 if (status.version() < "0.6") {
1231 if (completion.isStarted()) {
1232 Completion::Entry *entry = new Completion::Entry(element.attribute("percent-finished", "0").toInt(), Duration::fromString(element.attribute("remaining-effort")), Duration::fromString(element.attribute("performed-effort")));
1233 entry->note = element.attribute("note");
1234 QDate date = completion.startTime().date();
1235 if (completion.isFinished()) {
1236 date = completion.finishTime().date();
1237 }
1238 // almost the best we can do ;)
1239 completion.addEntry(date, entry);
1240 }
1241 } else {
1242 KoXmlElement e;
1243 forEachElement(e, element) {
1244 if (e.tagName() == "completion-entry") {
1245 QDate date;
1246 s = e.attribute("date");
1247 if (!s.isEmpty()) {
1248 date = QDate::fromString(s, Qt::ISODate);
1249 }
1250 if (!date.isValid()) {
1251 warnPlanXml<<"Invalid date: "<<date<<s;
1252 continue;
1253 }
1254 Completion::Entry *entry = new Completion::Entry(e.attribute("percent-finished", "0").toInt(), Duration::fromString(e.attribute("remaining-effort")), Duration::fromString(e.attribute("performed-effort")));
1255 completion.addEntry(date, entry);
1256 } else if (e.tagName() == "used-effort") {
1257 KoXmlElement el;
1258 forEachElement(el, e) {
1259 if (el.tagName() == "resource") {
1260 QString id = el.attribute("id");
1261 Resource *r = status.project().resource(id);
1262 if (r == 0) {
1263 warnPlanXml<<"Cannot find resource, id="<<id;
1264 continue;
1265 }
1266 Completion::UsedEffort *ue = new Completion::UsedEffort();
1267 completion.addUsedEffort(r, ue);
1268 load(ue, el, status);
1269 }
1270 }
1271 }
1272 }
1273 }
1274 return true;
1275 }
1276
load(Completion::UsedEffort * ue,const KoXmlElement & element,XMLLoaderObject &)1277 bool KPlatoXmlLoaderBase::load(Completion::UsedEffort* ue, const KoXmlElement& element, XMLLoaderObject& /*status*/)
1278 {
1279 debugPlanXml<<"used-effort";
1280 KoXmlElement e;
1281 forEachElement(e, element) {
1282 if (e.tagName() == "actual-effort") {
1283 QDate date = QDate::fromString(e.attribute("date"), Qt::ISODate);
1284 if (date.isValid()) {
1285 Completion::UsedEffort::ActualEffort a;
1286 a.setNormalEffort(Duration::fromString(e.attribute("normal-effort")));
1287 a.setOvertimeEffort(Duration::fromString(e.attribute("overtime-effort")));
1288 ue->setEffort(date, a);
1289 }
1290 }
1291 }
1292 return true;
1293 }
1294
load(Appointment * appointment,const KoXmlElement & element,XMLLoaderObject & status,Schedule & sch)1295 bool KPlatoXmlLoaderBase::load(Appointment *appointment, const KoXmlElement& element, XMLLoaderObject& status, Schedule &sch)
1296 {
1297 debugPlanXml<<"appointment";
1298 Node *node = status.project().findNode(element.attribute("task-id"));
1299 if (node == 0) {
1300 errorPlanXml<<"The referenced task does not exists: "<<element.attribute("task-id");
1301 return false;
1302 }
1303 Resource *res = status.project().resource(element.attribute("resource-id"));
1304 if (res == 0) {
1305 errorPlanXml<<"The referenced resource does not exists: resource id="<<element.attribute("resource-id");
1306 return false;
1307 }
1308 if (!res->addAppointment(appointment, sch)) {
1309 errorPlanXml<<"Failed to add appointment to resource: "<<res->name();
1310 return false;
1311 }
1312 if (! node->addAppointment(appointment, sch)) {
1313 errorPlanXml<<"Failed to add appointment to node: "<<node->name();
1314 appointment->resource()->takeAppointment(appointment);
1315 return false;
1316 }
1317 //debugPlanXml<<"res="<<m_resource<<" node="<<m_node;
1318 AppointmentIntervalList lst = appointment->intervals();
1319 load(lst, element, status);
1320 if (lst.isEmpty()) {
1321 errorPlanXml<<"Appointment interval list is empty (added anyway): "<<node->name()<<res->name();
1322 return false;
1323 }
1324 appointment->setIntervals(lst);
1325 return true;
1326 }
1327
load(AppointmentIntervalList & lst,const KoXmlElement & element,XMLLoaderObject & status)1328 bool KPlatoXmlLoaderBase::load(AppointmentIntervalList& lst, const KoXmlElement& element, XMLLoaderObject& status)
1329 {
1330 debugPlanXml<<"appointment-interval-list";
1331 KoXmlElement e;
1332 forEachElement(e, element) {
1333 if (e.tagName() == "interval") {
1334 AppointmentInterval a;
1335 if (load(a, e, status)) {
1336 lst.add(a);
1337 } else {
1338 errorPlanXml<<"Could not load interval";
1339 }
1340 }
1341 }
1342 return true;
1343 }
1344
load(AppointmentInterval & interval,const KoXmlElement & element,XMLLoaderObject & status)1345 bool KPlatoXmlLoaderBase::load(AppointmentInterval& interval, const KoXmlElement& element, XMLLoaderObject& status)
1346 {
1347 bool ok;
1348 QString s = element.attribute("start");
1349 if (!s.isEmpty()) {
1350 interval.setStartTime(DateTime::fromString(s, status.projectTimeZone()));
1351 }
1352 s = element.attribute("end");
1353 if (!s.isEmpty()) {
1354 interval.setEndTime(DateTime::fromString(s, status.projectTimeZone()));
1355 }
1356 double l = element.attribute("load", "100").toDouble(&ok);
1357 if (ok) {
1358 interval.setLoad(l);
1359 }
1360 debugPlanXml<<"interval:"<<interval;
1361 return interval.isValid();
1362 }
1363