1 /* This file is part of the KDE project
2 * Copyright (C) 2005 - 2011, 2012 Dag Andersen <danders@get2net.dk>
3 * Copyright (C) 2016 Dag Andersen <danders@get2net.dk>
4 * Copyright (C) 2019 Dag Andersen <danders@get2net.dk>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 // clazy:excludeall=qstring-arg
23 #include "kptschedule.h"
24
25 #include "kptappointment.h"
26 #include "kptdatetime.h"
27 #include "kptduration.h"
28 #include "kptnode.h"
29 #include "kptproject.h"
30 #include "kpttask.h"
31 #include "kptxmlloaderobject.h"
32 #include "kptschedulerplugin.h"
33 #include "kptdebug.h"
34
35 #include <KoXmlReader.h>
36
37 #include <KLocalizedString>
38
39 #include <QStringList>
40
41
42 namespace KPlato
43 {
44
45 class ScheduleManager;
46
Log(const Node * n,int sev,const QString & msg,int ph)47 Schedule::Log::Log(const Node *n, int sev, const QString &msg, int ph)
48 : node(n), resource(0), message(msg), severity(sev), phase(ph)
49 {
50 Q_ASSERT(n);
51 // debugPlan<<*this<<nodeId;
52 }
53
Log(const Node * n,const Resource * r,int sev,const QString & msg,int ph)54 Schedule::Log::Log(const Node *n, const Resource *r, int sev, const QString &msg, int ph)
55 : node(n), resource(r), message(msg), severity(sev), phase(ph)
56 {
57 Q_ASSERT(r);
58 // debugPlan<<*this<<resourceId;
59 }
60
Log(const Log & other)61 Schedule::Log::Log(const Log &other)
62 {
63 node = other.node;
64 resource = other.resource;
65 message = other.message;
66 severity = other.severity;
67 phase = other.phase;
68 }
69
operator =(const Schedule::Log & other)70 Schedule::Log &Schedule::Log::operator=(const Schedule::Log &other)
71 {
72 node = other.node;
73 resource = other.resource;
74 message = other.message;
75 severity = other.severity;
76 phase = other.phase;
77 return *this;
78 }
79
Schedule()80 Schedule::Schedule()
81 : m_type(Expected),
82 m_id(0),
83 m_deleted(false),
84 m_parent(0),
85 m_obstate(OBS_Parent),
86 m_calculationMode(Schedule::Scheduling),
87 notScheduled(true)
88 {
89 initiateCalculation();
90 }
91
Schedule(Schedule * parent)92 Schedule::Schedule(Schedule *parent)
93 : m_type(Expected),
94 m_id(0),
95 m_deleted(false),
96 m_parent(parent),
97 m_obstate(OBS_Parent),
98 m_calculationMode(Schedule::Scheduling),
99 notScheduled(true)
100 {
101
102 if (parent) {
103 m_name = parent->name();
104 m_type = parent->type();
105 m_id = parent->id();
106 }
107 initiateCalculation();
108 //debugPlan<<"("<<this<<") Name: '"<<name<<"' Type="<<type<<" id="<<id;
109 }
110
Schedule(const QString & name,Type type,long id)111 Schedule::Schedule(const QString& name, Type type, long id)
112 : m_name(name),
113 m_type(type),
114 m_id(id),
115 m_deleted(false),
116 m_parent(0),
117 m_obstate(OBS_Parent),
118 m_calculationMode(Schedule::Scheduling),
119 notScheduled(true)
120 {
121 //debugPlan<<"("<<this<<") Name: '"<<name<<"' Type="<<type<<" id="<<id;
122 initiateCalculation();
123 }
124
~Schedule()125 Schedule::~Schedule()
126 {
127 }
128
setParent(Schedule * parent)129 void Schedule::setParent(Schedule *parent)
130 {
131 m_parent = parent;
132 }
133
setDeleted(bool on)134 void Schedule::setDeleted(bool on)
135 {
136 //debugPlan<<"deleted="<<on;
137 m_deleted = on;
138 //changed(this); don't do this!
139 }
140
isDeleted() const141 bool Schedule::isDeleted() const
142 {
143 return m_parent == 0 ? m_deleted : m_parent->isDeleted();
144 }
145
setType(const QString & type)146 void Schedule::setType(const QString& type)
147 {
148 m_type = Expected;
149 if (type == "Expected")
150 m_type = Expected;
151 }
152
typeToString(bool translate) const153 QString Schedule::typeToString(bool translate) const
154 {
155 if (translate) {
156 return i18n("Expected");
157 } else {
158 return "Expected";
159 }
160 }
161
state() const162 QStringList Schedule::state() const
163 {
164 QStringList lst;
165 if (m_deleted)
166 lst << SchedulingState::deleted();
167 if (notScheduled)
168 lst << SchedulingState::notScheduled();
169 if (constraintError)
170 lst << SchedulingState::constraintsNotMet();
171 if (resourceError)
172 lst << SchedulingState::resourceNotAllocated();
173 if (resourceNotAvailable)
174 lst << SchedulingState::resourceNotAvailable();
175 if (resourceOverbooked)
176 lst << SchedulingState::resourceOverbooked();
177 if (effortNotMet)
178 lst << SchedulingState::effortNotMet();
179 if (schedulingError)
180 lst << SchedulingState::schedulingError();
181 if (lst.isEmpty())
182 lst << SchedulingState::scheduled();
183 return lst;
184 }
185
isBaselined() const186 bool Schedule::isBaselined() const
187 {
188 if (m_parent) {
189 return m_parent->isBaselined();
190 }
191 return false;
192 }
193
usePert() const194 bool Schedule::usePert() const
195 {
196 if (m_parent) {
197 return m_parent->usePert();
198 }
199 return false;
200 }
201
setAllowOverbookingState(Schedule::OBState state)202 void Schedule::setAllowOverbookingState(Schedule::OBState state)
203 {
204 m_obstate = state;
205 }
206
allowOverbookingState() const207 Schedule::OBState Schedule::allowOverbookingState() const
208 {
209 return m_obstate;
210 }
211
allowOverbooking() const212 bool Schedule::allowOverbooking() const
213 {
214 if (m_obstate == OBS_Parent && m_parent) {
215 return m_parent->allowOverbooking();
216 }
217 return m_obstate == OBS_Allow;
218 }
219
checkExternalAppointments() const220 bool Schedule::checkExternalAppointments() const
221 {
222 if (m_parent) {
223 return m_parent->checkExternalAppointments();
224 }
225 return false;
226 }
227
setScheduled(bool on)228 void Schedule::setScheduled(bool on)
229 {
230 notScheduled = !on;
231 changed(this);
232 }
233
effort(const DateTimeInterval & interval) const234 Duration Schedule::effort(const DateTimeInterval &interval) const
235 {
236 return interval.second - interval.first;
237 }
238
available(const DateTimeInterval & interval) const239 DateTimeInterval Schedule::available(const DateTimeInterval &interval) const
240 {
241 return DateTimeInterval(interval.first, interval.second);
242 }
243
initiateCalculation()244 void Schedule::initiateCalculation()
245 {
246 resourceError = false;
247 resourceOverbooked = false;
248 resourceNotAvailable = false;
249 constraintError = false;
250 schedulingError = false;
251 inCriticalPath = false;
252 effortNotMet = false;
253 workStartTime = DateTime();
254 workEndTime = DateTime();
255 }
256
calcResourceOverbooked()257 void Schedule::calcResourceOverbooked()
258 {
259 resourceOverbooked = false;
260 foreach(Appointment *a, m_appointments) {
261 if (a->resource() ->isOverbooked(a->startTime(), a->endTime())) {
262 resourceOverbooked = true;
263 break;
264 }
265 }
266 }
267
firstBookedInterval(const DateTimeInterval & interval,const Schedule * node) const268 DateTimeInterval Schedule::firstBookedInterval(const DateTimeInterval &interval, const Schedule *node) const
269 {
270 QList<Appointment*> lst = m_appointments;
271 switch (m_calculationMode) {
272 case CalculateForward: lst = m_forward; break;
273 case CalculateBackward: lst = m_backward; break;
274 default: break;
275 }
276 foreach (Appointment *a, lst) {
277 if (a->node() == node) {
278 AppointmentIntervalList i = a->intervals(interval.first, interval.second);
279 if (i.isEmpty()) {
280 break;
281 }
282 return DateTimeInterval(i.map().values().first().startTime(), i.map().values().first().endTime());
283 }
284 }
285 return DateTimeInterval();
286 }
287
overbookedResources() const288 QStringList Schedule::overbookedResources() const
289 {
290 QStringList rl;
291 foreach(Appointment *a, m_appointments) {
292 if (a->resource() ->isOverbooked(a->startTime(), a->endTime())) {
293 rl += a->resource() ->resource() ->name();
294 }
295 }
296 return rl;
297 }
298
resourceNameList() const299 QStringList Schedule::resourceNameList() const
300 {
301 return QStringList();
302 }
303
resources() const304 QList<Resource*> Schedule::resources() const
305 {
306 return QList<Resource*>();
307 }
308
loadXML(const KoXmlElement & sch,XMLLoaderObject &)309 bool Schedule::loadXML(const KoXmlElement &sch, XMLLoaderObject &)
310 {
311 m_name = sch.attribute("name");
312 setType(sch.attribute("type"));
313 m_id = sch.attribute("id").toLong();
314
315 return true;
316 }
317
saveXML(QDomElement & element) const318 void Schedule::saveXML(QDomElement &element) const
319 {
320 QDomElement sch = element.ownerDocument().createElement("schedule");
321 element.appendChild(sch);
322 saveCommonXML(sch);
323 }
324
saveCommonXML(QDomElement & element) const325 void Schedule::saveCommonXML(QDomElement &element) const
326 {
327 //debugPlan<<m_name<<" save schedule";
328 element.setAttribute("name", m_name);
329 element.setAttribute("type", typeToString());
330 element.setAttribute("id", QString::number(qlonglong(m_id)));
331 }
332
saveAppointments(QDomElement & element) const333 void Schedule::saveAppointments(QDomElement &element) const
334 {
335 //debugPlan;
336 QListIterator<Appointment*> it = m_appointments;
337 while (it.hasNext()) {
338 it.next() ->saveXML(element);
339 }
340 }
341
insertForwardNode(Node * node)342 void Schedule::insertForwardNode(Node *node)
343 {
344 if (m_parent) {
345 m_parent->insertForwardNode(node);
346 }
347 }
348
insertBackwardNode(Node * node)349 void Schedule::insertBackwardNode(Node *node)
350 {
351 if (m_parent) {
352 m_parent->insertBackwardNode(node);
353 }
354 }
355
356 // used (directly) when appointment wants to attach itself again
attach(Appointment * appointment)357 bool Schedule::attach(Appointment *appointment)
358 {
359 int mode = appointment->calculationMode();
360 //debugPlan<<appointment<<mode;
361 if (mode == Scheduling) {
362 if (m_appointments.indexOf(appointment) != -1) {
363 errorPlan << "Appointment already exists" << endl;
364 return false;
365 }
366 m_appointments.append(appointment);
367 //if (resource()) debugPlan<<appointment<<" For resource '"<<resource()->name()<<"'"<<" count="<<m_appointments.count();
368 //if (node()) debugPlan<<"("<<this<<")"<<appointment<<" For node '"<<node()->name()<<"'"<<" count="<<m_appointments.count();
369 return true;
370 }
371 if (mode == CalculateForward) {
372 if (m_forward.indexOf(appointment) != -1) {
373 errorPlan << "Appointment already exists" << endl;
374 return false;
375 }
376 m_forward.append(appointment);
377 //if (resource()) debugPlan<<"For resource '"<<resource()->name()<<"'";
378 //if (node()) debugPlan<<"For node '"<<node()->name()<<"'";
379 return true;
380 }
381 if (mode == CalculateBackward) {
382 if (m_backward.indexOf(appointment) != -1) {
383 errorPlan << "Appointment already exists" << endl;
384 return false;
385 }
386 m_backward.append(appointment);
387 //if (resource()) debugPlan<<"For resource '"<<resource()->name()<<"'";
388 //if (node()) debugPlan<<"For node '"<<node()->name()<<"'";
389 return true;
390 }
391 errorPlan<<"Unknown mode: "<<m_calculationMode<<endl;
392 return false;
393 }
394
395 // used to add new schedules
add(Appointment * appointment)396 bool Schedule::add(Appointment *appointment)
397 {
398 //debugPlan<<this;
399 appointment->setCalculationMode(m_calculationMode);
400 return attach(appointment);
401 }
402
takeAppointment(Appointment * appointment,int mode)403 void Schedule::takeAppointment(Appointment *appointment, int mode)
404 {
405 Q_UNUSED(mode);
406 //debugPlan<<"("<<this<<")"<<mode<<":"<<appointment<<","<<appointment->calculationMode();
407 int i = m_forward.indexOf(appointment);
408 if (i != -1) {
409 m_forward.removeAt(i);
410 Q_ASSERT(mode == CalculateForward);
411 }
412 i = m_backward.indexOf(appointment);
413 if (i != -1) {
414 m_backward.removeAt(i);
415 Q_ASSERT(mode == CalculateBackward);
416 }
417 i = m_appointments.indexOf(appointment);
418 if (i != -1) {
419 m_appointments.removeAt(i);
420 Q_ASSERT(mode == Scheduling);
421 }
422 }
423
findAppointment(Schedule * resource,Schedule * node,int mode)424 Appointment *Schedule::findAppointment(Schedule *resource, Schedule *node, int mode)
425 {
426 //debugPlan<<this<<" ("<<resourceError<<","<<node<<")"<<mode;
427 if (mode == Scheduling) {
428 foreach(Appointment *a, m_appointments) {
429 if (a->node() == node && a->resource() == resource) {
430 return a;
431 }
432 }
433 return 0;
434 } else if (mode == CalculateForward) {
435 foreach(Appointment *a, m_forward) {
436 if (a->node() == node && a->resource() == resource) {
437 return a;
438 }
439 }
440 } else if (mode == CalculateBackward) {
441 foreach(Appointment *a, m_backward) {
442 if (a->node() == node && a->resource() == resource) {
443 Q_ASSERT(mode == CalculateBackward);
444 return a;
445 }
446 }
447 } else {
448 Q_ASSERT(false); // unknown mode
449 }
450 return 0;
451 }
452
appointmentStartTime() const453 DateTime Schedule::appointmentStartTime() const
454 {
455 DateTime dt;
456 foreach (const Appointment *a, m_appointments) {
457 if (! dt.isValid() || dt > a->startTime()) {
458 dt = a->startTime();
459 }
460 }
461 return dt;
462 }
appointmentEndTime() const463 DateTime Schedule::appointmentEndTime() const
464 {
465 DateTime dt;
466 foreach (const Appointment *a, m_appointments) {
467 if (! dt.isValid() || dt > a->endTime()) {
468 dt = a->endTime();
469 }
470 }
471 return dt;
472 }
473
hasAppointments(int which) const474 bool Schedule::hasAppointments(int which) const
475 {
476 if (which == CalculateForward) {
477 return m_forward.isEmpty();
478 } else if (which == CalculateBackward) {
479 return m_backward.isEmpty();
480 }
481 return m_appointments.isEmpty();
482 }
483
appointments(int which) const484 QList<Appointment*> Schedule::appointments(int which) const
485 {
486 if (which == CalculateForward) {
487 return m_forward;
488 } else if (which == CalculateBackward) {
489 return m_backward;
490 }
491 return m_appointments;
492 }
493
appointmentIntervals(int which,const DateTimeInterval & interval) const494 Appointment Schedule::appointmentIntervals(int which, const DateTimeInterval &interval) const
495 {
496 Appointment app;
497 if (which == Schedule::CalculateForward) {
498 //debugPlan<<"list == CalculateForward";
499 foreach (Appointment *a, m_forward) {
500 app += interval.isValid() ? a->extractIntervals(interval) : *a;
501 }
502 return app;
503 } else if (which == Schedule::CalculateBackward) {
504 //debugPlan<<"list == CalculateBackward";
505 foreach (Appointment *a, m_backward) {
506 app += interval.isValid() ? a->extractIntervals(interval) : *a;
507 }
508 //debugPlan<<"list == CalculateBackward:"<<m_backward.count();
509 return app;
510 }
511 foreach (Appointment *a, m_appointments) {
512 app += interval.isValid() ? a->extractIntervals(interval) : *a;
513 }
514 return app;
515 }
516
copyAppointments(Schedule::CalculationMode from,Schedule::CalculationMode to)517 void Schedule::copyAppointments(Schedule::CalculationMode from, Schedule::CalculationMode to)
518 {
519 switch (to) {
520 case Scheduling:
521 m_appointments.clear();
522 switch(from) {
523 case CalculateForward:
524 m_appointments = m_forward;
525 break;
526 case CalculateBackward:
527 m_appointments = m_backward;
528 break;
529 default:
530 break;
531 }
532 break;
533 case CalculateForward: break;
534 case CalculateBackward: break;
535 }
536 }
537
bcwsPrDay(EffortCostCalculationType type) const538 EffortCostMap Schedule::bcwsPrDay(EffortCostCalculationType type) const
539 {
540 return const_cast<Schedule*>(this)->bcwsPrDay(type);
541 }
542
bcwsPrDay(EffortCostCalculationType type)543 EffortCostMap Schedule::bcwsPrDay(EffortCostCalculationType type)
544 {
545 //debugPlan<<m_name<<m_appointments;
546 EffortCostCache &ec = m_bcwsPrDay[ (int)type ];
547 if (! ec.cached) {
548 foreach (Appointment *a, m_appointments) {
549 ec.effortcostmap += a->plannedPrDay(a->startTime().date(), a->endTime().date(), type);
550 }
551 }
552 return ec.effortcostmap;
553 }
554
plannedEffortCostPrDay(const QDate & start,const QDate & end,EffortCostCalculationType type) const555 EffortCostMap Schedule::plannedEffortCostPrDay(const QDate &start, const QDate &end, EffortCostCalculationType type) const
556 {
557 //debugPlan<<m_name<<m_appointments;
558 EffortCostMap ec;
559 QListIterator<Appointment*> it(m_appointments);
560 while (it.hasNext()) {
561 //debugPlan<<m_name;
562 ec += it.next() ->plannedPrDay(start, end, type);
563 }
564 return ec;
565 }
566
plannedEffortCostPrDay(const Resource * resource,const QDate & start,const QDate & end,EffortCostCalculationType type) const567 EffortCostMap Schedule::plannedEffortCostPrDay(const Resource *resource, const QDate &start, const QDate &end, EffortCostCalculationType type) const
568 {
569 //debugPlan<<m_name<<m_appointments;
570 EffortCostMap ec;
571 foreach (Appointment *a, m_appointments) {
572 if (a->resource() && a->resource()->resource() == resource) {
573 ec += a->plannedPrDay(start, end, type);
574 break;
575 }
576 }
577 return ec;
578 }
579
plannedEffort(const Resource * resource,EffortCostCalculationType type) const580 Duration Schedule::plannedEffort(const Resource *resource, EffortCostCalculationType type) const
581 {
582 //debugPlan;
583 Duration eff;
584 QListIterator<Appointment*> it(m_appointments);
585 while (it.hasNext()) {
586 eff += it.next() ->plannedEffort(resource, type);
587 }
588 return eff;
589 }
590
plannedEffort(EffortCostCalculationType type) const591 Duration Schedule::plannedEffort(EffortCostCalculationType type) const
592 {
593 //debugPlan;
594 Duration eff;
595 QListIterator<Appointment*> it(m_appointments);
596 while (it.hasNext()) {
597 eff += it.next() ->plannedEffort(type);
598 }
599 return eff;
600 }
601
plannedEffort(const QDate & date,EffortCostCalculationType type) const602 Duration Schedule::plannedEffort(const QDate &date, EffortCostCalculationType type) const
603 {
604 //debugPlan;
605 Duration eff;
606 QListIterator<Appointment*> it(m_appointments);
607 while (it.hasNext()) {
608 eff += it.next() ->plannedEffort(date, type);
609 }
610 return eff;
611 }
612
plannedEffort(const Resource * resource,const QDate & date,EffortCostCalculationType type) const613 Duration Schedule::plannedEffort(const Resource *resource, const QDate &date, EffortCostCalculationType type) const
614 {
615 //debugPlan;
616 Duration eff;
617 QListIterator<Appointment*> it(m_appointments);
618 while (it.hasNext()) {
619 eff += it.next() ->plannedEffort(resource, date, type);
620 }
621 return eff;
622 }
623
plannedEffortTo(const QDate & date,EffortCostCalculationType type) const624 Duration Schedule::plannedEffortTo(const QDate &date, EffortCostCalculationType type) const
625 {
626 //debugPlan;
627 Duration eff;
628 QListIterator<Appointment*> it(m_appointments);
629 while (it.hasNext()) {
630 eff += it.next() ->plannedEffortTo(date, type);
631 }
632 return eff;
633 }
634
plannedEffortTo(const Resource * resource,const QDate & date,EffortCostCalculationType type) const635 Duration Schedule::plannedEffortTo(const Resource *resource, const QDate &date, EffortCostCalculationType type) const
636 {
637 //debugPlan;
638 Duration eff;
639 QListIterator<Appointment*> it(m_appointments);
640 while (it.hasNext()) {
641 eff += it.next() ->plannedEffortTo(resource, date, type);
642 }
643 return eff;
644 }
645
plannedEffortTo(const QDateTime & time,EffortCostCalculationType type) const646 Duration Schedule::plannedEffortTo(const QDateTime &time, EffortCostCalculationType type) const
647 {
648 //debugPlan;
649 Duration eff;
650 QListIterator<Appointment*> it(m_appointments);
651 while (it.hasNext()) {
652 eff += it.next() ->plannedEffortTo(time, type);
653 }
654 return eff;
655 }
656
plannedCost(EffortCostCalculationType type) const657 EffortCost Schedule::plannedCost(EffortCostCalculationType type) const
658 {
659 //debugPlan;
660 EffortCost c;
661 QListIterator<Appointment*> it(m_appointments);
662 while (it.hasNext()) {
663 c += it.next() ->plannedCost(type);
664 }
665 return c;
666 }
667
plannedCost(const QDate & date,EffortCostCalculationType type) const668 double Schedule::plannedCost(const QDate &date, EffortCostCalculationType type) const
669 {
670 //debugPlan;
671 double c = 0;
672 QListIterator<Appointment*> it(m_appointments);
673 while (it.hasNext()) {
674 c += it.next() ->plannedCost(date, type);
675 }
676 return c;
677 }
678
plannedCostTo(const QDate & date,EffortCostCalculationType type) const679 double Schedule::plannedCostTo(const QDate &date, EffortCostCalculationType type) const
680 {
681 //debugPlan;
682 double c = 0;
683 QListIterator<Appointment*> it(m_appointments);
684 while (it.hasNext()) {
685 c += it.next() ->plannedCostTo(date, type);
686 }
687 return c;
688 }
689
addLog(const Schedule::Log & log)690 void Schedule::addLog(const Schedule::Log &log)
691 {
692 if (m_parent) {
693 m_parent->addLog(log);
694 }
695 }
696
formatMsg() const697 QString Schedule::Log::formatMsg() const
698 {
699 QString s;
700 s += node ? QString("%1 ").arg(node->name(), -8) : "";
701 s += resource ? QString("%1 ").arg(resource->name(), -8) : "";
702 s += message;
703 return s;
704 }
705
clearPerformanceCache()706 void Schedule::clearPerformanceCache()
707 {
708 m_bcwsPrDay.clear();
709 m_bcwpPrDay.clear();
710 m_acwp.clear();
711 }
712
713 //-------------------------------------------------
NodeSchedule()714 NodeSchedule::NodeSchedule()
715 : Schedule(),
716 m_node(0)
717 {
718 //debugPlan<<"("<<this<<")";
719 init();
720 }
721
NodeSchedule(Node * node,const QString & name,Schedule::Type type,long id)722 NodeSchedule::NodeSchedule(Node *node, const QString& name, Schedule::Type type, long id)
723 : Schedule(name, type, id),
724 m_node(node)
725 {
726 //debugPlan<<"node name:"<<node->name();
727 init();
728 }
729
NodeSchedule(Schedule * parent,Node * node)730 NodeSchedule::NodeSchedule(Schedule *parent, Node *node)
731 : Schedule(parent),
732 m_node(node)
733 {
734
735 //debugPlan<<"node name:"<<node->name();
736 init();
737 }
738
~NodeSchedule()739 NodeSchedule::~NodeSchedule()
740 {
741 //debugPlan<<this<<""<<m_appointments.count();
742 while (!m_appointments.isEmpty()) {
743 Appointment *a = m_appointments.takeFirst();
744 a->setNode(0);
745 delete a;
746 }
747 //debugPlan<<"forw"<<m_forward.count();
748 while (!m_forward.isEmpty()) {
749 Appointment *a = m_forward.takeFirst();
750 a->setNode(0);
751 delete a;
752 }
753 //debugPlan<<"backw"<<m_backward.count();
754 while (!m_backward.isEmpty()) {
755 Appointment *a = m_backward.takeFirst();
756 a->setNode(0);
757 delete a;
758 }
759 }
760
init()761 void NodeSchedule::init()
762 {
763 resourceError = false;
764 resourceOverbooked = false;
765 resourceNotAvailable = false;
766 constraintError = false;
767 schedulingError = false;
768 notScheduled = true;
769 inCriticalPath = false;
770 m_calculationMode = Schedule::Scheduling;
771 positiveFloat = Duration::zeroDuration;
772 negativeFloat = Duration::zeroDuration;
773 freeFloat = Duration::zeroDuration;
774 }
775
setDeleted(bool on)776 void NodeSchedule::setDeleted(bool on)
777 {
778 //debugPlan<<"deleted="<<on;
779 m_deleted = on;
780 // set deleted also for possible resource schedules
781 QListIterator<Appointment*> it = m_appointments;
782 while (it.hasNext()) {
783 Appointment * a = it.next();
784 if (a->resource()) {
785 a->resource() ->setDeleted(on);
786 }
787 }
788 }
789
loadXML(const KoXmlElement & sch,XMLLoaderObject & status)790 bool NodeSchedule::loadXML(const KoXmlElement &sch, XMLLoaderObject &status)
791 {
792 //debugPlan;
793 QString s;
794 Schedule::loadXML(sch, status);
795 s = sch.attribute("earlystart");
796 if (s.isEmpty()) { // try version < 0.6
797 s = sch.attribute("earlieststart");
798 }
799 if (!s.isEmpty()) {
800 earlyStart = DateTime::fromString(s, status.projectTimeZone());
801 }
802 s = sch.attribute("latefinish");
803 if (s.isEmpty()) { // try version < 0.6
804 s = sch.attribute("latestfinish");
805 }
806 if (!s.isEmpty()) {
807 lateFinish = DateTime::fromString(s, status.projectTimeZone());
808 }
809 s = sch.attribute("latestart");
810 if (!s.isEmpty()) {
811 lateStart = DateTime::fromString(s, status.projectTimeZone());
812 }
813 s = sch.attribute("earlyfinish");
814 if (!s.isEmpty()) {
815 earlyFinish = DateTime::fromString(s, status.projectTimeZone());
816 }
817 s = sch.attribute("start");
818 if (!s.isEmpty())
819 startTime = DateTime::fromString(s, status.projectTimeZone());
820 s = sch.attribute("end");
821 if (!s.isEmpty())
822 endTime = DateTime::fromString(s, status.projectTimeZone());
823 s = sch.attribute("start-work");
824 if (!s.isEmpty())
825 workStartTime = DateTime::fromString(s, status.projectTimeZone());
826 s = sch.attribute("end-work");
827 if (!s.isEmpty())
828 workEndTime = DateTime::fromString(s, status.projectTimeZone());
829 duration = Duration::fromString(sch.attribute("duration"));
830
831 inCriticalPath = sch.attribute("in-critical-path", "0").toInt();
832 resourceError = sch.attribute("resource-error", "0").toInt();
833 resourceOverbooked = sch.attribute("resource-overbooked", "0").toInt();
834 resourceNotAvailable = sch.attribute("resource-not-available", "0").toInt();
835 constraintError = sch.attribute("scheduling-conflict", "0").toInt();
836 schedulingError = sch.attribute("scheduling-error", "0").toInt();
837 notScheduled = sch.attribute("not-scheduled", "1").toInt();
838
839 positiveFloat = Duration::fromString(sch.attribute("positive-float"));
840 negativeFloat = Duration::fromString(sch.attribute("negative-float"));
841 freeFloat = Duration::fromString(sch.attribute("free-float"));
842
843 return true;
844 }
845
saveXML(QDomElement & element) const846 void NodeSchedule::saveXML(QDomElement &element) const
847 {
848 //debugPlan;
849 QDomElement sch = element.ownerDocument().createElement("schedule");
850 element.appendChild(sch);
851 saveCommonXML(sch);
852
853 if (earlyStart.isValid()) {
854 sch.setAttribute("earlystart", earlyStart.toString(Qt::ISODate));
855 }
856 if (lateStart.isValid()) {
857 sch.setAttribute("latestart", lateStart.toString(Qt::ISODate));
858 }
859 if (earlyFinish.isValid()) {
860 sch.setAttribute("earlyfinish", earlyFinish.toString(Qt::ISODate));
861 }
862 if (lateFinish.isValid()) {
863 sch.setAttribute("latefinish", lateFinish.toString(Qt::ISODate));
864 }
865 if (startTime.isValid())
866 sch.setAttribute("start", startTime.toString(Qt::ISODate));
867 if (endTime.isValid())
868 sch.setAttribute("end", endTime.toString(Qt::ISODate));
869 if (workStartTime.isValid())
870 sch.setAttribute("start-work", workStartTime.toString(Qt::ISODate));
871 if (workEndTime.isValid())
872 sch.setAttribute("end-work", workEndTime.toString(Qt::ISODate));
873
874 sch.setAttribute("duration", duration.toString());
875
876 sch.setAttribute("in-critical-path", QString::number(inCriticalPath));
877 sch.setAttribute("resource-error", QString::number(resourceError));
878 sch.setAttribute("resource-overbooked", QString::number(resourceOverbooked));
879 sch.setAttribute("resource-not-available", QString::number(resourceNotAvailable));
880 sch.setAttribute("scheduling-conflict", QString::number(constraintError));
881 sch.setAttribute("scheduling-error", QString::number(schedulingError));
882 sch.setAttribute("not-scheduled", QString::number(notScheduled));
883
884 sch.setAttribute("positive-float", positiveFloat.toString());
885 sch.setAttribute("negative-float", negativeFloat.toString());
886 sch.setAttribute("free-float", freeFloat.toString());
887 }
888
addAppointment(Schedule * resource,const DateTime & start,const DateTime & end,double load)889 void NodeSchedule::addAppointment(Schedule *resource, const DateTime &start, const DateTime &end, double load)
890 {
891 //debugPlan;
892 Appointment * a = findAppointment(resource, this, m_calculationMode);
893 if (a != 0) {
894 //debugPlan<<"Add interval to existing"<<a;
895 a->addInterval(start, end, load);
896 return ;
897 }
898 a = new Appointment(resource, this, start, end, load);
899 bool result = add(a);
900 Q_ASSERT (result);
901 result = resource->add(a);
902 Q_ASSERT (result);
903 Q_UNUSED (result); // cheating the compiler in release mode to not warn about unused-but-set-variable
904 //debugPlan<<"Added interval to new"<<a;
905 }
906
takeAppointment(Appointment * appointment,int mode)907 void NodeSchedule::takeAppointment(Appointment *appointment, int mode)
908 {
909 Schedule::takeAppointment(appointment, mode);
910 appointment->setNode(0); // not my appointment anymore
911 //debugPlan<<"Taken:"<<appointment;
912 if (appointment->resource())
913 appointment->resource() ->takeAppointment(appointment);
914 }
915
resources() const916 QList<Resource*> NodeSchedule::resources() const
917 {
918 QList<Resource*> rl;
919 foreach(Appointment *a, m_appointments) {
920 rl += a->resource() ->resource();
921 }
922 return rl;
923 }
924
resourceNameList() const925 QStringList NodeSchedule::resourceNameList() const
926 {
927 QStringList rl;
928 foreach(Appointment *a, m_appointments) {
929 rl += a->resource() ->resource() ->name();
930 }
931 return rl;
932 }
933
logError(const QString & msg,int phase)934 void NodeSchedule::logError(const QString &msg, int phase)
935 {
936 Schedule::Log log(m_node, Log::Type_Error, msg, phase);
937 if (m_parent) {
938 m_parent->addLog(log);
939 } else {
940 addLog(log);
941 }
942 }
943
logWarning(const QString & msg,int phase)944 void NodeSchedule::logWarning(const QString &msg, int phase)
945 {
946 Schedule::Log log(m_node, Log::Type_Warning, msg, phase);
947 if (m_parent) {
948 m_parent->addLog(log);
949 } else {
950 addLog(log);
951 }
952 }
953
logInfo(const QString & msg,int phase)954 void NodeSchedule::logInfo(const QString &msg, int phase)
955 {
956 Schedule::Log log(m_node, Log::Type_Info, msg, phase);
957 if (m_parent) {
958 m_parent->addLog(log);
959 } else {
960 addLog(log);
961 }
962 }
963
logDebug(const QString & msg,int phase)964 void NodeSchedule::logDebug(const QString &msg, int phase)
965 {
966 Schedule::Log log(m_node, Log::Type_Debug, msg, phase);
967 if (m_parent) {
968 m_parent->addLog(log);
969 } else {
970 addLog(log);
971 }
972 }
973
974 //-----------------------------------------------
ResourceSchedule()975 ResourceSchedule::ResourceSchedule()
976 : Schedule(),
977 m_resource(0)
978 {
979 //debugPlan<<"("<<this<<")";
980 }
981
ResourceSchedule(Resource * resource,const QString & name,Schedule::Type type,long id)982 ResourceSchedule::ResourceSchedule(Resource *resource, const QString& name, Schedule::Type type, long id)
983 : Schedule(name, type, id),
984 m_resource(resource),
985 m_parent(0),
986 m_nodeSchedule(0)
987 {
988 //debugPlan<<"resource:"<<resource->name();
989 }
990
ResourceSchedule(Schedule * parent,Resource * resource)991 ResourceSchedule::ResourceSchedule(Schedule *parent, Resource *resource)
992 : Schedule(parent),
993 m_resource(resource),
994 m_parent(parent),
995 m_nodeSchedule(0)
996 {
997 //debugPlan<<"resource:"<<resource->name();
998 }
999
~ResourceSchedule()1000 ResourceSchedule::~ResourceSchedule()
1001 {
1002 //debugPlan<<this<<""<<m_appointments.count();
1003 while (!m_appointments.isEmpty()) {
1004 Appointment *a = m_appointments.takeFirst();
1005 a->setResource(0);
1006 delete a;
1007 }
1008 //debugPlan<<"forw"<<m_forward.count();
1009 while (!m_forward.isEmpty()) {
1010 Appointment *a = m_forward.takeFirst();
1011 a->setResource(0);
1012 delete a;
1013 }
1014 //debugPlan<<"backw"<<m_backward.count();
1015 while (!m_backward.isEmpty()) {
1016 Appointment *a = m_backward.takeFirst();
1017 a->setResource(0);
1018 delete a;
1019 }
1020 }
1021
1022 // called from the resource
addAppointment(Schedule * node,const DateTime & start,const DateTime & end,double load)1023 void ResourceSchedule::addAppointment(Schedule *node, const DateTime &start, const DateTime &end, double load)
1024 {
1025 Q_ASSERT(start < end);
1026 //debugPlan<<"("<<this<<")"<<node<<","<<m_calculationMode;
1027 Appointment * a = findAppointment(this, node, m_calculationMode);
1028 if (a != 0) {
1029 //debugPlan<<"Add interval to existing"<<a;
1030 a->addInterval(start, end, load);
1031 return ;
1032 }
1033 a = new Appointment(this, node, start, end, load);
1034 bool result = add(a);
1035 Q_ASSERT (result == true);
1036 result = node->add(a);
1037 Q_ASSERT (result == true);
1038 Q_UNUSED (result); //don't warn about unused-but-set-variable in release mode
1039 //debugPlan<<"Added interval to new"<<a;
1040 }
1041
takeAppointment(Appointment * appointment,int mode)1042 void ResourceSchedule::takeAppointment(Appointment *appointment, int mode)
1043 {
1044 Schedule::takeAppointment(appointment, mode);
1045 appointment->setResource(0);
1046 //debugPlan<<"Taken:"<<appointment;
1047 if (appointment->node())
1048 appointment->node() ->takeAppointment(appointment);
1049 }
1050
isOverbooked() const1051 bool ResourceSchedule::isOverbooked() const
1052 {
1053 return false;
1054 }
1055
isOverbooked(const DateTime & start,const DateTime & end) const1056 bool ResourceSchedule::isOverbooked(const DateTime &start, const DateTime &end) const
1057 {
1058 if (m_resource == 0)
1059 return false;
1060 //debugPlan<<start.toString()<<" -"<<end.toString();
1061 Appointment a = appointmentIntervals();
1062 foreach (const AppointmentInterval &i, a.intervals().map()) {
1063 if ((!end.isValid() || i.startTime() < end) &&
1064 (!start.isValid() || i.endTime() > start)) {
1065 if (i.load() > m_resource->units()) {
1066 //debugPlan<<m_name<<" overbooked";
1067 return true;
1068 }
1069 }
1070 if (i.startTime() >= end)
1071 break;
1072 }
1073 //debugPlan<<m_name<<" not overbooked";
1074 return false;
1075 }
1076
normalRatePrHour() const1077 double ResourceSchedule::normalRatePrHour() const
1078 {
1079 return m_resource ? m_resource->normalRate() : 0.0;
1080 }
1081
1082 //TODO change to return the booked effort
effort(const DateTimeInterval & interval) const1083 Duration ResourceSchedule::effort(const DateTimeInterval &interval) const
1084 {
1085 Duration eff = interval.second - interval.first;
1086 if (allowOverbooking()) {
1087 return eff;
1088 }
1089 Appointment a;
1090 if (checkExternalAppointments()) {
1091 a.setIntervals(m_resource->externalAppointments());
1092 }
1093 a.merge(appointmentIntervals(m_calculationMode));
1094 if (a.isEmpty() || a.startTime() >= interval.second || a.endTime() <= interval.first) {
1095 return eff;
1096 }
1097 foreach (const AppointmentInterval &i, a.intervals().map()) {
1098 if (interval.second <= i.startTime()) {
1099 break;
1100 }
1101 if (interval.first >= i.startTime()) {
1102 DateTime et = i.endTime() < interval.second ? i.endTime() : interval.second;
1103 eff -= (et - interval.first) * ((double)i.load()/100.0);
1104 } else {
1105 DateTime et = i.endTime() < interval.second ? i.endTime() : interval.second;
1106 eff -= (et - i.startTime()) * ((double)i.load()/100.0);
1107 }
1108 }
1109 return eff;
1110 }
1111
available(const DateTimeInterval & interval) const1112 DateTimeInterval ResourceSchedule::available(const DateTimeInterval &interval) const
1113 {
1114 //const_cast<ResourceSchedule*>(this)->logDebug(QString("Schedule available id=%1, Mode=%2: interval=%3 - %4").arg(m_id).arg(m_calculationMode).arg(interval.first.toString()).arg(interval.second.toString()));
1115 if (allowOverbooking()) {
1116 return DateTimeInterval(interval.first, interval.second);
1117 }
1118 QTimeZone projectTimeZone = QTimeZone::systemTimeZone();
1119 if (m_resource) {
1120 projectTimeZone = m_resource->project()->timeZone();
1121 }
1122 DateTimeInterval ci(interval.first.toTimeZone(projectTimeZone), interval.second.toTimeZone(projectTimeZone));
1123 Appointment a;
1124 if (checkExternalAppointments()) {
1125 a.setIntervals(m_resource->externalAppointments(ci));
1126 }
1127 a.merge(appointmentIntervals(m_calculationMode, ci));
1128 if (a.isEmpty() || a.startTime() >= ci.second || a.endTime() <= ci.first) {
1129 //debugPlan<<this<<"id="<<m_id<<"Mode="<<m_calculationMode<<""<<interval.first<<","<<interval.second<<" FREE";
1130 return DateTimeInterval(interval.first, interval.second); // just return the interval
1131 }
1132 //debugPlan<<"available:"<<interval<<endl<<a.intervals();
1133 DateTimeInterval res;
1134 int units = m_resource ? m_resource->units() : 100;
1135 foreach (const AppointmentInterval &i, a.intervals().map()) {
1136 //const_cast<ResourceSchedule*>(this)->logDebug(QString("Schedule available check interval=%1 - %2").arg(i.startTime().toString()).arg(i.endTime().toString()));
1137 if (i.startTime() < ci.second && i.endTime() > ci.first) {
1138 // interval intersects appointment
1139 if (ci.first >= i.startTime() && ci.second <= i.endTime()) {
1140 // interval within appointment
1141 if (i.load() < units) {
1142 if (! res.first.isValid()) {
1143 res.first = qMax(ci.first, i.startTime());
1144 }
1145 res.second = qMin(ci.second, i.endTime());
1146 } else {
1147 // fully booked
1148 if (res.first.isValid()) {
1149 res.second = i.startTime();
1150 if (res.first >= res.second) {
1151 res = DateTimeInterval();
1152 }
1153 }
1154 }
1155 //debugPlan<<"available within:"<<interval<<i<<":"<<ci<<res;
1156 break;
1157 }
1158 DateTime t = i.startTime();
1159 if (ci.first < t) {
1160 // Interval starts before appointment, so free from interval start
1161 //debugPlan<<"available before:"<<interval<<i<<":"<<ci<<res;
1162 //const_cast<ResourceSchedule*>(this)->logDebug(QString("Schedule available t>first: returns interval=%1 - %2").arg(ci.first.toString()).arg(t.toString()));
1163 if (! res.first.isValid()) {
1164 res.first = ci.first;
1165 }
1166 res.second = t;
1167 if (i.load() < units) {
1168 res.second = qMin(ci.second, i.endTime());
1169 if (ci.second > i.endTime()) {
1170 ci.first = i.endTime();
1171 //debugPlan<<"available next 1:"<<interval<<i<<":"<<ci<<res;
1172 continue; // check next appointment
1173 }
1174 }
1175 //debugPlan<<"available:"<<interval<<i<<":"<<ci<<res;
1176 break;
1177 }
1178 // interval start >= appointment start
1179 t = i.endTime();
1180 if (t < ci.second) {
1181 // check if rest of appointment is free
1182 if (units <= i.load()) {
1183 ci.first = t; // fully booked, so move forward to appointment end
1184 }
1185 res = ci;
1186 //debugPlan<<"available next 2:"<<interval<<i<<":"<<ci<<res;
1187 continue;
1188 }
1189 //debugPlan<<"available:"<<interval<<i<<":"<<ci<<res;
1190 Q_ASSERT(false);
1191 } else if (i.startTime() >= interval.second) {
1192 // no more overlaps
1193 break;
1194 }
1195 }
1196 //debugPlan<<"available: result="<<interval<<":"<<res;
1197 return DateTimeInterval(res.first.toTimeZone(interval.first.timeZone()), res.second.toTimeZone(interval.second.timeZone()));
1198 }
1199
logError(const QString & msg,int phase)1200 void ResourceSchedule::logError(const QString &msg, int phase)
1201 {
1202 if (m_parent) {
1203 Schedule::Log log(m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Error, msg, phase);
1204 m_parent->addLog(log);
1205 }
1206 }
1207
logWarning(const QString & msg,int phase)1208 void ResourceSchedule::logWarning(const QString &msg, int phase)
1209 {
1210 if (m_parent) {
1211 Schedule::Log log(m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Warning, msg, phase);
1212 m_parent->addLog(log);
1213 }
1214 }
1215
logInfo(const QString & msg,int phase)1216 void ResourceSchedule::logInfo(const QString &msg, int phase)
1217 {
1218 if (m_parent) {
1219 Schedule::Log log(m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Info, msg, phase);
1220 m_parent->addLog(log);
1221 }
1222 }
1223
logDebug(const QString & msg,int phase)1224 void ResourceSchedule::logDebug(const QString &msg, int phase)
1225 {
1226 if (m_parent) {
1227 Schedule::Log log(m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Debug, msg, phase);
1228 m_parent->addLog(log);
1229 }
1230 }
1231
1232 //--------------------------------------
MainSchedule()1233 MainSchedule::MainSchedule()
1234 : NodeSchedule(),
1235
1236 m_manager(0)
1237 {
1238 //debugPlan<<"("<<this<<")";
1239 init();
1240 }
1241
MainSchedule(Node * node,const QString & name,Schedule::Type type,long id)1242 MainSchedule::MainSchedule(Node *node, const QString& name, Schedule::Type type, long id)
1243 : NodeSchedule(node, name, type, id),
1244 criticalPathListCached(false),
1245 m_manager(0),
1246 m_currentCriticalPath(0)
1247 {
1248 //debugPlan<<"node name:"<<node->name();
1249 init();
1250 }
1251
~MainSchedule()1252 MainSchedule::~MainSchedule()
1253 {
1254 //debugPlan<<"("<<this<<")";
1255 }
1256
incProgress()1257 void MainSchedule::incProgress()
1258 {
1259 if (m_manager) m_manager->incProgress();
1260 }
1261
isBaselined() const1262 bool MainSchedule::isBaselined() const
1263 {
1264 return m_manager == 0 ? false : m_manager->isBaselined();
1265 }
1266
usePert() const1267 bool MainSchedule::usePert() const
1268 {
1269 return m_manager == 0 ? false : m_manager->usePert();
1270 }
1271
allowOverbooking() const1272 bool MainSchedule::allowOverbooking() const
1273 {
1274 return m_manager == 0 ? false : m_manager->allowOverbooking();
1275 }
1276
checkExternalAppointments() const1277 bool MainSchedule::checkExternalAppointments() const
1278 {
1279 return m_manager == 0 ? false : m_manager->checkExternalAppointments();
1280 }
1281
changed(Schedule * sch)1282 void MainSchedule::changed(Schedule *sch)
1283 {
1284 if (m_manager) {
1285 m_manager->scheduleChanged(static_cast<MainSchedule*>(sch));
1286 }
1287 }
1288
insertHardConstraint(Node * node)1289 void MainSchedule::insertHardConstraint(Node *node)
1290 {
1291 m_hardconstraints.append(node);
1292 }
1293
hardConstraints() const1294 QList<Node*> MainSchedule::hardConstraints() const
1295 {
1296 return m_hardconstraints;
1297 }
1298
insertSoftConstraint(Node * node)1299 void MainSchedule::insertSoftConstraint(Node *node)
1300 {
1301 m_softconstraints.insert(-node->priority(), node);
1302 }
1303
softConstraints() const1304 QList<Node*> MainSchedule::softConstraints() const
1305 {
1306 return m_softconstraints.values();
1307 }
1308
forwardNodes() const1309 QList<Node*> MainSchedule::forwardNodes() const
1310 {
1311 return m_forwardnodes;
1312 }
1313
insertForwardNode(Node * node)1314 void MainSchedule::insertForwardNode(Node *node)
1315 {
1316 m_forwardnodes.append(node);
1317 }
1318
backwardNodes() const1319 QList<Node*> MainSchedule::backwardNodes() const
1320 {
1321 return m_backwardnodes;
1322 }
1323
insertBackwardNode(Node * node)1324 void MainSchedule::insertBackwardNode(Node *node)
1325 {
1326 m_backwardnodes.append(node);
1327 }
1328
insertStartNode(Node * node)1329 void MainSchedule::insertStartNode(Node *node)
1330 {
1331 m_startNodes.insert(-node->priority(), node);
1332 }
1333
startNodes() const1334 QList<Node*> MainSchedule::startNodes() const
1335 {
1336 return m_startNodes.values();
1337 }
1338
insertEndNode(Node * node)1339 void MainSchedule::insertEndNode(Node *node)
1340 {
1341 m_endNodes.insert(-node->priority(), node);
1342 }
1343
endNodes() const1344 QList<Node*> MainSchedule::endNodes() const
1345 {
1346 return m_endNodes.values();
1347 }
1348
insertSummaryTask(Node * node)1349 void MainSchedule::insertSummaryTask(Node *node)
1350 {
1351 m_summarytasks.append(node);
1352 }
1353
summaryTasks() const1354 QList<Node*> MainSchedule::summaryTasks() const
1355 {
1356 return m_summarytasks;
1357 }
1358
loadXML(const KoXmlElement & sch,XMLLoaderObject & status)1359 bool MainSchedule::loadXML(const KoXmlElement &sch, XMLLoaderObject &status)
1360 {
1361 //debugPlan;
1362 QString s;
1363 Schedule::loadXML(sch, status);
1364
1365 s = sch.attribute("start");
1366 if (!s.isEmpty())
1367 startTime = DateTime::fromString(s, status.projectTimeZone());
1368 s = sch.attribute("end");
1369 if (!s.isEmpty())
1370 endTime = DateTime::fromString(s, status.projectTimeZone());
1371
1372 duration = Duration::fromString(sch.attribute("duration"));
1373 constraintError = sch.attribute("scheduling-conflict", "0").toInt();
1374 schedulingError = sch.attribute("scheduling-error", "0").toInt();
1375 //NOTE: we use "scheduled" as default to match old format without "not-scheduled" element
1376 notScheduled = sch.attribute("not-scheduled", "0").toInt();
1377
1378 KoXmlNode n = sch.firstChild();
1379 for (; ! n.isNull(); n = n.nextSibling()) {
1380 if (! n.isElement()) {
1381 continue;
1382 }
1383 KoXmlElement el = n.toElement();
1384 if (el.tagName() == "appointment") {
1385 // Load the appointments.
1386 // Resources and tasks must already be loaded
1387 Appointment * child = new Appointment();
1388 if (!child->loadXML(el, status, *this)) {
1389 // TODO: Complain about this
1390 errorPlan << "Failed to load appointment" << endl;
1391 delete child;
1392 }
1393 } else if (el.tagName() == "criticalpath-list") {
1394 // Tasks must already be loaded
1395 for (KoXmlNode n1 = el.firstChild(); ! n1.isNull(); n1 = n1.nextSibling()) {
1396 if (! n1.isElement()) {
1397 continue;
1398 }
1399 KoXmlElement e1 = n1.toElement();
1400 if (e1.tagName() != "criticalpath") {
1401 continue;
1402 }
1403 QList<Node*> lst;
1404 for (KoXmlNode n2 = e1.firstChild(); ! n2.isNull(); n2 = n2.nextSibling()) {
1405 if (! n2.isElement()) {
1406 continue;
1407 }
1408 KoXmlElement e2 = n2.toElement();
1409 if (e2.tagName() != "node") {
1410 continue;
1411 }
1412 QString s = e2.attribute("id");
1413 Node *node = status.project().findNode(s);
1414 if (node) {
1415 lst.append(node);
1416 } else {
1417 errorPlan<<"Failed to find node id="<<s;
1418 }
1419 }
1420 m_pathlists.append(lst);
1421 }
1422 criticalPathListCached = true;
1423 }
1424 }
1425 return true;
1426 }
1427
saveXML(QDomElement & element) const1428 void MainSchedule::saveXML(QDomElement &element) const
1429 {
1430 saveCommonXML(element);
1431
1432 element.setAttribute("start", startTime.toString(Qt::ISODate));
1433 element.setAttribute("end", endTime.toString(Qt::ISODate));
1434 element.setAttribute("duration", duration.toString());
1435 element.setAttribute("scheduling-conflict", QString::number(constraintError));
1436 element.setAttribute("scheduling-error", QString::number(schedulingError));
1437 element.setAttribute("not-scheduled", QString::number(notScheduled));
1438
1439 if (! m_pathlists.isEmpty()) {
1440 QDomElement lists = element.ownerDocument().createElement("criticalpath-list");
1441 element.appendChild(lists);
1442 foreach (const QList<Node*> &l, m_pathlists) {
1443 if (l.isEmpty()) {
1444 continue;
1445 }
1446 QDomElement list = lists.ownerDocument().createElement("criticalpath");
1447 lists.appendChild(list);
1448 foreach (Node *n, l) {
1449 QDomElement el = list.ownerDocument().createElement("node");
1450 list.appendChild(el);
1451 el.setAttribute("id", n->id());
1452 }
1453 }
1454 }
1455 }
1456
calculateForward(int use)1457 DateTime MainSchedule::calculateForward(int use)
1458 {
1459 DateTime late;
1460 foreach(Node *n, m_backwardnodes) {
1461 DateTime t = n->calculateForward(use);
1462 if (!late.isValid() || late < t) {
1463 late = t;
1464 }
1465 }
1466 return late;
1467 }
1468
calculateBackward(int use)1469 DateTime MainSchedule::calculateBackward(int use)
1470 {
1471 DateTime early;
1472 foreach(Node *n, m_forwardnodes) {
1473 DateTime t = n->calculateBackward(use);
1474 if (!early.isValid() || early > t) {
1475 early = t;
1476 }
1477 }
1478 return early;
1479 }
1480
scheduleForward(const DateTime & earliest,int use)1481 DateTime MainSchedule::scheduleForward(const DateTime &earliest, int use)
1482 {
1483 DateTime end;
1484 foreach(Node *n, m_forwardnodes) {
1485 DateTime t = n->scheduleForward(earliest, use);
1486 if (!end.isValid() || end < t) {
1487 end = t;
1488 }
1489 }
1490 return end;
1491 }
1492
scheduleBackward(const DateTime & latest,int use)1493 DateTime MainSchedule::scheduleBackward(const DateTime &latest, int use)
1494 {
1495 DateTime start;
1496 foreach(Node *n, m_backwardnodes) {
1497 DateTime t = n->scheduleBackward(latest, use);
1498 if (!start.isValid() || start > t) {
1499 start = t;
1500 }
1501 }
1502 return start;
1503 }
1504
recalculate() const1505 bool MainSchedule::recalculate() const
1506 {
1507 return m_manager == 0 ? false : m_manager->recalculate();
1508 }
1509
recalculateFrom() const1510 DateTime MainSchedule::recalculateFrom() const
1511 {
1512 return m_manager == 0 ? DateTime() : m_manager->recalculateFrom();
1513 }
1514
parentScheduleId() const1515 long MainSchedule::parentScheduleId() const
1516 {
1517 return m_manager == 0 ? -2 : m_manager->parentScheduleId();
1518 }
1519
clearCriticalPathList()1520 void MainSchedule::clearCriticalPathList()
1521 {
1522 m_pathlists.clear();
1523 m_currentCriticalPath = 0;
1524 criticalPathListCached = false;
1525 }
1526
currentCriticalPath() const1527 QList<Node*> *MainSchedule::currentCriticalPath() const
1528 {
1529 return m_currentCriticalPath;
1530 }
1531
addCriticalPath(QList<Node * > * lst)1532 void MainSchedule::addCriticalPath(QList<Node*> *lst)
1533 {
1534 QList<Node*> l;
1535 if (lst) {
1536 l = *lst;
1537 }
1538 m_pathlists.append(l);
1539 m_currentCriticalPath = &(m_pathlists.last());
1540 }
1541
addCriticalPathNode(Node * node)1542 void MainSchedule::addCriticalPathNode(Node *node)
1543 {
1544 if (m_currentCriticalPath == 0) {
1545 errorPlan<<"No currentCriticalPath"<<endl;
1546 return;
1547 }
1548 m_currentCriticalPath->append(node);
1549 }
1550
logs() const1551 QVector<Schedule::Log> MainSchedule::logs() const
1552 {
1553 return m_log;
1554 }
1555
addLog(const KPlato::Schedule::Log & log)1556 void MainSchedule::addLog(const KPlato::Schedule::Log &log)
1557 {
1558 Q_ASSERT(log.resource || log.node);
1559 #ifndef NDEBUG
1560 if (log.resource) {
1561 Q_ASSERT(manager()->project().findResource(log.resource->id()) == log.resource);
1562 } else if (log.node) {
1563 Q_ASSERT(manager()->project().findNode(log.node->id()) == log.node);
1564 }
1565 #endif
1566 const int phaseToSet = (log.phase == -1 && ! m_log.isEmpty()) ? m_log.last().phase : -1;
1567 m_log.append(log);
1568
1569 if (phaseToSet != -1) {
1570 m_log.last().phase = phaseToSet;
1571 }
1572 if (m_manager) {
1573 m_manager->logAdded(m_log.last());
1574 }
1575 }
1576
1577 //static
logSeverity(int severity)1578 QString MainSchedule::logSeverity(int severity)
1579 {
1580 switch (severity) {
1581 case Log::Type_Debug: return "Debug";//FIXME i18n("Debug");
1582 case Log::Type_Info: return i18n("Info");
1583 case Log::Type_Warning: return i18n("Warning");
1584 case Log::Type_Error: return i18n("Error");
1585 default: break;
1586 }
1587 return QString("Severity %1").arg(severity);
1588 }
1589
logMessages() const1590 QStringList MainSchedule::logMessages() const
1591 {
1592 QStringList lst;
1593 foreach (const Schedule::Log &l, m_log) {
1594 lst << l.formatMsg();
1595 }
1596 return lst;
1597 }
1598
1599 //-----------------------------------------
ScheduleManager(Project & project,const QString name)1600 ScheduleManager::ScheduleManager(Project &project, const QString name)
1601 : m_project(project),
1602 m_parent(0),
1603 m_name(name),
1604 m_baselined(false),
1605 m_allowOverbooking(false),
1606 m_checkExternalAppointments(true),
1607 m_usePert(false),
1608 m_recalculate(false),
1609 m_schedulingDirection(false),
1610 m_scheduling(false),
1611 m_progress(0),
1612 m_maxprogress(0),
1613 m_expected(nullptr),
1614 m_calculationresult(0),
1615 m_schedulingMode(false)
1616 {
1617 //debugPlan<<name;
1618 }
1619
~ScheduleManager()1620 ScheduleManager::~ScheduleManager()
1621 {
1622 qDeleteAll(m_children);
1623 setParentManager(0);
1624 }
1625
setParentManager(ScheduleManager * sm,int index)1626 void ScheduleManager::setParentManager(ScheduleManager *sm, int index)
1627 {
1628 if (m_parent) {
1629 m_parent->removeChild(this);
1630 }
1631 m_parent = sm;
1632 if (sm) {
1633 sm->insertChild(this, index);
1634 }
1635 }
1636
removeChild(const ScheduleManager * sm)1637 int ScheduleManager::removeChild(const ScheduleManager *sm)
1638 {
1639 int i = m_children.indexOf(const_cast<ScheduleManager*>(sm));
1640 if (i != -1) {
1641 m_children.removeAt(i);
1642 }
1643 return i;
1644 }
1645
insertChild(ScheduleManager * sm,int index)1646 void ScheduleManager::insertChild(ScheduleManager *sm, int index)
1647 {
1648 //debugPlan<<m_name<<", insert"<<sm->name()<<","<<index;
1649 if (index == -1) {
1650 m_children.append(sm);
1651 } else {
1652 m_children.insert(index, sm);
1653 }
1654 }
1655
createSchedules()1656 void ScheduleManager::createSchedules()
1657 {
1658 setExpected(m_project.createSchedule(m_name, Schedule::Expected));
1659 }
1660
indexOf(const ScheduleManager * child) const1661 int ScheduleManager::indexOf(const ScheduleManager *child) const
1662 {
1663 //debugPlan<<this<<","<<child;
1664 return m_children.indexOf(const_cast<ScheduleManager*>(child));
1665 }
1666
findManager(const QString & name) const1667 ScheduleManager *ScheduleManager::findManager(const QString& name) const
1668 {
1669 if (m_name == name) {
1670 return const_cast<ScheduleManager*>(this);
1671 }
1672 foreach (ScheduleManager *sm, m_children) {
1673 ScheduleManager *m = sm->findManager(name);
1674 if (m) {
1675 return m;
1676 }
1677 }
1678 return 0;
1679 }
1680
allChildren() const1681 QList<ScheduleManager*> ScheduleManager::allChildren() const
1682 {
1683 QList<ScheduleManager*> lst;
1684 foreach (ScheduleManager *sm, m_children) {
1685 lst << sm;
1686 lst << sm->allChildren();
1687 }
1688 return lst;
1689 }
1690
isParentOf(const ScheduleManager * sm) const1691 bool ScheduleManager::isParentOf(const ScheduleManager *sm) const
1692 {
1693 if (indexOf(sm) >= 0) {
1694 return true;
1695 }
1696 foreach (ScheduleManager *p, m_children) {
1697 if (p->isParentOf(sm)) {
1698 return true;
1699 }
1700 }
1701 return false;
1702 }
1703
setName(const QString & name)1704 void ScheduleManager::setName(const QString& name)
1705 {
1706 m_name = name;
1707 #ifndef NDEBUG
1708 setObjectName(name);
1709 #endif
1710 if (m_expected) {
1711 m_expected->setName(name);
1712 m_project.changed(m_expected);
1713 }
1714 m_project.changed(this);
1715 }
1716
isChildBaselined() const1717 bool ScheduleManager::isChildBaselined() const
1718 {
1719 //debugPlan<<on;
1720 foreach (ScheduleManager *sm, m_children) {
1721 if (sm->isBaselined() || sm->isChildBaselined()) {
1722 return true;
1723 }
1724 }
1725 return false;
1726 }
1727
setBaselined(bool on)1728 void ScheduleManager::setBaselined(bool on)
1729 {
1730 //debugPlan<<on;
1731 m_baselined = on;
1732 m_project.changed(this);
1733 }
1734
setAllowOverbooking(bool on)1735 void ScheduleManager::setAllowOverbooking(bool on)
1736 {
1737 //debugPlan<<on;
1738 m_allowOverbooking = on;
1739 m_project.changed(this, OverbookProperty);
1740 }
1741
allowOverbooking() const1742 bool ScheduleManager::allowOverbooking() const
1743 {
1744 //debugPlan<<m_name<<"="<<m_allowOverbooking;
1745 return m_allowOverbooking;
1746 }
1747
checkExternalAppointments() const1748 bool ScheduleManager::checkExternalAppointments() const
1749 {
1750 //debugPlan<<m_name<<"="<<m_allowOverbooking;
1751 return m_checkExternalAppointments;
1752 }
1753
setCheckExternalAppointments(bool on)1754 void ScheduleManager::setCheckExternalAppointments(bool on)
1755 {
1756 //debugPlan<<m_name<<"="<<m_checkExternalAppointments;
1757 m_checkExternalAppointments = on;
1758 }
1759
scheduleChanged(MainSchedule * sch)1760 void ScheduleManager::scheduleChanged(MainSchedule *sch)
1761 {
1762 m_project.changed(sch);
1763 m_project.changed(this); //hmmm, due to aggregated info
1764 }
1765
setUsePert(bool on)1766 void ScheduleManager::setUsePert(bool on)
1767 {
1768 m_usePert = on;
1769 m_project.changed(this, DistributionProperty);
1770 }
1771
setSchedulingDirection(bool on)1772 void ScheduleManager::setSchedulingDirection(bool on)
1773 {
1774 //debugPlan<<on;
1775 m_schedulingDirection = on;
1776 m_project.changed(this, DirectionProperty);
1777 }
1778
setScheduling(bool on)1779 void ScheduleManager::setScheduling(bool on)
1780 {
1781 m_scheduling = on;
1782 if (! on) {
1783 m_project.setProgress(0, this);
1784 }
1785 m_project.changed(this);
1786 }
1787
schedulerPlugins() const1788 const QList<SchedulerPlugin*> ScheduleManager::schedulerPlugins() const
1789 {
1790 return m_project.schedulerPlugins().values();
1791 }
1792
schedulerPluginId() const1793 QString ScheduleManager::schedulerPluginId() const
1794 {
1795 return m_schedulerPluginId;
1796 }
1797
setSchedulerPluginId(const QString & id)1798 void ScheduleManager::setSchedulerPluginId(const QString &id)
1799 {
1800 m_schedulerPluginId = id;
1801 m_project.changed(this);
1802 }
1803
schedulerPlugin() const1804 SchedulerPlugin *ScheduleManager::schedulerPlugin() const
1805 {
1806 if (m_schedulerPluginId.isEmpty() || !m_project.schedulerPlugins().contains(m_schedulerPluginId)) {
1807 // try to avoid crash
1808 return m_project.schedulerPlugins().value(m_project.schedulerPlugins().keys().value(0));
1809 }
1810 return m_project.schedulerPlugins().value(m_schedulerPluginId);
1811 }
1812
schedulerPluginNames() const1813 QStringList ScheduleManager::schedulerPluginNames() const
1814 {
1815 QStringList lst;
1816 QMap<QString, SchedulerPlugin*>::const_iterator it = m_project.schedulerPlugins().constBegin();
1817 QMap<QString, SchedulerPlugin*>::const_iterator end = m_project.schedulerPlugins().constEnd();
1818 for (; it != end; ++it) {
1819 lst << it.value()->name();
1820 }
1821 return lst;
1822 }
1823
schedulerPluginIndex() const1824 int ScheduleManager::schedulerPluginIndex() const
1825 {
1826 if (m_schedulerPluginId.isEmpty()) {
1827 return 0;
1828 }
1829 return m_project.schedulerPlugins().keys().indexOf(m_schedulerPluginId);
1830 }
1831
setSchedulerPlugin(int index)1832 void ScheduleManager::setSchedulerPlugin(int index)
1833 {
1834 if (schedulerPlugin()) {
1835 schedulerPlugin()->stopCalculation(this); // in case...
1836 }
1837
1838 m_schedulerPluginId = m_project.schedulerPlugins().keys().value(index);
1839 debugPlan<<index<<m_schedulerPluginId;
1840 m_project.changed(this);
1841 }
1842
calculateSchedule()1843 void ScheduleManager::calculateSchedule()
1844 {
1845 m_calculationresult = CalculationRunning;
1846 if (schedulerPlugin()) {
1847 schedulerPlugin()->calculate(m_project, this);
1848 }
1849 }
1850
stopCalculation()1851 void ScheduleManager::stopCalculation()
1852 {
1853 if (schedulerPlugin()) {
1854 schedulerPlugin()->stopCalculation(this);
1855 }
1856 }
1857
haltCalculation()1858 void ScheduleManager::haltCalculation()
1859 {
1860 if (schedulerPlugin()) {
1861 schedulerPlugin()->haltCalculation(this);
1862 }
1863 }
1864
setMaxProgress(int value)1865 void ScheduleManager::setMaxProgress(int value)
1866 {
1867 m_maxprogress = value;
1868 emit maxProgressChanged(value);
1869 m_project.changed(this);
1870 }
1871
setProgress(int value)1872 void ScheduleManager::setProgress(int value)
1873 {
1874 m_progress = value;
1875 emit progressChanged(value);
1876 m_project.changed(this);
1877 }
1878
setDeleted(bool on)1879 void ScheduleManager::setDeleted(bool on)
1880 {
1881 if (m_expected) {
1882 m_expected->setDeleted(on);
1883 }
1884 m_project.changed(this);
1885 }
1886
setExpected(MainSchedule * sch)1887 void ScheduleManager::setExpected(MainSchedule *sch)
1888 {
1889 //debugPlan<<m_expected<<","<<sch;
1890 if (m_expected) {
1891 m_project.sendScheduleToBeRemoved(m_expected);
1892 m_expected->setDeleted(true);
1893 m_project.sendScheduleRemoved(m_expected);
1894 }
1895 m_expected = sch;
1896 if (sch) {
1897 m_project.sendScheduleToBeAdded(this, 0);
1898 sch->setManager(this);
1899 m_expected->setDeleted(false);
1900 m_project.sendScheduleAdded(sch);
1901 }
1902 m_project.changed(this);
1903 }
1904
state() const1905 QStringList ScheduleManager::state() const
1906 {
1907 QStringList lst;
1908 if (isBaselined()) {
1909 return lst << i18n("Baselined");
1910 }
1911 if (m_scheduling) {
1912 return lst << i18n("Scheduling");
1913 }
1914 if (m_expected == 0) {
1915 return lst << i18n("Not scheduled");
1916 }
1917 if (Schedule *s = m_expected) {
1918 if (s->resourceError || s->resourceOverbooked || s->resourceNotAvailable || s->constraintError || s->schedulingError) {
1919 return lst << i18n("Error");
1920 }
1921 return s->state();
1922 }
1923 return lst;
1924 }
1925
supportedGranularities() const1926 QList<long unsigned int> ScheduleManager::supportedGranularities() const
1927 {
1928 QList<long unsigned int> lst;
1929 if (schedulerPlugin()) {
1930 lst = schedulerPlugin()->granularities();
1931 }
1932 return lst;
1933 }
1934
granularity() const1935 int ScheduleManager::granularity() const
1936 {
1937 if (schedulerPlugin()) {
1938 return schedulerPlugin()->granularity();
1939 }
1940 return 0;
1941 }
1942
setGranularity(int duration)1943 void ScheduleManager::setGranularity(int duration)
1944 {
1945 if (schedulerPlugin()) {
1946 schedulerPlugin()->setGranularity(duration);
1947 }
1948 m_project.changed(this, GranularityProperty);
1949 }
1950
schedulingMode() const1951 bool ScheduleManager::schedulingMode() const
1952 {
1953 return m_schedulingMode;
1954 }
1955
setSchedulingMode(int mode)1956 void ScheduleManager::setSchedulingMode(int mode)
1957 {
1958 m_schedulingMode = mode;
1959 m_project.changed(this, SchedulingModeProperty);
1960 }
1961
incProgress()1962 void ScheduleManager::incProgress()
1963 {
1964 m_project.incProgress();
1965 }
1966
logAdded(const Schedule::Log & log)1967 void ScheduleManager::logAdded(const Schedule::Log &log)
1968 {
1969 emit sigLogAdded(log);
1970 int row = expected()->logs().count() - 1;
1971 emit logInserted(expected(), row, row);
1972 }
1973
slotAddLog(const QVector<KPlato::Schedule::Log> & log)1974 void ScheduleManager::slotAddLog(const QVector<KPlato::Schedule::Log> &log)
1975 {
1976 if (expected() && ! log.isEmpty()) {
1977 int first = expected()->logs().count();
1978 int last = first + log.count() - 1;
1979 Q_UNUSED(last);
1980 foreach (const KPlato::Schedule::Log &l, log) {
1981 expected()->addLog(l);
1982 }
1983 }
1984 }
1985
phaseNames() const1986 QMap< int, QString > ScheduleManager::phaseNames() const
1987 {
1988 if (expected()) {
1989 return expected()->phaseNames();
1990 }
1991 return QMap<int, QString>();
1992 }
1993
setPhaseNames(const QMap<int,QString> & phasenames)1994 void ScheduleManager::setPhaseNames(const QMap<int, QString> &phasenames)
1995 {
1996 if (expected()) {
1997 expected()->setPhaseNames(phasenames);
1998 }
1999 }
2000
2001
loadXML(KoXmlElement & element,XMLLoaderObject & status)2002 bool ScheduleManager::loadXML(KoXmlElement &element, XMLLoaderObject &status)
2003 {
2004 MainSchedule *sch = 0;
2005 if (status.version() <= "0.5") {
2006 m_usePert = false;
2007 sch = loadMainSchedule(element, status);
2008 if (sch) {
2009 sch->setManager(this);
2010 switch (sch->type()) {
2011 case Schedule::Expected: setExpected(sch); break;
2012 }
2013 }
2014 return true;
2015 }
2016 setName(element.attribute("name"));
2017 m_id = element.attribute("id");
2018 m_usePert = (element.attribute("distribution").toInt()) == 1;
2019 m_allowOverbooking = (bool)(element.attribute("overbooking").toInt());
2020 m_checkExternalAppointments = (bool)(element.attribute("check-external-appointments").toInt());
2021 m_schedulingDirection = (bool)(element.attribute("scheduling-direction").toInt());
2022 m_baselined = (bool)(element.attribute("baselined").toInt());
2023 m_schedulerPluginId = element.attribute("scheduler-plugin-id");
2024 if (status.project().schedulerPlugins().contains(m_schedulerPluginId)) {
2025 // atm we only load for current plugin
2026 int g = element.attribute("granularity", "0").toInt();
2027 status.project().schedulerPlugins().value(m_schedulerPluginId)->setGranularity(g);
2028 }
2029 m_recalculate = (bool)(element.attribute("recalculate").toInt());
2030 m_recalculateFrom = DateTime::fromString(element.attribute("recalculate-from"), status.projectTimeZone());
2031 if (element.hasAttribute("scheduling-mode")) {
2032 m_schedulingMode = element.attribute("scheduling-mode").toInt();
2033 }
2034
2035 KoXmlNode n = element.firstChild();
2036 for (; ! n.isNull(); n = n.nextSibling()) {
2037 if (! n.isElement()) {
2038 continue;
2039 }
2040 KoXmlElement e = n.toElement();
2041 //debugPlan<<e.tagName();
2042 if (e.tagName() == "schedule") {
2043 sch = loadMainSchedule(e, status);
2044 if (sch) {
2045 sch->setManager(this);
2046 switch (sch->type()) {
2047 case Schedule::Expected: setExpected(sch); break;
2048 }
2049 }
2050 } else if (e.tagName() == "plan") {
2051 ScheduleManager *sm = new ScheduleManager(status.project());
2052 if (sm->loadXML(e, status)) {
2053 m_project.addScheduleManager(sm, this);
2054 } else {
2055 errorPlan<<"Failed to load schedule manager"<<endl;
2056 delete sm;
2057 }
2058 }
2059 }
2060 return true;
2061 }
2062
loadMainSchedule(KoXmlElement & element,XMLLoaderObject & status)2063 MainSchedule *ScheduleManager::loadMainSchedule(KoXmlElement &element, XMLLoaderObject &status) {
2064 MainSchedule *sch = new MainSchedule();
2065 if (sch->loadXML(element, status)) {
2066 status.project().addSchedule(sch);
2067 sch->setNode(&(status.project()));
2068 status.project().setParentSchedule(sch);
2069 } else {
2070 errorPlan << "Failed to load schedule" << endl;
2071 delete sch;
2072 sch = 0;
2073 }
2074 return sch;
2075 }
2076
loadMainSchedule(MainSchedule * schedule,KoXmlElement & element,XMLLoaderObject & status)2077 bool ScheduleManager::loadMainSchedule(MainSchedule *schedule, KoXmlElement &element, XMLLoaderObject &status) {
2078 long sid = schedule->id();
2079 if (schedule->loadXML(element, status)) {
2080 if (sid != schedule->id() && status.project().findSchedule(sid)) {
2081 status.project().takeSchedule(schedule);
2082 }
2083 if (! status.project().findSchedule(schedule->id())) {
2084 status.project().addSchedule(schedule);
2085 }
2086 schedule->setNode(&(status.project()));
2087 status.project().setParentSchedule(schedule);
2088 return true;
2089 }
2090 return false;
2091 }
2092
saveXML(QDomElement & element) const2093 void ScheduleManager::saveXML(QDomElement &element) const
2094 {
2095 QDomElement el = element.ownerDocument().createElement("plan");
2096 element.appendChild(el);
2097 el.setAttribute("name", m_name);
2098 el.setAttribute("id", m_id);
2099 el.setAttribute("distribution", QString::number(m_usePert ? 1 : 0));
2100 el.setAttribute("overbooking", QString::number(m_allowOverbooking));
2101 el.setAttribute("check-external-appointments", QString::number(m_checkExternalAppointments));
2102 el.setAttribute("scheduling-direction", QString::number(m_schedulingDirection));
2103 el.setAttribute("baselined", QString::number(m_baselined));
2104 el.setAttribute("scheduler-plugin-id", m_schedulerPluginId);
2105 if (schedulerPlugin()) {
2106 // atm we only save for current plugin
2107 el.setAttribute("granularity", QString::number(schedulerPlugin()->granularity()));
2108 }
2109 el.setAttribute("recalculate", QString::number(m_recalculate));
2110 el.setAttribute("recalculate-from", m_recalculateFrom.toString(Qt::ISODate));
2111 el.setAttribute("scheduling-mode", m_schedulingMode);
2112 if (m_expected && ! m_expected->isDeleted()) {
2113 QDomElement schs = el.ownerDocument().createElement("schedule");
2114 el.appendChild(schs);
2115 m_expected->saveXML(schs);
2116 m_project.saveAppointments(schs, m_expected->id());
2117 }
2118 foreach (ScheduleManager *sm, m_children) {
2119 sm->saveXML(el);
2120 }
2121
2122 }
2123
saveWorkPackageXML(QDomElement & element,const Node & node) const2124 void ScheduleManager::saveWorkPackageXML(QDomElement &element, const Node &node) const
2125 {
2126 QDomElement el = element.ownerDocument().createElement("plan");
2127 element.appendChild(el);
2128 el.setAttribute("name", m_name);
2129 el.setAttribute("id", m_id);
2130 el.setAttribute("distribution", QString::number(m_usePert ? 1 : 0));
2131 el.setAttribute("overbooking", QString::number(m_allowOverbooking));
2132 el.setAttribute("check-external-appointments", QString::number(m_checkExternalAppointments));
2133 el.setAttribute("scheduling-direction", QString::number(m_schedulingDirection));
2134 el.setAttribute("baselined", QString::number(m_baselined));
2135 if (m_expected && ! m_expected->isDeleted()) { // TODO: should we check isScheduled() ?
2136 QDomElement schs = el.ownerDocument().createElement("schedule");
2137 el.appendChild(schs);
2138 m_expected->saveXML(schs);
2139 Schedule *s = node.findSchedule(m_expected->id());
2140 if (s && ! s->isDeleted()) {
2141 s->saveAppointments(schs);
2142 }
2143 }
2144 }
2145
2146
2147 } //namespace KPlato
2148
operator <<(QDebug dbg,const KPlato::Schedule * s)2149 QDebug operator<<(QDebug dbg, const KPlato::Schedule *s)
2150 {
2151 if (s) {
2152 return dbg<<(*s);
2153 }
2154 return dbg<<"Schedule(0x0)";
2155 }
operator <<(QDebug dbg,const KPlato::Schedule & s)2156 QDebug operator<<(QDebug dbg, const KPlato::Schedule &s)
2157 {
2158 dbg.nospace()<<"Schedule["<<s.id();
2159 if (s.isDeleted()) {
2160 dbg.nospace()<<": Deleted";
2161 } else {
2162 dbg.nospace()<<": "<<s.name();
2163 }
2164 dbg.nospace()<<"]";
2165 return dbg.space();
2166 }
2167
operator <<(QDebug dbg,const KPlato::Schedule::Log & log)2168 QDebug operator<<(QDebug dbg, const KPlato::Schedule::Log &log)
2169 {
2170 dbg.nospace()<<"Schedule::Log: "<<log.formatMsg();
2171 return dbg.space();
2172 }
2173