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