kplato

kptappointment.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005 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;
7 version 2 of the License.
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#include "kptappointment.h"
21
22#include "kptproject.h"
23#include "kpttask.h"
24#include "kptdatetime.h"
25#include "kptcalendar.h"
26#include "kpteffortcostmap.h"
27#include "kptschedule.h"
28
29#include <kdebug.h>
30
31namespace KPlato
32{
33
34class Resource;
35
36AppointmentInterval::AppointmentInterval() {
37 m_load = 100.0;
38}
39AppointmentInterval::AppointmentInterval(const AppointmentInterval &interval) {
40 //kdDebug()<<k_funcinfo<<endl;
41 m_start = interval.startTime();
42 m_end = interval.endTime();
43 m_load = interval.load();
44}
45AppointmentInterval::AppointmentInterval(const DateTime &start, const DateTime end, double load) {
46 //kdDebug()<<k_funcinfo<<endl;
47 m_start = start;
48 m_end = end;
49 m_load = load;
50}
51AppointmentInterval::~AppointmentInterval() {
52 //kdDebug()<<k_funcinfo<<endl;
53}
54
55Duration AppointmentInterval::effort(const DateTime &start, const DateTime end) const {
56 if (start >= m_end || end <= m_start) {
58 }
59 DateTime s = (start > m_start ? start : m_start);
60 DateTime e = (end < m_end ? end : m_end);
61 return (e - s) * m_load / 100;
62}
63
64Duration AppointmentInterval::effort(const DateTime &time, bool upto) const {
65 if (upto) {
66 if (time <= m_start) {
68 }
69 DateTime e = (time < m_end ? time : m_end);
70 return (e - m_start) * m_load / 100;
71 }
72 // from time till end
73 if (time >= m_end) {
75 }
76 DateTime s = (time > m_start ? time : m_start);
77 return (m_end - s) * m_load / 100;
78}
79
80bool AppointmentInterval::loadXML(TQDomElement &element) {
81 //kdDebug()<<k_funcinfo<<endl;
82 bool ok;
83 TQString s = element.attribute("start");
84 if (s != "")
85 m_start = DateTime::fromString(s);
86 s = element.attribute("end");
87 if (s != "")
88 m_end = DateTime::fromString(s);
89 m_load = element.attribute("load", "100").toDouble(&ok);
90 if (!ok) m_load = 100;
91 return m_start.isValid() && m_end.isValid();
92}
93
94void AppointmentInterval::saveXML(TQDomElement &element) const {
95 TQDomElement me = element.ownerDocument().createElement("interval");
96 element.appendChild(me);
97
98 me.setAttribute("start", m_start.toString(TQt::ISODate));
99 me.setAttribute("end", m_end.toString(TQt::ISODate));
100 me.setAttribute("load", m_load);
101}
102
103bool AppointmentInterval::isValid() const {
104 return m_start.isValid() && m_end.isValid();
105}
106
107AppointmentInterval AppointmentInterval::firstInterval(const AppointmentInterval &interval, const DateTime &from) const {
108 //kdDebug()<<k_funcinfo<<interval.startTime().toString()<<" - "<<interval.endTime().toString()<<" from="<<from.toString()<<endl;
109 DateTime f = from;
110 DateTime s1 = m_start;
111 DateTime e1 = m_end;
112 DateTime s2 = interval.startTime();
113 DateTime e2 = interval.endTime();
114 AppointmentInterval a;
115 if (f.isValid() && f >= e1 && f >= e2) {
116 return a;
117 }
118 if (f.isValid()) {
119 if (s1 < f && f < e1) {
120 s1 = f;
121 }
122 if (s2 < f && f < e2) {
123 s2 = f;
124 }
125 } else {
126 f = s1 < s2 ? s1 : s2;
127 }
128 if (s1 < s2) {
129 a.setStartTime(s1);
130 if (e1 <= s2) {
131 a.setEndTime(e1);
132 } else {
133 a.setEndTime(s2);
134 }
135 a.setLoad(m_load);
136 } else if (s1 > s2) {
137 a.setStartTime(s2);
138 if (e2 <= s1) {
139 a.setEndTime(e2);
140 } else {
141 a.setEndTime(s1);
142 }
143 a.setLoad(interval.load());
144 } else {
145 a.setStartTime(s1);
146 if (e1 <= e2)
147 a.setEndTime(e1);
148 else
149 a.setEndTime(e2);
150 a.setLoad(m_load + interval.load());
151 }
152 //kdDebug()<<k_funcinfo<<a.startTime().toString()<<" - "<<a.endTime().toString()<<" load="<<a.load()<<endl;
153 return a;
154}
155
157
158Appointment::UsedEffortItem::UsedEffortItem(TQDate date, Duration effort, bool overtime) {
159 m_date = date;
160 m_effort = effort;
161 m_overtime = overtime;
162}
163TQDate Appointment::UsedEffortItem::date() {
164 return m_date;
165}
166Duration Appointment::UsedEffortItem::effort() {
167 return m_effort;
168}
169bool Appointment::UsedEffortItem::isOvertime() {
170 return m_overtime;
171}
172
173Appointment::UsedEffort::UsedEffort() {
174 setAutoDelete(true);
175}
176
177void Appointment::UsedEffort::inSort(TQDate date, Duration effort, bool overtime) {
178 UsedEffortItem *item = new UsedEffortItem(date, effort, overtime);
179 TQPtrList<UsedEffortItem>::inSort(item);
180}
181
182Duration Appointment::UsedEffort::usedEffort(bool includeOvertime) const {
183 Duration eff;
184 TQPtrListIterator<UsedEffortItem> it(*this);
185 for (; it.current(); ++it) {
186 if (includeOvertime || !it.current()->isOvertime()) {
187 eff += it.current()->effort();
188 }
189 }
190 return eff;
191}
192
193Duration Appointment::UsedEffort::usedEffort(const TQDate &date, bool includeOvertime) const {
194 Duration eff;
195 TQPtrListIterator<UsedEffortItem> it(*this);
196 for (; it.current(); ++it) {
197 if ((includeOvertime || !it.current()->isOvertime()) &&
198 it.current()->date() == date) {
199 eff += it.current()->effort();
200 }
201 }
202 return eff;
203}
204
205Duration Appointment::UsedEffort::usedEffortTo(const TQDate &date, bool includeOvertime) const {
206 Duration eff;
207 TQPtrListIterator<UsedEffortItem> it(*this);
208 for (; it.current(); ++it) {
209 if ((includeOvertime || !it.current()->isOvertime()) &&
210 it.current()->date() <= date) {
211 eff += it.current()->effort();
212 }
213 }
214 return eff;
215}
216
217Duration Appointment::UsedEffort::usedOvertime() const {
218 UsedEffortItem *item = getFirst();
219 return item==0 ? Duration::zeroDuration : usedOvertime(item->date());
220}
221
222Duration Appointment::UsedEffort::usedOvertime(const TQDate &date) const {
223 Duration eff;
224 TQPtrListIterator<UsedEffortItem> it(*this);
225 for (; it.current(); ++it) {
226 if (it.current()->isOvertime() && it.current()->date() == date) {
227 eff += it.current()->effort();
228 }
229 }
230 return eff;
231}
232
233Duration Appointment::UsedEffort::usedOvertimeTo(const TQDate &date) const {
234 Duration eff;
235 TQPtrListIterator<UsedEffortItem> it(*this);
236 for (; it.current(); ++it) {
237 if (it.current()->isOvertime() && it.current()->date() <= date) {
238 eff += it.current()->effort();
239 }
240 }
241 return eff;
242}
243
244bool Appointment::UsedEffort::load(TQDomElement &element) {
245 TQString s;
246 TQDomNodeList list = element.childNodes();
247 for (unsigned int i=0; i<list.count(); ++i) {
248 if (list.item(i).isElement()) {
249 TQDomElement e = list.item(i).toElement();
250 if (e.tagName() == "actual-effort") {
251 TQDate date;
252 s = e.attribute("date");
253 if (s != "")
254 date = TQDate::fromString(s, TQt::ISODate);
255 Duration eff = Duration::fromString(e.attribute("effort"));
256 bool ot = e.attribute("overtime", "0").toInt();
257 if (date.isValid()) {
258 inSort(date, eff, ot);
259 } else {
260 kdError()<<k_funcinfo<<"Load failed, illegal date: "<<e.attribute("date")<<endl;
261 }
262 }
263 }
264 }
265 return true;
266}
267
268void Appointment::UsedEffort::save(TQDomElement &element) const {
269 if (isEmpty()) return;
270 TQPtrListIterator<UsedEffortItem> it = *this;
271 for (; it.current(); ++it) {
272 TQDomElement me = element.ownerDocument().createElement("actual-effort");
273 element.appendChild(me);
274 me.setAttribute("date",it.current()->date().toString(TQt::ISODate));
275 me.setAttribute("effort",it.current()->effort().toString());
276 me.setAttribute("overtime",it.current()->isOvertime());
277 }
278}
279
280int Appointment::UsedEffort::compareItems(TQPtrCollection::Item item1, TQPtrCollection::Item item2) {
281 TQDate d1 = static_cast<UsedEffortItem*>(item1)->date();
282 TQDate d2 = static_cast<UsedEffortItem*>(item2)->date();
283 if (d1 > d2) return 1;
284 if (d1 < d2) return -1;
285 return 0;
286}
287
289Appointment::Appointment()
290 : m_extraRepeats(), m_skipRepeats() {
291 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
292 m_resource=0;
293 m_node=0;
294 m_repeatInterval=Duration();
295 m_repeatCount=0;
296
297 m_intervals.setAutoDelete(true);
298}
299
300Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, DateTime end, double load)
301 : m_extraRepeats(),
302 m_skipRepeats() {
303 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
304 m_node = node;
305 m_resource = resource;
306 m_repeatInterval = Duration();
307 m_repeatCount = 0;
308
309 addInterval(start, end, load);
310
311 m_intervals.setAutoDelete(true);
312}
313
314Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, Duration duration, double load)
315 : m_extraRepeats(),
316 m_skipRepeats() {
317 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
318 m_node = node;
319 m_resource = resource;
320 m_repeatInterval = Duration();
321 m_repeatCount = 0;
322
323 addInterval(start, duration, load);
324
325 m_intervals.setAutoDelete(true);
326}
327
328Appointment::~Appointment() {
329 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
330 detach();
331}
332
333void Appointment::addInterval(AppointmentInterval *a) {
334 //kdDebug()<<k_funcinfo<<m_resource->name()<<" to "<<m_node->name()<<endl;
335 m_intervals.inSort(a);
336}
337void Appointment::addInterval(const DateTime &start, const DateTime &end, double load) {
338 addInterval(new AppointmentInterval(start, end, load));
339}
340void Appointment::addInterval(const DateTime &start, const Duration &duration, double load) {
341 DateTime e = start+duration;
342 addInterval(start, e, load);
343}
344
345double Appointment::maxLoad() const {
346 double v = 0.0;
347 TQPtrListIterator<AppointmentInterval> it = m_intervals;
348 for (; it.current(); ++it) {
349 if (v < it.current()->load())
350 v = it.current()->load();
351 }
352 return v;
353}
354
355DateTime Appointment::startTime() const {
356 DateTime t;
357 TQPtrListIterator<AppointmentInterval> it = m_intervals;
358 for (; it.current(); ++it) {
359 if (!t.isValid() || t > it.current()->startTime())
360 t = it.current()->startTime();
361 }
362 return t;
363}
364
365DateTime Appointment::endTime() const {
366 DateTime t;
367 TQPtrListIterator<AppointmentInterval> it = m_intervals;
368 for (; it.current(); ++it) {
369 if (!t.isValid() || t < it.current()->endTime())
370 t = it.current()->endTime();
371 }
372 return t;
373}
374
375void Appointment::deleteAppointmentFromRepeatList(DateTime) {
376}
377
378void Appointment::addAppointmentToRepeatList(DateTime) {
379}
380
381bool Appointment::isBusy(const DateTime &/*start*/, const DateTime &/*end*/) {
382 return false;
383}
384
385bool Appointment::loadXML(TQDomElement &element, Project &project, Schedule &sch) {
386 //kdDebug()<<k_funcinfo<<endl;
387 TQDictIterator<Node> it = project.nodeDict();
388/* for (; it.current(); ++it) {
389 kdDebug()<<" Node="<<it.current()->name()<<" id="<<it.currentKey()<<endl;
390 }*/
391 Node *node = project.findNode(element.attribute("task-id"));
392 if (node == 0) {
393 kdError()<<k_funcinfo<<"The referenced task does not exists: "<<element.attribute("task-id")<<endl;
394 return false;
395 }
396 Resource *res = project.resource(element.attribute("resource-id"));
397 if (res == 0) {
398 kdError()<<k_funcinfo<<"The referenced resource does not exists: resource id="<<element.attribute("resource-id")<<endl;
399 return false;
400 }
401 if (!res->addAppointment(this, sch)) {
402 kdError()<<k_funcinfo<<"Failed to add appointment to resource: "<<res->name()<<endl;
403 return false;
404 }
405 if (!node->addAppointment(this, sch)) {
406 kdError()<<k_funcinfo<<"Failed to add appointment to node: "<<node->name()<<endl;
407 m_resource->takeAppointment(this);
408 return false;
409 }
410 //kdDebug()<<k_funcinfo<<"res="<<m_resource<<" node="<<m_node<<endl;
411 TQDomNodeList list = element.childNodes();
412 for (unsigned int i=0; i<list.count(); ++i) {
413 if (list.item(i).isElement()) {
414 TQDomElement e = list.item(i).toElement();
415 if (e.tagName() == "interval") {
416 AppointmentInterval *a = new AppointmentInterval();
417 if (a->loadXML(e)) {
418 addInterval(a);
419 } else {
420 kdError()<<k_funcinfo<<"Could not load interval"<<endl;
421 delete a;
422 }
423 }
424 }
425 }
426 if (m_intervals.isEmpty()) {
427 return false;
428 }
429 m_actualEffort.load(element);
430 return true;
431}
432
433void Appointment::saveXML(TQDomElement &element) const {
434 if (m_intervals.isEmpty()) {
435 kdError()<<k_funcinfo<<"Incomplete appointment data: No intervals"<<endl;
436 }
437 if (m_resource == 0 || m_resource->resource() == 0) {
438 kdError()<<k_funcinfo<<"Incomplete appointment data: No resource"<<endl;
439 return;
440 }
441 if (m_node == 0 || m_node->node() == 0) {
442 kdError()<<k_funcinfo<<"Incomplete appointment data: No node"<<endl;
443 return; // shouldn't happen
444 }
445 //kdDebug()<<k_funcinfo<<endl;
446 TQDomElement me = element.ownerDocument().createElement("appointment");
447 element.appendChild(me);
448
449 me.setAttribute("resource-id", m_resource->resource()->id());
450 me.setAttribute("task-id", m_node->node()->id());
451 TQPtrListIterator<AppointmentInterval> it = m_intervals;
452 for (; it.current(); ++it) {
453 it.current()->saveXML(me);
454 }
455 m_actualEffort.save(me);
456}
457
458// Returns the total actual effort for this appointment
460 Duration d;
461 TQPtrListIterator<AppointmentInterval> it = m_intervals;
462 for (; it.current(); ++it) {
463 d += it.current()->effort();
464 }
465 return d;
466}
467
468// Returns the planned effort on the date
469Duration Appointment::plannedEffort(const TQDate &date) const {
470 Duration d;
471 DateTime s(date);
472 DateTime e(date.addDays(1));
473 TQPtrListIterator<AppointmentInterval> it = m_intervals;
474 for (; it.current(); ++it) {
475 d += it.current()->effort(s, e);
476 }
477 return d;
478}
479
480// Returns the planned effort upto and including the date
481Duration Appointment::plannedEffortTo(const TQDate& date) const {
482 Duration d;
483 DateTime e(date.addDays(1));
484 TQPtrListIterator<AppointmentInterval> it = m_intervals;
485 for (; it.current(); ++it) {
486 d += it.current()->effort(e, true);
487 }
488 return d;
489}
490
491// Returns a list of efforts pr day for interval start, end inclusive
492// The list only includes days with any planned effort
493EffortCostMap Appointment::plannedPrDay(const TQDate& start, const TQDate& end) const {
494 //kdDebug()<<k_funcinfo<<m_node->id()<<", "<<m_resource->id()<<endl;
495 EffortCostMap ec;
496 Duration eff;
497 DateTime dt(start);
498 DateTime ndt(dt.addDays(1));
499 double rate = m_resource->normalRatePrHour();
500 AppointmentIntervalListIterator it = m_intervals;
501 for (; it.current(); ++it) {
502 DateTime st = it.current()->startTime();
503 DateTime e = it.current()->endTime();
504 if (end < st.date())
505 break;
506 if (dt.date() < st.date()) {
507 dt.setDate(st.date());
508 }
509 ndt = TQDateTime(dt.addDays(1));
510 while (dt.date() <= e.date()) {
511 eff = it.current()->effort(dt, ndt);
512 ec.add(dt.date(), eff, eff.toDouble(Duration::Unit_h) * rate);
513 if (dt.date() < e.date() ) {
514 // loop trough the interval (it spans dates)
515 dt = ndt;
516 ndt = TQDateTime(ndt.addDays(1));
517 } else {
518 break;
519 }
520 }
521 }
522 return ec;
523}
524
525
526// Returns the total actual effort for this appointment
528 return m_actualEffort.usedEffort();
529}
530
531// Returns the actual effort on the date
532Duration Appointment::actualEffort(const TQDate &date) const {
533 return m_actualEffort.usedEffort(date);
534}
535
536// Returns the actual effort upto and including date
537Duration Appointment::actualEffortTo(const TQDate &date) const {
538 return m_actualEffort.usedEffortTo(date);
539}
540
542 if (m_resource && m_resource->resource()) {
543 return plannedEffort().toDouble(Duration::Unit_h) * m_resource->resource()->normalRate(); //FIXME overtime
544 }
545 return 0.0;
546}
547
548//Calculates the planned cost on date
549double Appointment::plannedCost(const TQDate &date) {
550 if (m_resource && m_resource->resource()) {
551 return plannedEffort(date).toDouble(Duration::Unit_h) * m_resource->resource()->normalRate(); //FIXME overtime
552 }
553 return 0.0;
554}
555
556//Calculates the planned cost upto and including date
557double Appointment::plannedCostTo(const TQDate &date) {
558 if (m_resource && m_resource->resource()) {
559 return plannedEffortTo(date).toDouble(Duration::Unit_h) * m_resource->resource()->normalRate(); //FIXME overtime
560 }
561 return 0.0;
562}
563
564// Calculates the total actual cost for this appointment
566 //kdDebug()<<k_funcinfo<<m_actualEffort.usedEffort(false /*ex. overtime*/).toDouble(Duration::Unit_h)<<endl;
567 if (m_resource && m_resource->resource()) {
568 return (m_actualEffort.usedEffort(false /*ex. overtime*/).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime().toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
569 }
570 return 0.0;
571}
572
573// Calculates the actual cost on date
574double Appointment::actualCost(const TQDate &date) {
575 if (m_resource && m_resource->resource()) {
576 return (m_actualEffort.usedEffort(date, false /*ex. overtime*/).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
577 }
578 return 0.0;
579}
580
581// Calculates the actual cost upto and including date
582double Appointment::actualCostTo(const TQDate &date) {
583 if (m_resource && m_resource->resource()) {
584 return (m_actualEffort.usedEffortTo(date, false /*ex. overtime*/).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertimeTo(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
585 }
586 return 0.0;
587}
588
589void Appointment::addActualEffort(TQDate date, Duration effort, bool overtime) {
590 m_actualEffort.inSort(date, effort, overtime);
591}
592
594 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
595 if (m_resource && m_node) {
596 m_resource->add(this);
597 m_node->add(this);
598 return true;
599 }
600 kdWarning()<<k_funcinfo<<"Failed: "<<(m_resource ? "" : "resource=0 ")
601 <<(m_node ? "" : "node=0")<<endl;
602 return false;
603}
604
606 //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
607 if (m_resource) {
608 m_resource->takeAppointment(this); // takes from node also
609 }
610 if (m_node) {
611 m_node->takeAppointment(this); // to make it robust
612 }
613}
614
615// Returns the effort from start to end
616Duration Appointment::effort(const DateTime &start, const DateTime &end) const {
617 Duration d;
618 TQPtrListIterator<AppointmentInterval> it = m_intervals;
619 for (; it.current(); ++it) {
620 d += it.current()->effort(start, end);
621 }
622 return d;
623}
624// Returns the effort from start for the duration
625Duration Appointment::effort(const DateTime &start, const Duration &duration) const {
626 Duration d;
627 TQPtrListIterator<AppointmentInterval> it = m_intervals;
628 for (; it.current(); ++it) {
629 d += it.current()->effort(start, start+duration);
630 }
631 return d;
632}
633// Returns the effort upto time / from time
635 Duration d;
636 TQPtrListIterator<AppointmentInterval> it = m_intervals;
637 for (; it.current(); ++it) {
638 d += it.current()->effort(time, false);
639 }
640 return d;
641}
642
643Appointment &Appointment::operator=(const Appointment &app) {
644 m_resource = app.resource();
645 m_node = app.node();
646 m_repeatInterval = app.repeatInterval();
647 m_repeatCount = app.repeatCount();
648
649 m_intervals.clear();
650 TQPtrListIterator<AppointmentInterval> it = app.intervals();
651 for (; it.current(); ++it) {
652 addInterval(new AppointmentInterval(*(it.current())));
653 }
654 return *this;
655}
656
657Appointment &Appointment::operator+=(const Appointment &app) {
658 *this = *this + app;
659 return *this;
660}
661
662Appointment Appointment::operator+(const Appointment &app) {
663 Appointment a;
664 AppointmentIntervalList ai = app.intervals();
665 AppointmentInterval i;
666 AppointmentInterval *i1 = m_intervals.first();
667 AppointmentInterval *i2 = ai.first();
668 DateTime from;
669 while (i1 || i2) {
670 if (!i1) {
671 if (!from.isValid() || from < i2->startTime())
672 from = i2->startTime();
673 a.addInterval(from, i2->endTime(), i2->load());
674 //kdDebug()<<"Interval+ (i2): "<<from.toString()<<" - "<<i2->endTime().toString()<<endl;
675 from = i2->endTime();
676 i2 = ai.next();
677 continue;
678 }
679 if (!i2) {
680 if (!from.isValid() || from < i1->startTime())
681 from = i1->startTime();
682 a.addInterval(from, i1->endTime(), i1->load());
683 //kdDebug()<<"Interval+ (i1): "<<from.toString()<<" - "<<i1->endTime().toString()<<endl;
684 from = i1->endTime();
685 i1 = m_intervals.next();
686 continue;
687 }
688 i = i1->firstInterval(*i2, from);
689 if (!i.isValid()) {
690 break;
691 }
692 a.addInterval(i);
693 from = i.endTime();
694 //kdDebug()<<"Interval+ (i): "<<i.startTime().toString()<<" - "<<i.endTime().toString()<<" load="<<i.load()<<endl;
695 if (i1 && a.endTime() >= i1->endTime()) {
696 i1 = m_intervals.next();
697 }
698 if (i2 && a.endTime() >= i2->endTime()) {
699 i2 = ai.next();
700 }
701 }
702 return a;
703}
704
705#ifndef NDEBUG
706void Appointment::printDebug(TQString indent)
707{
708 bool err = false;
709 if (m_node == 0) {
710 kdDebug()<<indent<<" No node schedule"<<endl;
711 err = true;
712 } else if (m_node->node() == 0) {
713 kdDebug()<<indent<<" No node"<<endl;
714 err = true;
715 }
716 if (m_resource == 0) {
717 kdDebug()<<indent<<" No resource schedule"<<endl;
718 err = true;
719 } else if (m_resource->resource() == 0) {
720 kdDebug()<<indent<<" No resource"<<endl;
721 err = true;
722 }
723 if (err)
724 return;
725 kdDebug()<<indent<<" + Appointment to schedule: "<<m_node->name()<<" ("<<m_node->type()<<")"<<" resource: "<<m_resource->resource()->name()<<endl;
726 indent += " ! ";
727 TQPtrListIterator<AppointmentInterval> it = intervals();
728 for (; it.current(); ++it) {
729 kdDebug()<<indent<<it.current()->startTime().toString()<<" - "<<it.current()->endTime().toString()<<" load="<<it.current()->load()<<endl;
730 }
731}
732#endif
733
734} //KPlato namespace
A resource (Resource) can be scheduled to be used at any time, this is represented internally with Ap...
Duration effortFrom(const DateTime &time) const
Returns the planned effort from time onwards.
void detach()
detach appointment from resource and node
EffortCostMap plannedPrDay(const TQDate &start, const TQDate &end) const
Returns the planned effort and cost for the interval start to end (inclusive).
double plannedCost()
Calculates the total planned cost for this appointment.
double actualCost()
Calculates the total actual cost for this appointment.
double actualCostTo(const TQDate &date)
Calculates the actual cost upto and including date.
Duration plannedEffort() const
Returns the total planned effort for this appointment.
bool attach()
attach appointment to resource and node
Duration actualEffortTo(const TQDate &date) const
Returns the actual effort on the date.
Duration effort(const DateTime &start, const DateTime &end) const
Returns the planned effort from start to end.
Duration plannedEffortTo(const TQDate &date) const
Returns the planned effort upto and including date.
Duration actualEffort() const
Returns the total actual effort for this appointment.
double plannedCostTo(const TQDate &date)
Calculates the planned cost upto and including date.
DateTime is a TQDateTime which knows about Duration.
Definition kptdatetime.h:33
The duration class can be used to store a timespan in a convenient format.
Definition kptduration.h:34
static const Duration zeroDuration
This is useful for occasions where we need a zero duration.
Any resource that is used by a task.