20#include "kptappointment.h"
22#include "kptproject.h"
24#include "kptdatetime.h"
25#include "kptcalendar.h"
26#include "kpteffortcostmap.h"
27#include "kptschedule.h"
36AppointmentInterval::AppointmentInterval() {
39AppointmentInterval::AppointmentInterval(
const AppointmentInterval &interval) {
41 m_start = interval.startTime();
42 m_end = interval.endTime();
43 m_load = interval.load();
45AppointmentInterval::AppointmentInterval(
const DateTime &start,
const DateTime end,
double load) {
51AppointmentInterval::~AppointmentInterval() {
55Duration AppointmentInterval::effort(
const DateTime &start,
const DateTime end)
const {
56 if (start >= m_end || end <= m_start) {
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;
64Duration AppointmentInterval::effort(
const DateTime &time,
bool upto)
const {
66 if (time <= m_start) {
69 DateTime e = (time < m_end ? time : m_end);
70 return (e - m_start) * m_load / 100;
76 DateTime s = (time > m_start ? time : m_start);
77 return (m_end - s) * m_load / 100;
80bool AppointmentInterval::loadXML(TQDomElement &element) {
83 TQString s = element.attribute(
"start");
85 m_start = DateTime::fromString(s);
86 s = element.attribute(
"end");
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();
94void AppointmentInterval::saveXML(TQDomElement &element)
const {
95 TQDomElement me = element.ownerDocument().createElement(
"interval");
96 element.appendChild(me);
98 me.setAttribute(
"start", m_start.toString(TQt::ISODate));
99 me.setAttribute(
"end", m_end.toString(TQt::ISODate));
100 me.setAttribute(
"load", m_load);
103bool AppointmentInterval::isValid()
const {
104 return m_start.isValid() && m_end.isValid();
107AppointmentInterval AppointmentInterval::firstInterval(
const AppointmentInterval &interval,
const DateTime &from)
const {
110 DateTime s1 = m_start;
112 DateTime s2 = interval.startTime();
113 DateTime e2 = interval.endTime();
114 AppointmentInterval a;
115 if (f.isValid() && f >= e1 && f >= e2) {
119 if (s1 < f && f < e1) {
122 if (s2 < f && f < e2) {
126 f = s1 < s2 ? s1 : s2;
136 }
else if (s1 > s2) {
143 a.setLoad(interval.load());
150 a.setLoad(m_load + interval.load());
158Appointment::UsedEffortItem::UsedEffortItem(TQDate date, Duration effort,
bool overtime) {
161 m_overtime = overtime;
163TQDate Appointment::UsedEffortItem::date() {
166Duration Appointment::UsedEffortItem::effort() {
169bool Appointment::UsedEffortItem::isOvertime() {
173Appointment::UsedEffort::UsedEffort() {
177void Appointment::UsedEffort::inSort(TQDate date, Duration effort,
bool overtime) {
178 UsedEffortItem *item =
new UsedEffortItem(date, effort, overtime);
179 TQPtrList<UsedEffortItem>::inSort(item);
182Duration Appointment::UsedEffort::usedEffort(
bool includeOvertime)
const {
184 TQPtrListIterator<UsedEffortItem> it(*
this);
185 for (; it.current(); ++it) {
186 if (includeOvertime || !it.current()->isOvertime()) {
187 eff += it.current()->effort();
193Duration Appointment::UsedEffort::usedEffort(
const TQDate &date,
bool includeOvertime)
const {
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();
205Duration Appointment::UsedEffort::usedEffortTo(
const TQDate &date,
bool includeOvertime)
const {
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();
217Duration Appointment::UsedEffort::usedOvertime()
const {
218 UsedEffortItem *item = getFirst();
222Duration Appointment::UsedEffort::usedOvertime(
const TQDate &date)
const {
224 TQPtrListIterator<UsedEffortItem> it(*
this);
225 for (; it.current(); ++it) {
226 if (it.current()->isOvertime() && it.current()->date() == date) {
227 eff += it.current()->effort();
233Duration Appointment::UsedEffort::usedOvertimeTo(
const TQDate &date)
const {
235 TQPtrListIterator<UsedEffortItem> it(*
this);
236 for (; it.current(); ++it) {
237 if (it.current()->isOvertime() && it.current()->date() <= date) {
238 eff += it.current()->effort();
244bool Appointment::UsedEffort::load(TQDomElement &element) {
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") {
252 s = e.attribute(
"date");
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);
260 kdError()<<k_funcinfo<<
"Load failed, illegal date: "<<e.attribute(
"date")<<endl;
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());
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;
289Appointment::Appointment()
290 : m_extraRepeats(), m_skipRepeats() {
294 m_repeatInterval=Duration();
297 m_intervals.setAutoDelete(
true);
300Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, DateTime end,
double load)
305 m_resource = resource;
306 m_repeatInterval = Duration();
309 addInterval(start, end, load);
311 m_intervals.setAutoDelete(
true);
314Appointment::Appointment(Schedule *resource, Schedule *node, DateTime start, Duration duration,
double load)
319 m_resource = resource;
320 m_repeatInterval = Duration();
323 addInterval(start, duration, load);
325 m_intervals.setAutoDelete(
true);
328Appointment::~Appointment() {
333void Appointment::addInterval(AppointmentInterval *a) {
335 m_intervals.inSort(a);
337void Appointment::addInterval(
const DateTime &start,
const DateTime &end,
double load) {
338 addInterval(
new AppointmentInterval(start, end, load));
340void Appointment::addInterval(
const DateTime &start,
const Duration &duration,
double load) {
341 DateTime e = start+duration;
342 addInterval(start, e, load);
345double Appointment::maxLoad()
const {
347 TQPtrListIterator<AppointmentInterval> it = m_intervals;
348 for (; it.current(); ++it) {
349 if (v < it.current()->load())
350 v = it.current()->load();
355DateTime Appointment::startTime()
const {
357 TQPtrListIterator<AppointmentInterval> it = m_intervals;
358 for (; it.current(); ++it) {
359 if (!t.isValid() || t > it.current()->startTime())
360 t = it.current()->startTime();
365DateTime Appointment::endTime()
const {
367 TQPtrListIterator<AppointmentInterval> it = m_intervals;
368 for (; it.current(); ++it) {
369 if (!t.isValid() || t < it.current()->endTime())
370 t = it.current()->endTime();
375void Appointment::deleteAppointmentFromRepeatList(DateTime) {
378void Appointment::addAppointmentToRepeatList(DateTime) {
381bool Appointment::isBusy(
const DateTime &,
const DateTime &) {
385bool Appointment::loadXML(TQDomElement &element, Project &project, Schedule &sch) {
387 TQDictIterator<Node> it = project.nodeDict();
391 Node *node = project.findNode(element.attribute(
"task-id"));
393 kdError()<<k_funcinfo<<
"The referenced task does not exists: "<<element.attribute(
"task-id")<<endl;
396 Resource *res = project.resource(element.attribute(
"resource-id"));
398 kdError()<<k_funcinfo<<
"The referenced resource does not exists: resource id="<<element.attribute(
"resource-id")<<endl;
401 if (!res->addAppointment(
this, sch)) {
402 kdError()<<k_funcinfo<<
"Failed to add appointment to resource: "<<res->name()<<endl;
405 if (!node->addAppointment(
this, sch)) {
406 kdError()<<k_funcinfo<<
"Failed to add appointment to node: "<<node->name()<<endl;
407 m_resource->takeAppointment(
this);
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();
420 kdError()<<k_funcinfo<<
"Could not load interval"<<endl;
426 if (m_intervals.isEmpty()) {
429 m_actualEffort.load(element);
433void Appointment::saveXML(TQDomElement &element)
const {
434 if (m_intervals.isEmpty()) {
435 kdError()<<k_funcinfo<<
"Incomplete appointment data: No intervals"<<endl;
437 if (m_resource == 0 || m_resource->resource() == 0) {
438 kdError()<<k_funcinfo<<
"Incomplete appointment data: No resource"<<endl;
441 if (m_node == 0 || m_node->node() == 0) {
442 kdError()<<k_funcinfo<<
"Incomplete appointment data: No node"<<endl;
446 TQDomElement me = element.ownerDocument().createElement(
"appointment");
447 element.appendChild(me);
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);
455 m_actualEffort.save(me);
461 TQPtrListIterator<AppointmentInterval> it = m_intervals;
462 for (; it.current(); ++it) {
463 d += it.current()->effort();
469Duration Appointment::plannedEffort(
const TQDate &date)
const {
473 TQPtrListIterator<AppointmentInterval> it = m_intervals;
474 for (; it.current(); ++it) {
475 d += it.current()->effort(s, e);
481Duration Appointment::plannedEffortTo(
const TQDate& date)
const {
484 TQPtrListIterator<AppointmentInterval> it = m_intervals;
485 for (; it.current(); ++it) {
486 d += it.current()->effort(e,
true);
493EffortCostMap Appointment::plannedPrDay(
const TQDate& start,
const TQDate& end)
const {
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();
506 if (dt.date() < st.date()) {
507 dt.setDate(st.date());
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() ) {
516 ndt = TQDateTime(ndt.addDays(1));
528 return m_actualEffort.usedEffort();
532Duration Appointment::actualEffort(
const TQDate &date)
const {
533 return m_actualEffort.usedEffort(date);
537Duration Appointment::actualEffortTo(
const TQDate &date)
const {
538 return m_actualEffort.usedEffortTo(date);
541double Appointment::plannedCost() {
542 if (m_resource && m_resource->resource()) {
543 return plannedEffort().toDouble(Duration::Unit_h) * m_resource->resource()->normalRate();
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();
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();
565double Appointment::actualCost() {
567 if (m_resource && m_resource->resource()) {
568 return (m_actualEffort.usedEffort(
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime().toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
574double Appointment::actualCost(
const TQDate &date) {
575 if (m_resource && m_resource->resource()) {
576 return (m_actualEffort.usedEffort(date,
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertime(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
582double Appointment::actualCostTo(
const TQDate &date) {
583 if (m_resource && m_resource->resource()) {
584 return (m_actualEffort.usedEffortTo(date,
false ).toDouble(Duration::Unit_h)*m_resource->resource()->normalRate()) + (m_actualEffort.usedOvertimeTo(date).toDouble(Duration::Unit_h)*m_resource->resource()->overtimeRate());
589void Appointment::addActualEffort(TQDate date,
Duration effort,
bool overtime) {
590 m_actualEffort.inSort(date, effort, overtime);
593bool Appointment::attach() {
595 if (m_resource && m_node) {
596 m_resource->add(
this);
600 kdWarning()<<k_funcinfo<<
"Failed: "<<(m_resource ?
"" :
"resource=0 ")
601 <<(m_node ?
"" :
"node=0")<<endl;
605void Appointment::detach() {
608 m_resource->takeAppointment(
this);
611 m_node->takeAppointment(
this);
618 TQPtrListIterator<AppointmentInterval> it = m_intervals;
619 for (; it.current(); ++it) {
620 d += it.current()->effort(start, end);
627 TQPtrListIterator<AppointmentInterval> it = m_intervals;
628 for (; it.current(); ++it) {
629 d += it.current()->effort(start, start+duration);
636 TQPtrListIterator<AppointmentInterval> it = m_intervals;
637 for (; it.current(); ++it) {
638 d += it.current()->effort(time,
false);
644 m_resource = app.resource();
646 m_repeatInterval = app.repeatInterval();
647 m_repeatCount = app.repeatCount();
650 TQPtrListIterator<AppointmentInterval> it = app.intervals();
651 for (; it.current(); ++it) {
652 addInterval(
new AppointmentInterval(*(it.current())));
657Appointment &Appointment::operator+=(
const Appointment &app) {
662Appointment Appointment::operator+(
const Appointment &app) {
664 AppointmentIntervalList ai = app.intervals();
665 AppointmentInterval i;
666 AppointmentInterval *i1 = m_intervals.first();
667 AppointmentInterval *i2 = ai.first();
671 if (!from.isValid() || from < i2->startTime())
672 from = i2->startTime();
673 a.addInterval(from, i2->endTime(), i2->load());
675 from = i2->endTime();
680 if (!from.isValid() || from < i1->startTime())
681 from = i1->startTime();
682 a.addInterval(from, i1->endTime(), i1->load());
684 from = i1->endTime();
685 i1 = m_intervals.next();
688 i = i1->firstInterval(*i2, from);
695 if (i1 && a.endTime() >= i1->endTime()) {
696 i1 = m_intervals.next();
698 if (i2 && a.endTime() >= i2->endTime()) {
706void Appointment::printDebug(TQString indent)
710 kdDebug()<<indent<<
" No node schedule"<<endl;
712 }
else if (m_node->node() == 0) {
713 kdDebug()<<indent<<
" No node"<<endl;
716 if (m_resource == 0) {
717 kdDebug()<<indent<<
" No resource schedule"<<endl;
719 }
else if (m_resource->resource() == 0) {
720 kdDebug()<<indent<<
" No resource"<<endl;
725 kdDebug()<<indent<<
" + Appointment to schedule: "<<m_node->name()<<
" ("<<m_node->type()<<
")"<<
" resource: "<<m_resource->resource()->name()<<endl;
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;
A resource (Resource) can be scheduled to be used at any time, this is represented internally with Ap...
DateTime is a TQDateTime which knows about Duration.
The duration class can be used to store a timespan in a convenient format.
static const Duration zeroDuration
This is useful for occasions where we need a zero duration.