00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kptschedule.h"
00021
00022 #include "kptappointment.h"
00023 #include "kptdatetime.h"
00024 #include "kptduration.h"
00025 #include "kptnode.h"
00026
00027 #include <qdom.h>
00028 #include <qstring.h>
00029 #include <qstringlist.h>
00030
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033
00034 namespace KPlato
00035 {
00036
00037 Schedule::Schedule()
00038 : m_type(Expected),
00039 m_id(0),
00040 m_deleted(false),
00041 m_parent(0) {
00042 }
00043
00044 Schedule::Schedule(Schedule *parent)
00045 : m_type(Expected),
00046 m_id(0),
00047 m_deleted(false),
00048 m_appointments(),
00049 m_parent(parent) {
00050
00051 if (parent) {
00052 m_name = parent->name();
00053 m_type = parent->type();
00054 m_id = parent->id();
00055 }
00056 m_appointments.setAutoDelete(true);
00057
00058 }
00059
00060 Schedule::Schedule(QString name, Type type, long id)
00061 : m_name(name),
00062 m_type(type),
00063 m_id(id),
00064 m_deleted(false),
00065 m_appointments(),
00066 m_parent(0) {
00067
00068
00069 m_appointments.setAutoDelete(true);
00070 }
00071
00072 Schedule::~Schedule() {
00073 }
00074
00075 void Schedule::setParent(Schedule *parent) {
00076 m_parent = parent;
00077 }
00078
00079 void Schedule::setDeleted(bool on) {
00080
00081 m_deleted = on;
00082 }
00083
00084 bool Schedule::isDeleted() const {
00085 return m_parent == 0 ? m_deleted : m_parent->isDeleted();
00086 }
00087
00088 void Schedule::setType(const QString type) {
00089 m_type = Expected;
00090 if (type == "Expected")
00091 m_type = Expected;
00092 else if (type == "Optimistic")
00093 m_type = Optimistic;
00094 else if (type == "Pessimistic")
00095 m_type = Pessimistic;
00096 }
00097
00098 QString Schedule::typeToString(bool translate) const {
00099 if (translate) {
00100 if (m_type == Expected)
00101 return i18n("Expected");
00102 if (m_type == Optimistic)
00103 return i18n("Optimistic");
00104 if (m_type == Pessimistic)
00105 return i18n("Pessimistic");
00106 return i18n("Expected");
00107 } else {
00108 if (m_type == Expected)
00109 return "Expected";
00110 if (m_type == Optimistic)
00111 return "Optimistic";
00112 if (m_type == Pessimistic)
00113 return "Pessimistic";
00114 return "Expected";
00115 }
00116 }
00117
00118 void Schedule::initiateCalculation() {
00119 resourceError = false;
00120 resourceOverbooked = false;
00121 schedulingError = false;
00122 inCriticalPath = false;
00123 workStartTime = DateTime();
00124 workEndTime = DateTime();
00125 }
00126
00127 void Schedule::calcResourceOverbooked() {
00128 resourceOverbooked = false;
00129 QPtrListIterator<Appointment> it = m_appointments;
00130 for (; it.current(); ++it) {
00131 if (it.current()->resource()->isOverbooked(startTime, endTime)) {
00132 resourceOverbooked = true;
00133 break;
00134 }
00135 }
00136 }
00137
00138 QStringList Schedule::overbookedResources() const {
00139 QStringList rl;
00140 QPtrListIterator<Appointment> it = m_appointments;
00141 for (; it.current(); ++it) {
00142 if (it.current()->resource()->isOverbooked(it.current()->startTime(), it.current()->endTime())) {
00143 rl += it.current()->resource()->resource()->name();
00144 }
00145 }
00146 return rl;
00147 }
00148
00149 bool Schedule::loadXML(const QDomElement &sch) {
00150 m_name = sch.attribute("name");
00151 setType(sch.attribute("type"));
00152 m_id = sch.attribute("id").toLong();
00153 return true;
00154 }
00155
00156 void Schedule::saveXML(QDomElement &element) const {
00157 QDomElement sch = element.ownerDocument().createElement("schedule");
00158 element.appendChild(sch);
00159 saveCommonXML(sch);
00160 }
00161
00162 void Schedule::saveCommonXML(QDomElement &element) const {
00163
00164 element.setAttribute("name", m_name);
00165 element.setAttribute("type", typeToString());
00166 element.setAttribute("id", m_id);
00167 }
00168
00169 void Schedule::saveAppointments(QDomElement &element) const {
00170
00171 QPtrListIterator<Appointment> it = m_appointments;
00172 for (; it.current(); ++it) {
00173 it.current()->saveXML(element);
00174 }
00175 }
00176
00177 bool Schedule::add(Appointment *appointment) {
00178 if (m_appointments.findRef(appointment) != -1) {
00179 kdError()<<k_funcinfo<<"Appointment allready exists"<<endl;
00180 return false;
00181 }
00182 m_appointments.append(appointment);
00183
00184
00185 return true;
00186 }
00187
00188 void Schedule::removeAppointment(Appointment *appointment) {
00189 takeAppointment(appointment);
00190 delete appointment;
00191 }
00192
00193 void Schedule::takeAppointment(Appointment *appointment) {
00194 int i = m_appointments.findRef(appointment);
00195 if (i != -1) {
00196 m_appointments.take(i);
00197
00198 if (appointment->node())
00199 appointment->node()->takeAppointment(appointment);
00200 } else {
00201
00202 }
00203 }
00204
00205 Appointment *Schedule::findAppointment(Schedule *resource, Schedule *node) {
00206 QPtrListIterator<Appointment> it = m_appointments;
00207 for (; it.current(); ++it) {
00208 if (it.current()->node() == node && it.current()->resource() == resource)
00209 return it.current();
00210 }
00211 return 0;
00212 }
00213
00214 EffortCostMap Schedule::plannedEffortCostPrDay(const QDate &start, const QDate &end) const {
00215
00216 EffortCostMap ec;
00217 QPtrListIterator<Appointment> it(m_appointments);
00218 for (; it.current(); ++it) {
00219
00220 ec += it.current()->plannedPrDay(start, end);
00221 }
00222 return ec;
00223 }
00224
00225 Duration Schedule::plannedEffort() const {
00226
00227 Duration eff;
00228 QPtrListIterator<Appointment> it(m_appointments);
00229 for (; it.current(); ++it) {
00230 eff += it.current()->plannedEffort();
00231 }
00232 return eff;
00233 }
00234
00235 Duration Schedule::plannedEffort(const QDate &date) const {
00236
00237 Duration eff;
00238 QPtrListIterator<Appointment> it(m_appointments);
00239 for (; it.current(); ++it) {
00240 eff += it.current()->plannedEffort(date);
00241 }
00242 return eff;
00243 }
00244
00245 Duration Schedule::plannedEffortTo(const QDate &date) const {
00246
00247 Duration eff;
00248 QPtrListIterator<Appointment> it(m_appointments);
00249 for (; it.current(); ++it) {
00250 eff += it.current()->plannedEffortTo(date);
00251 }
00252 return eff;
00253 }
00254
00255 Duration Schedule::actualEffort() const {
00256
00257 Duration eff;
00258 QPtrListIterator<Appointment> it(m_appointments);
00259 for (; it.current(); ++it) {
00260 eff += it.current()->actualEffort();
00261 }
00262 return eff;
00263 }
00264
00265 Duration Schedule::actualEffort(const QDate &date) const {
00266
00267 Duration eff;
00268 QPtrListIterator<Appointment> it(m_appointments);
00269 for (; it.current(); ++it) {
00270 eff += it.current()->actualEffort(date);
00271 }
00272 return eff;
00273 }
00274
00275 Duration Schedule::actualEffortTo(const QDate &date) const {
00276
00277 Duration eff;
00278 QPtrListIterator<Appointment> it(m_appointments);
00279 for (; it.current(); ++it) {
00280 eff += it.current()->actualEffortTo(date);
00281 }
00282 return eff;
00283 }
00284
00285 double Schedule::plannedCost() const {
00286
00287 double c = 0;
00288 QPtrListIterator<Appointment> it(m_appointments);
00289 for (; it.current(); ++it) {
00290 c += it.current()->plannedCost();
00291 }
00292 return c;
00293 }
00294
00295 double Schedule::plannedCost(const QDate &date) const {
00296
00297 double c = 0;
00298 QPtrListIterator<Appointment> it(m_appointments);
00299 for (; it.current(); ++it) {
00300 c += it.current()->plannedCost(date);
00301 }
00302 return c;
00303 }
00304
00305 double Schedule::plannedCostTo(const QDate &date) const {
00306
00307 double c = 0;
00308 QPtrListIterator<Appointment> it(m_appointments);
00309 for (; it.current(); ++it) {
00310 c += it.current()->plannedCostTo(date);
00311 }
00312 return c;
00313 }
00314
00315 double Schedule::actualCost() const {
00316
00317 double c = 0;
00318 QPtrListIterator<Appointment> it(m_appointments);
00319 for (; it.current(); ++it) {
00320 c += it.current()->actualCost();
00321 }
00322 return c;
00323 }
00324
00325 double Schedule::actualCost(const QDate &date) const {
00326
00327 double c = 0;
00328 QPtrListIterator<Appointment> it(m_appointments);
00329 for (; it.current(); ++it) {
00330 c += it.current()->actualCost(date);
00331 }
00332 return c;
00333 }
00334
00335 double Schedule::actualCostTo(const QDate &date) const {
00336
00337 double c = 0;
00338 QPtrListIterator<Appointment> it(m_appointments);
00339 for (; it.current(); ++it) {
00340 c += it.current()->actualCostTo(date);
00341 }
00342 return c;
00343 }
00344
00345
00346 NodeSchedule::NodeSchedule()
00347 : Schedule(),
00348 m_node(0) {
00349
00350 init();
00351 }
00352
00353 NodeSchedule::NodeSchedule(Node *node, QString name, Schedule::Type type, long id)
00354 : Schedule(name, type, id),
00355 m_node(node) {
00356
00357 init();
00358 }
00359
00360 NodeSchedule::NodeSchedule(Schedule *parent, Node *node)
00361 : Schedule(parent),
00362 m_node(node) {
00363
00364
00365 init();
00366 }
00367
00368 NodeSchedule::~NodeSchedule() {
00369
00370 }
00371
00372 void NodeSchedule::init() {
00373 resourceError = false;
00374 resourceOverbooked = false;
00375 resourceNotAvailable = false;
00376 schedulingError = false;
00377 notScheduled = true;
00378 inCriticalPath = false;
00379 }
00380
00381 void NodeSchedule::setDeleted(bool on) {
00382
00383 m_deleted = on;
00384
00385 QPtrListIterator<Appointment> it = m_appointments;
00386 for (; it.current(); ++it) {
00387 if (it.current()->resource()) {
00388 it.current()->resource()->setDeleted(on);
00389 }
00390 }
00391 }
00392
00393 bool NodeSchedule::loadXML(const QDomElement &sch) {
00394
00395 QString s;
00396 Schedule::loadXML(sch);
00397 s = sch.attribute("earlieststart");
00398 if (s != "")
00399 earliestStart = DateTime::fromString(s);
00400 s = sch.attribute("latestfinish");
00401 if (s != "")
00402 latestFinish = DateTime::fromString(s);
00403 s = sch.attribute("start");
00404 if (s != "")
00405 startTime = DateTime::fromString(s);
00406 s = sch.attribute("end");
00407 if (s != "")
00408 endTime = DateTime::fromString(s);
00409 s = sch.attribute("start-work");
00410 if (s != "")
00411 workStartTime = DateTime::fromString(s);
00412 s = sch.attribute("end-work");
00413 if (s != "")
00414 workEndTime = DateTime::fromString(s);
00415 duration = Duration::fromString(sch.attribute("duration"));
00416
00417 inCriticalPath = sch.attribute("in-critical-path", "0").toInt();
00418 resourceError = sch.attribute("resource-error", "0").toInt();
00419 resourceOverbooked = sch.attribute("resource-overbooked", "0").toInt();
00420 resourceNotAvailable = sch.attribute("resource-not-available", "0").toInt();
00421 schedulingError = sch.attribute("scheduling-conflict", "0").toInt();
00422 notScheduled = sch.attribute("not-scheduled", "1").toInt();
00423
00424 return true;
00425 }
00426
00427 void NodeSchedule::saveXML(QDomElement &element) const {
00428
00429 QDomElement sch = element.ownerDocument().createElement("schedule");
00430 element.appendChild(sch);
00431 saveCommonXML(sch);
00432
00433 if (earliestStart.isValid())
00434 sch.setAttribute("earlieststart",earliestStart.toString(Qt::ISODate));
00435 if (latestFinish.isValid())
00436 sch.setAttribute("latestfinish",latestFinish.toString(Qt::ISODate));
00437 if (startTime.isValid())
00438 sch.setAttribute("start",startTime.toString(Qt::ISODate));
00439 if (endTime.isValid())
00440 sch.setAttribute("end",endTime.toString(Qt::ISODate));
00441 if (workStartTime.isValid())
00442 sch.setAttribute("start-work", workStartTime.toString(Qt::ISODate));
00443 if (workEndTime.isValid())
00444 sch.setAttribute("end-work", workEndTime.toString(Qt::ISODate));
00445
00446 sch.setAttribute("duration",duration.toString());
00447
00448 sch.setAttribute("in-critical-path",inCriticalPath);
00449 sch.setAttribute("resource-error",resourceError);
00450 sch.setAttribute("resource-overbooked",resourceOverbooked);
00451 sch.setAttribute("resource-not-available",resourceNotAvailable);
00452 sch.setAttribute("scheduling-conflict",schedulingError);
00453 sch.setAttribute("not-scheduled",notScheduled);
00454 }
00455
00456 void NodeSchedule::addAppointment(Schedule *resource, DateTime &start, DateTime &end, double load) {
00457
00458 Appointment *a = findAppointment(resource, this);
00459 if (a != 0) {
00460
00461 a->addInterval(start, end, load);
00462 return;
00463 }
00464 a = new Appointment(resource, this, start, end, load);
00465 if (!add(a)) {
00466 delete a;
00467 }
00468 if (!resource->add(a)) {
00469 delete a;
00470 }
00471 }
00472
00473
00474 ResourceSchedule::ResourceSchedule()
00475 : Schedule(),
00476 m_resource(0) {
00477
00478 }
00479
00480 ResourceSchedule::ResourceSchedule(Resource *resource, QString name, Schedule::Type type, long id)
00481 : Schedule(name, type, id),
00482 m_resource(resource),
00483 m_parent(0) {
00484
00485 }
00486
00487 ResourceSchedule::ResourceSchedule(Schedule *parent, Resource *resource)
00488 : Schedule(parent),
00489 m_resource(resource),
00490 m_parent(parent) {
00491
00492 }
00493
00494 ResourceSchedule::~ResourceSchedule() {
00495
00496 }
00497
00498 void ResourceSchedule::addAppointment(Schedule *node, DateTime &start, DateTime &end, double load) {
00499
00500 Appointment *a = findAppointment(this, node);
00501 if (a != 0) {
00502
00503 a->addInterval(start, end, load);
00504 return;
00505 }
00506 a = new Appointment(this, node, start, end, load);
00507 if (!add(a)) {
00508 delete a;
00509 }
00510 if (!node->add(a)) {
00511 delete a;
00512 }
00513 }
00514
00515 bool ResourceSchedule::isOverbooked() const {
00516 return false;
00517 }
00518
00519 bool ResourceSchedule::isOverbooked(const DateTime &start, const DateTime &end) const {
00520 if (m_resource == 0)
00521 return false;
00522
00523 Appointment a = appointmentIntervals();
00524 QPtrListIterator<AppointmentInterval> it = a.intervals();
00525 for (; it.current(); ++it) {
00526 if ((!end.isValid() || it.current()->startTime() < end) &&
00527 (!start.isValid() || it.current()->endTime() > start))
00528 {
00529 if (it.current()->load() > m_resource->units()) {
00530
00531 return true;
00532 }
00533 }
00534 if (it.current()->startTime() >= end)
00535 break;
00536 }
00537
00538 return false;
00539 }
00540
00541 Appointment ResourceSchedule::appointmentIntervals() const {
00542 Appointment a;
00543 QPtrListIterator<Appointment> it = m_appointments;
00544 for (; it.current(); ++it) {
00545 a += *(it.current());
00546 }
00547 return a;
00548 }
00549
00550 double ResourceSchedule::normalRatePrHour() const {
00551 return m_resource ? m_resource->normalRate() : 0.0;
00552 }
00553
00554
00555 MainSchedule::MainSchedule()
00556 : NodeSchedule() {
00557
00558 init();
00559 }
00560
00561 MainSchedule::MainSchedule(Node *node, QString name, Schedule::Type type, long id)
00562 : NodeSchedule(node, name, type, id) {
00563
00564 init();
00565 }
00566
00567 MainSchedule::~MainSchedule() {
00568
00569 }
00570
00571 bool MainSchedule::loadXML(const QDomElement &sch, Project &project) {
00572 kdDebug()<<k_funcinfo<<endl;
00573 QString s;
00574 Schedule::loadXML(sch);
00575
00576 s = sch.attribute("start");
00577 if (s != "")
00578 startTime = DateTime::fromString(s);
00579 s = sch.attribute("end");
00580 if (s != "")
00581 endTime = DateTime::fromString(s);
00582
00583 QDomNodeList al = sch.childNodes();
00584 kdDebug()<<k_funcinfo<<"No of appointments: "<<al.count()<<endl;
00585 for (unsigned int i=0; i<al.count(); ++i) {
00586 if (al.item(i).isElement()) {
00587 QDomElement app = al.item(i).toElement();
00588 if (app.tagName() == "appointment") {
00589
00590
00591 Appointment *child = new Appointment();
00592 if (!child->loadXML(app, project, *this)) {
00593
00594 kdError()<<k_funcinfo<<"Failed to load appointment"<<endl;
00595 delete child;
00596 }
00597 }
00598 }
00599 }
00600 return true;
00601 }
00602
00603 void MainSchedule::saveXML(QDomElement &element) const {
00604 saveCommonXML(element);
00605
00606 element.setAttribute("start",startTime.toString(Qt::ISODate));
00607 element.setAttribute("end",endTime.toString(Qt::ISODate));
00608 }
00609
00610 #ifndef NDEBUG
00611 void Schedule::printDebug(QString indent) {
00612 kdDebug()<<indent<<"Schedule["<<m_id<<"] '"<<m_name<<"' type: "<<typeToString()<<" ("<<m_type<<")"<<(isDeleted()?" Deleted":"")<<endl;
00613 }
00614 void NodeSchedule::printDebug(QString indent) {
00615 Schedule::printDebug(indent);
00616 indent += "! ";
00617 if (m_parent == 0)
00618 kdDebug()<<indent<<"No parent schedule!"<<endl;
00619 if (!notScheduled) {
00620 if (node()) kdDebug()<<indent<<"Node: "<<node()->name()<<endl;
00621 else kdDebug()<<indent<<"No parent node!"<<endl;
00622 }
00623 kdDebug()<<indent<<"Not scheduled="<<notScheduled<<endl;
00624 kdDebug()<<indent<<"Start time: "<<startTime.toString()<<endl;
00625 kdDebug()<<indent<<"End time: " <<endTime.toString()<<endl;
00626 kdDebug()<<indent<<"Duration: "<<duration.seconds()<<QCString(" secs")<<" ("<<duration.toString()<<")"<<endl;
00627 kdDebug()<<indent<<"Earliest start: "<<earliestStart.toString()<<endl;
00628 kdDebug()<<indent<<"Latest finish: " <<latestFinish.toString()<<endl;
00629
00630 kdDebug()<<indent<<"resourceError="<<resourceError<<endl;
00631 kdDebug()<<indent<<"schedulingError="<<schedulingError<<endl;
00632 kdDebug()<<indent<<"resourceNotAvailable="<<resourceNotAvailable<<endl;
00633 kdDebug()<<indent<<"Resource overbooked="<<resourceOverbooked<<endl;
00634 kdDebug()<<indent<<" "<<overbookedResources()<<endl;
00635
00636 kdDebug()<<indent<<"inCriticalPath="<<inCriticalPath<<endl;
00637 kdDebug()<<indent<<endl;
00638 kdDebug()<<indent<<"workStartTime="<<workStartTime.toString()<<endl;
00639 kdDebug()<<indent<<"workEndTime="<<workEndTime.toString()<<endl;
00640 kdDebug()<<indent<<endl;
00641 kdDebug()<<indent<<"Appointments: "<<m_appointments.count()<<endl;
00642 QPtrListIterator<Appointment> it = m_appointments;
00643 for (; it.current(); ++it) {
00644 it.current()->printDebug(indent + " ");
00645 }
00646 }
00647 void ResourceSchedule::printDebug(QString indent) {
00648 Schedule::printDebug(indent);
00649 indent += "! ";
00650 if (m_parent == 0)
00651 kdDebug()<<indent<<"No parent schedule!"<<endl;
00652 if (resource()) kdDebug()<<indent<<"Resource: "<<resource()->name()<<endl;
00653 else kdDebug()<<indent<<"No parent resource!"<<endl;
00654 kdDebug()<<indent<<endl;
00655 kdDebug()<<indent<<"Appointments: "<<m_appointments.count()<<endl;
00656 }
00657
00658 void MainSchedule::printDebug(QString indent) {
00659 Schedule::printDebug(indent);
00660 indent += "! ";
00661 if (node()) kdDebug()<<indent<<"Node: "<<node()->name()<<endl;
00662 else kdDebug()<<indent<<"No parent node!"<<endl;
00663
00664 kdDebug()<<indent<<"Not scheduled="<<notScheduled<<endl;
00665 kdDebug()<<indent<<"Start time: "<<startTime.toString()<<endl;
00666 kdDebug()<<indent<<"End time: " <<endTime.toString()<<endl;
00667 kdDebug()<<indent<<"Duration: "<<duration.seconds()<<QCString(" secs")<<" ("<<duration.toString()<<")"<<endl;
00668 kdDebug()<<indent<<"Earliest start: "<<earliestStart.toString()<<endl;
00669 kdDebug()<<indent<<"Latest finish: " <<latestFinish.toString()<<endl;
00670
00671 kdDebug()<<indent<<endl;
00672 kdDebug()<<indent<<"Appointments: "<<m_appointments.count()<<endl;
00673 QPtrListIterator<Appointment> it = m_appointments;
00674 for (; it.current(); ++it) {
00675 it.current()->printDebug(indent + " ");
00676 }
00677 }
00678 #endif
00679
00680 }
00681