00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "kptresource.h"
00022 #include "kptappointment.h"
00023 #include "kptproject.h"
00024 #include "kpttask.h"
00025 #include "kptdatetime.h"
00026 #include "kptcalendar.h"
00027 #include "kpteffortcostmap.h"
00028 #include "kptschedule.h"
00029
00030 #include <kdebug.h>
00031 #include <kglobal.h>
00032 #include <klocale.h>
00033
00034 #include <QList>
00035
00036 namespace KPlato
00037 {
00038
00039 ResourceGroup::ResourceGroup(Project *project) {
00040 m_project = project;
00041 m_type = Type_Work;
00042 generateId();
00043
00044 }
00045
00046 ResourceGroup::~ResourceGroup() {
00047
00048 if (findId() == this) {
00049 removeId();
00050 }
00051 while (!m_resources.isEmpty()) {
00052 delete m_resources.takeFirst();
00053 }
00054
00055 }
00056
00057 bool ResourceGroup::setId(QString id) {
00058
00059 if (id.isEmpty()) {
00060 kError()<<k_funcinfo<<"id is empty"<<endl;
00061 m_id = id;
00062 return false;
00063 }
00064 ResourceGroup *g = findId();
00065 if (g == this) {
00066
00067 removeId();
00068 } else if (g) {
00069
00070 kError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different group: "<<g->name()<<endl;
00071 }
00072 if (findId(id)) {
00073 kError()<<k_funcinfo<<"id '"<<id<<"' is already used for different group: "<<findId(id)->name()<<endl;
00074 m_id = QString();
00075 return false;
00076 }
00077 m_id = id;
00078 insertId(id);
00079
00080 return true;
00081 }
00082
00083 void ResourceGroup::generateId() {
00084 if (!m_id.isEmpty()) {
00085 removeId();
00086 }
00087 for (int i=0; i<32000 ; ++i) {
00088 m_id = m_id.setNum(i);
00089 if (!findId()) {
00090 insertId(m_id);
00091 return;
00092 }
00093 }
00094 m_id = QString();
00095 }
00096
00097 void ResourceGroup::addResource(Resource* resource, Risk*) {
00098 m_resources.append(resource);
00099 }
00100
00101 Resource* ResourceGroup::getResource(int) {
00102 return 0L;
00103 }
00104
00105 Risk* ResourceGroup::getRisk(int) {
00106 return 0L;
00107 }
00108
00109 void ResourceGroup::deleteResource(Resource *resource) {
00110 int i = m_resources.indexOf(resource);
00111 if (i != -1)
00112 m_resources.removeAt(i);
00113 delete resource;
00114 }
00115
00116 Resource *ResourceGroup::takeResource(Resource *resource) {
00117 int i = m_resources.indexOf(resource);
00118 if (i != -1)
00119 return m_resources.takeAt(i);
00120 return 0;
00121 }
00122
00123 void ResourceGroup::deleteResource(int) {
00124 }
00125
00126 void ResourceGroup::addRequiredResource(ResourceGroup*) {
00127 }
00128
00129 ResourceGroup* ResourceGroup::getRequiredResource(int) {
00130 return 0L;
00131 }
00132
00133 void ResourceGroup::deleteRequiredResource(int) {
00134 }
00135
00136 bool ResourceGroup::load(QDomElement &element) {
00137
00138 setId(element.attribute("id"));
00139 m_name = element.attribute("name");
00140
00141 QDomNodeList list = element.childNodes();
00142 for (unsigned int i=0; i<list.count(); ++i) {
00143 if (list.item(i).isElement()) {
00144 QDomElement e = list.item(i).toElement();
00145 if (e.tagName() == "resource") {
00146
00147 Resource *child = new Resource(m_project);
00148 if (child->load(e))
00149 addResource(child, 0);
00150 else
00151
00152 delete child;
00153 }
00154 }
00155 }
00156 return true;
00157 }
00158
00159 void ResourceGroup::save(QDomElement &element) const {
00160
00161
00162 QDomElement me = element.ownerDocument().createElement("resource-group");
00163 element.appendChild(me);
00164
00165 me.setAttribute("id", m_id);
00166 me.setAttribute("name", m_name);
00167
00168 foreach (Resource *r, m_resources) {
00169 r->save(me);
00170 }
00171 }
00172
00173 void ResourceGroup::initiateCalculation(Schedule &sch) {
00174 foreach (Resource *r, m_resources) {
00175 r->initiateCalculation(sch);
00176 }
00177 clearNodes();
00178 }
00179
00180 int ResourceGroup::units() {
00181 int u = 0;
00182 foreach (Resource *r, m_resources) {
00183 u += r->units();
00184 }
00185 return u;
00186 }
00187
00188 ResourceGroup *ResourceGroup::findId(const QString &id) const {
00189 return m_project ? m_project->findResourceGroup(id) : 0;
00190 }
00191
00192 bool ResourceGroup::removeId(const QString &id) {
00193 return m_project ? m_project->removeResourceGroupId(id): false;
00194 }
00195
00196 void ResourceGroup::insertId(const QString &id) {
00197 if (m_project)
00198 m_project->insertResourceGroupId(id, this);
00199 }
00200
00201 Appointment ResourceGroup::appointmentIntervals() const {
00202 Appointment a;
00203 foreach (Resource *r, m_resources) {
00204 a += r->appointmentIntervals();
00205 }
00206 return a;
00207 }
00208
00209 Resource::Resource(Project *project) : m_project(project), m_schedules(), m_workingHours() {
00210 m_type = Type_Work;
00211 m_units = 100;
00212
00213 m_availableFrom = DateTime(QDate::currentDate());
00214 m_availableUntil = m_availableFrom.addYears(2);
00215
00216 cost.normalRate = 100;
00217 cost.overtimeRate = 200;
00218 cost.fixed = 0;
00219 m_calendar = 0;
00220 m_currentSchedule = 0;
00221 generateId();
00222
00223 }
00224
00225 Resource::Resource(Resource *resource) {
00226
00227 copy(resource);
00228 }
00229
00230 Resource::~Resource() {
00231
00232 if (findId() == this) {
00233 removeId();
00234 }
00235 foreach (ResourceRequest *r, m_requests) {
00236 r->setResource(0);
00237 }
00238 foreach (ResourceRequest *r, m_requests) {
00239 r->parent()->deleteResourceRequest(r);
00240 }
00241 foreach (long key, m_schedules.keys()) {
00242 delete m_schedules.take(key);
00243 }
00244 }
00245
00246 bool Resource::setId(QString id) {
00247
00248 if (id.isEmpty()) {
00249 kError()<<k_funcinfo<<"id is empty"<<endl;
00250 m_id = id;
00251 return false;
00252 }
00253 Resource *r = findId();
00254 if (r == this) {
00255
00256 removeId();
00257 } else if (r) {
00258
00259 kError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different resource: "<<r->name()<<endl;
00260 }
00261 if (findId(id)) {
00262 kError()<<k_funcinfo<<"id '"<<id<<"' is already used for different resource: "<<findId(id)->name()<<endl;
00263 m_id = QString();
00264 return false;
00265 }
00266 m_id = id;
00267 insertId(id);
00268
00269 return true;
00270 }
00271
00272 void Resource::generateId() {
00273 if (!m_id.isEmpty()) {
00274 removeId();
00275 }
00276 for (int i=0; i<32000 ; ++i) {
00277 m_id = m_id.setNum(i);
00278 if (!findId()) {
00279 insertId(m_id);
00280
00281 return;
00282 }
00283 }
00284 m_id = QString();
00285 }
00286
00287 void Resource::setType(const QString &type) {
00288 if (type == "Work")
00289 m_type = Type_Work;
00290 else if (type == "Material")
00291 m_type = Type_Material;
00292 }
00293
00294 QString Resource::typeToString() const {
00295 if (m_type == Type_Work)
00296 return QString("Work");
00297 else if (m_type == Type_Material)
00298 return QString("Material");
00299
00300 return QString();
00301 }
00302
00303 void Resource::copy(Resource *resource) {
00304 m_project = resource->project();
00305
00306 m_id = resource->id();
00307 m_name = resource->name();
00308 m_initials = resource->initials();
00309 m_email = resource->email();
00310 m_availableFrom = resource->availableFrom();
00311 m_availableUntil = resource->availableUntil();
00312 m_workingHours.clear();
00313 m_workingHours = resource->workingHours();
00314
00315 m_units = resource->units();
00316
00317 m_type = resource->type();
00318
00319 cost.normalRate = resource->normalRate();
00320 cost.overtimeRate = resource->overtimeRate();
00321 cost.fixed = resource->fixedCost();
00322
00323 m_calendar = resource->m_calendar;
00324 }
00325
00326 void Resource::addWorkingHour(QTime from, QTime until) {
00327
00328 m_workingHours.append(new QTime(from));
00329 m_workingHours.append(new QTime(until));
00330 }
00331
00332 Calendar *Resource::calendar(bool local) const {
00333 if (!local && project() != 0 && (m_calendar == 0 || m_calendar->isDeleted())) {
00334 return project()->defaultCalendar();
00335 }
00336 if (m_calendar && m_calendar->isDeleted()) {
00337 return 0;
00338 }
00339 return m_calendar;
00340 }
00341
00342 DateTime Resource::getFirstAvailableTime(DateTime ) {
00343 return DateTime();
00344 }
00345
00346 DateTime Resource::getBestAvailableTime(Duration ) {
00347 return DateTime();
00348 }
00349
00350 DateTime Resource::getBestAvailableTime(const DateTime , const Duration ) {
00351 return DateTime();
00352 }
00353
00354 bool Resource::load(QDomElement &element) {
00355
00356 QString s;
00357 setId(element.attribute("id"));
00358 m_name = element.attribute("name");
00359 m_initials = element.attribute("initials");
00360 m_email = element.attribute("email");
00361 setType(element.attribute("type"));
00362 m_calendar = findCalendar(element.attribute("calendar-id"));
00363 m_units = element.attribute("units", "100").toInt();
00364 s = element.attribute("available-from");
00365 if (s != "")
00366 m_availableFrom = DateTime::fromString(s);
00367 s = element.attribute("available-until");
00368 if (s != "")
00369 m_availableUntil = DateTime::fromString(s);
00370
00371 cost.normalRate = KGlobal::locale()->readMoney(element.attribute("normal-rate"));
00372 cost.overtimeRate = KGlobal::locale()->readMoney(element.attribute("overtime-rate"));
00373 return true;
00374 }
00375
00376 void Resource::save(QDomElement &element) const {
00377
00378 QDomElement me = element.ownerDocument().createElement("resource");
00379 element.appendChild(me);
00380
00381 if (calendar(true))
00382 me.setAttribute("calendar-id", m_calendar->id());
00383 me.setAttribute("id", m_id);
00384 me.setAttribute("name", m_name);
00385 me.setAttribute("initials", m_initials);
00386 me.setAttribute("email", m_email);
00387 me.setAttribute("type", typeToString());
00388 me.setAttribute("units", m_units);
00389 me.setAttribute("available-from", m_availableFrom.toString(Qt::ISODate));
00390 me.setAttribute("available-until", m_availableUntil.toString(Qt::ISODate));
00391 me.setAttribute("normal-rate", KGlobal::locale()->formatMoney(cost.normalRate));
00392 me.setAttribute("overtime-rate", KGlobal::locale()->formatMoney(cost.overtimeRate));
00393 }
00394
00395 bool Resource::isAvailable(Task *) {
00396 bool busy = false;
00397
00398
00399
00400
00401
00402
00403
00404 return !busy;
00405 }
00406
00407 QList<Appointment*> Resource::appointments() {
00408 QList<Appointment*> lst;
00409 if (m_currentSchedule)
00410 lst = m_currentSchedule->appointments();
00411
00412 return lst;
00413 }
00414
00415 Appointment *Resource::findAppointment(Node *) {
00416
00417
00418
00419
00420
00421 return 0;
00422 }
00423
00424 bool Resource::addAppointment(Appointment *appointment) {
00425 if (m_currentSchedule)
00426 return m_currentSchedule->add(appointment);
00427 return false;
00428 }
00429
00430 bool Resource::addAppointment(Appointment *appointment, Schedule &main) {
00431 Schedule *s = findSchedule(main.id());
00432 if (s == 0) {
00433 s = createSchedule(&main);
00434 }
00435 appointment->setResource(s);
00436 return s->add(appointment);
00437 }
00438
00439 void Resource::addAppointment(Schedule *node, DateTime &start, DateTime &end, double load) {
00440
00441 Schedule *s = findSchedule(node->id());
00442 if (s == 0) {
00443 s = createSchedule(node->parent());
00444 }
00445 s->addAppointment(node, start, end, load);
00446 }
00447
00448 void Resource::initiateCalculation(Schedule &sch) {
00449 m_currentSchedule = createSchedule(&sch);
00450 }
00451
00452 void Resource::deleteSchedule(Schedule *schedule) {
00453 takeSchedule(schedule);
00454 delete schedule;
00455 }
00456
00457 void Resource::takeSchedule(const Schedule *schedule) {
00458 if (schedule == 0)
00459 return;
00460 if (m_currentSchedule == schedule)
00461 m_currentSchedule = 0;
00462 m_schedules.take(schedule->id());
00463 }
00464
00465 void Resource::addSchedule(Schedule *schedule) {
00466 if (schedule == 0)
00467 return;
00468 m_schedules.remove(schedule->id());
00469 m_schedules.insert(schedule->id(), schedule);
00470 }
00471
00472 ResourceSchedule *Resource::createSchedule(QString name, int type, long id) {
00473 ResourceSchedule *sch = new ResourceSchedule(this, name, (Schedule::Type)type, id);
00474 addSchedule(sch);
00475 return sch;
00476 }
00477
00478 ResourceSchedule *Resource::createSchedule(Schedule *parent) {
00479 ResourceSchedule *sch = new ResourceSchedule(parent, this);
00480 addSchedule(sch);
00481 return sch;
00482 }
00483
00484 void Resource::makeAppointment(Schedule *node, const DateTime &from, const DateTime &end) {
00485 if (!from.isValid() || !end.isValid()) {
00486 kWarning()<<k_funcinfo<<"Invalid time"<<endl;
00487 return;
00488 }
00489 Calendar *cal = calendar();
00490 if (cal == 0) {
00491 return;
00492 }
00493 DateTime time = from;
00494 while (time < end) {
00495
00496 if (!time.isValid() || !end.isValid()) {
00497 kWarning()<<k_funcinfo<<"Invalid time"<<endl;
00498 return;
00499 }
00500 if (!cal->hasInterval(time, end)) {
00501
00502 kWarning()<<k_funcinfo<<m_name<<": Resource only partially available"<<endl;
00503
00504 return;
00505 }
00506 DateTimeInterval i = cal->firstInterval(time, end);
00507 if (!i.second.isValid()) {
00508 kWarning()<<k_funcinfo<<"Invalid interval: "<<time<<", "<<end<<endl;
00509 return;
00510 }
00511 if (time == i.second)
00512 return;
00513 addAppointment(node, i.first, i.second, m_units);
00514
00515 if (!(node->workStartTime.isValid()) || i.first < node->workStartTime)
00516 node->workStartTime = i.first;
00517 if (!(node->workEndTime.isValid()) || i.second > node->workEndTime)
00518 node->workEndTime = i.second;
00519 time = i.second;
00520 }
00521 return;
00522 }
00523 void Resource::makeAppointment(Schedule *node) {
00524
00525 if (!node->startTime.isValid()) {
00526 kWarning()<<k_funcinfo<<m_name<<": startTime invalid"<<endl;
00527 return;
00528 }
00529 if (!node->endTime.isValid()) {
00530 kWarning()<<k_funcinfo<<m_name<<": endTime invalid"<<endl;
00531 return;
00532 }
00533 Calendar *cal = calendar();
00534 if (m_type == Type_Material) {
00535 DateTime from = availableAfter(node->startTime, node->endTime);
00536 DateTime end = availableBefore(node->endTime, node->startTime);
00537 if (!from.isValid() || !end.isValid()) {
00538 return;
00539 }
00540 if (cal == 0) {
00541
00542 addAppointment(node, from, end, m_units);
00543 return;
00544 }
00545 makeAppointment(node, from, end);
00546 }
00547 if (!cal) {
00548 kWarning()<<k_funcinfo<<m_name<<": No calendar defined"<<endl;
00549 return;
00550 }
00551
00552 DateTime time = node->startTime;
00553 DateTime end = node->endTime;
00554 time = availableAfter(time, end);
00555 if (!time.isValid()) {
00556 kWarning()<<k_funcinfo<<m_name<<": Resource not available (after="<<node->startTime<<", "<<end<<")"<<endl;
00557 node->resourceNotAvailable = true;
00558 return;
00559 }
00560 end = availableBefore(end, time);
00561 if (!end.isValid()) {
00562 kWarning()<<k_funcinfo<<m_name<<": Resource not available (before="<<node->endTime<<", "<<time<<")"<<endl;
00563 node->resourceNotAvailable = true;
00564 return;
00565 }
00566
00567 makeAppointment(node, time, end);
00568 }
00569
00570
00571 Duration Resource::effort(const DateTime &start, const Duration &duration, bool backward, bool *ok) const {
00572
00573 bool sts=false;
00574 Duration e;
00575 if (duration == 0) {
00576 kWarning()<<k_funcinfo<<"zero duration"<<endl;
00577 return e;
00578 }
00579 Calendar *cal = calendar();
00580 if (cal == 0) {
00581 kWarning()<<k_funcinfo<<m_name<<": No calendar defined"<<endl;
00582 return e;
00583 }
00584 if (backward) {
00585 DateTime limit = start - duration;
00586 DateTime t = availableBefore(start, limit);
00587 if (t.isValid()) {
00588 sts = true;
00589 e = (cal->effort(limit, t) * m_units)/100;
00590 } else {
00591
00592 }
00593 } else {
00594 DateTime limit = start + duration;
00595 DateTime t = availableAfter(start, limit);
00596 if (t.isValid()) {
00597 sts = true;
00598 e = (cal->effort(t, limit) * m_units)/100;
00599 }
00600 }
00601
00602 if (ok) *ok = sts;
00603 return e;
00604 }
00605
00606 DateTime Resource::availableAfter(const DateTime &time, const DateTime limit, bool checkAppointments) const {
00607 DateTime t;
00608 if (m_units == 0) {
00609 return t;
00610 }
00611 DateTime lmt = m_availableUntil;
00612 if (limit.isValid() && limit < lmt) {
00613 lmt = limit;
00614 }
00615 if (time >= lmt) {
00616 return t;
00617 }
00618 if (type() == Type_Material) {
00619 t = time > m_availableFrom ? time : m_availableFrom;
00620
00621 return t;
00622 }
00623 Calendar *cal = calendar();
00624 if (cal == 0) {
00625 return t;
00626 }
00627 t = m_availableFrom > time ? m_availableFrom : time;
00628 t = cal->firstAvailableAfter(t, lmt);
00629 if (checkAppointments) {
00630
00631 }
00632
00633 return t;
00634 }
00635
00636 DateTime Resource::availableBefore(const DateTime &time, const DateTime limit, bool checkAppointments) const {
00637 DateTime t;
00638 if (m_units == 0) {
00639 return t;
00640 }
00641 DateTime lmt = m_availableFrom;
00642 if (limit.isValid() && limit > lmt) {
00643 lmt = limit;
00644 }
00645 if (time <= lmt) {
00646 return t;
00647 }
00648 if (type() == Type_Material) {
00649 t = time < m_availableUntil ? time : m_availableUntil;
00650
00651 return t;
00652 }
00653 Calendar *cal = calendar();
00654 if (cal == 0) {
00655 return t;
00656 }
00657 if (!m_availableUntil.isValid()) {
00658 kWarning()<<k_funcinfo<<m_name<<": availabelUntil is invalid"<<endl;
00659 t = time;
00660 } else {
00661 t = m_availableUntil < time ? m_availableUntil : time;
00662 }
00663
00664 t = cal->firstAvailableBefore(t, lmt);
00665 if (checkAppointments) {
00666
00667 }
00668
00669 return t;
00670 }
00671
00672 Resource *Resource::findId(const QString &id) const {
00673 return m_project ? m_project->findResource(id) : 0;
00674 }
00675
00676 bool Resource::removeId(const QString &id) {
00677 return m_project ? m_project->removeResourceId(id) : false;
00678 }
00679
00680 void Resource::insertId(const QString &id) {
00681 if (m_project)
00682 m_project->insertResourceId(id, this);
00683 }
00684
00685 Calendar *Resource::findCalendar(const QString &id) const {
00686 return (m_project ? m_project->findCalendar(id) : 0);
00687 }
00688
00689 bool Resource::isOverbooked() const {
00690 return isOverbooked(DateTime(), DateTime());
00691 }
00692
00693 bool Resource::isOverbooked(const QDate &date) const {
00694 return isOverbooked(DateTime(date), DateTime(date.addDays(1)));
00695 }
00696
00697 bool Resource::isOverbooked(const DateTime &start, const DateTime &end) const {
00698
00699 return m_currentSchedule ? m_currentSchedule->isOverbooked(start, end) : false;
00700 }
00701
00702 Appointment Resource::appointmentIntervals() const {
00703 Appointment a;
00704 if (m_currentSchedule == 0)
00705 return a;
00706 foreach (Appointment *app, m_currentSchedule->appointments()) {
00707 a += *app;
00708 }
00709 return a;
00710 }
00711
00712 Duration Resource::plannedEffort(const QDate &date) const {
00713 return m_currentSchedule ? m_currentSchedule->plannedEffort(date) : Duration::zeroDuration;
00714 }
00715
00717 Risk::Risk(Node *n, Resource *r, RiskType rt) {
00718 m_node=n;
00719 m_resource=r;
00720 m_riskType=rt;
00721 }
00722
00723 Risk::~Risk() {
00724 }
00725
00726 ResourceRequest::ResourceRequest(Resource *resource, int units)
00727 : m_resource(resource),
00728 m_units(units),
00729 m_parent(0) {
00730
00731 }
00732
00733 ResourceRequest::~ResourceRequest() {
00734
00735 if (m_resource)
00736 m_resource->unregisterRequest(this);
00737 m_resource = 0;
00738 }
00739
00740 bool ResourceRequest::load(QDomElement &element, Project &project) {
00741
00742 m_resource = project.resource(element.attribute("resource-id"));
00743 if (m_resource == 0) {
00744 kWarning()<<k_funcinfo<<"The referenced resource does not exist: resource id="<<element.attribute("resource-id")<<endl;
00745 return false;
00746 }
00747 m_units = element.attribute("units").toInt();
00748 return true;
00749 }
00750
00751 void ResourceRequest::save(QDomElement &element) const {
00752 QDomElement me = element.ownerDocument().createElement("resource-request");
00753 element.appendChild(me);
00754 me.setAttribute("resource-id", m_resource->id());
00755 me.setAttribute("units", m_units);
00756 }
00757
00758 int ResourceRequest::units() const {
00759
00760 return m_units;
00761 }
00762
00763 int ResourceRequest::workUnits() const {
00764 if (m_resource->type() == Resource::Type_Work)
00765 return units();
00766
00767
00768 return 0;
00769 }
00770
00771 Task *ResourceRequest::task() const {
00772 return m_parent ? m_parent->task() : 0;
00773 }
00774
00776 ResourceGroupRequest::ResourceGroupRequest(ResourceGroup *group, int units)
00777 : m_group(group), m_units(units) {
00778
00779
00780 if (group)
00781 group->registerRequest(this);
00782 }
00783
00784 ResourceGroupRequest::~ResourceGroupRequest() {
00785
00786 if (m_group)
00787 m_group->unregisterRequest(this);
00788
00789 while (!m_resourceRequests.isEmpty()) {
00790 delete m_resourceRequests.takeFirst();
00791 }
00792 }
00793
00794 void ResourceGroupRequest::addResourceRequest(ResourceRequest *request) {
00795
00796 request->setParent(this);
00797 m_resourceRequests.append(request);
00798 request->registerRequest();
00799 }
00800
00801 ResourceRequest *ResourceGroupRequest::takeResourceRequest(ResourceRequest *request) {
00802 if (request)
00803 request->unregisterRequest();
00804 int i = m_resourceRequests.indexOf(request);
00805 if (i != -1)
00806 return m_resourceRequests.takeAt(i);
00807 return 0;
00808 }
00809
00810 ResourceRequest *ResourceGroupRequest::find(Resource *resource) {
00811 foreach (ResourceRequest *gr, m_resourceRequests) {
00812 if (gr->resource() == resource)
00813 return gr;
00814 }
00815 return 0;
00816 }
00817
00818 bool ResourceGroupRequest::load(QDomElement &element, Project &project) {
00819
00820 m_group = project.findResourceGroup(element.attribute("group-id"));
00821 if (m_group == 0) {
00822
00823 return false;
00824 }
00825 m_group->registerRequest(this);
00826
00827 m_units = element.attribute("units").toInt();
00828
00829 QDomNodeList list = element.childNodes();
00830 for (unsigned int i=0; i<list.count(); ++i) {
00831 if (list.item(i).isElement()) {
00832 QDomElement e = list.item(i).toElement();
00833 if (e.tagName() == "resource-request") {
00834 ResourceRequest *r = new ResourceRequest();
00835 if (r->load(e, project))
00836 addResourceRequest(r);
00837 else {
00838 kError()<<k_funcinfo<<"Failed to load resource request"<<endl;
00839 delete r;
00840 }
00841 }
00842 }
00843 }
00844 return true;
00845 }
00846
00847 void ResourceGroupRequest::save(QDomElement &element) const {
00848 if (units() == 0)
00849 return;
00850 QDomElement me = element.ownerDocument().createElement("resourcegroup-request");
00851 element.appendChild(me);
00852 me.setAttribute("group-id", m_group->id());
00853 me.setAttribute("units", m_units);
00854 foreach (ResourceRequest *r, m_resourceRequests)
00855 r->save(me);
00856 }
00857
00858 int ResourceGroupRequest::units() const {
00859 int units = m_units;
00860 foreach (ResourceRequest *r, m_resourceRequests) {
00861 units += r->units();
00862 }
00863
00864 return units;
00865 }
00866
00867 int ResourceGroupRequest::workUnits() const {
00868 int units = 0;
00869 if (m_group->type() == ResourceGroup::Type_Work)
00870 units = m_units;
00871 foreach (ResourceRequest *r, m_resourceRequests) {
00872 units += r->workUnits();
00873 }
00874
00875 return units;
00876 }
00877
00878
00879 Duration ResourceGroupRequest::effort(const DateTime &time, const Duration &duration, bool backward, bool *ok) const {
00880 Duration e;
00881 bool sts=false;
00882 if (ok) *ok = sts;
00883 foreach (ResourceRequest *r, m_resourceRequests) {
00884 e += r->resource()->effort(time, duration, backward, &sts);
00885 if (sts && ok) *ok = sts;
00886
00887 }
00888
00889 return e;
00890 }
00891
00892 int ResourceGroupRequest::numDays(const DateTime &time, bool backward) const {
00893 DateTime t1, t2 = time;
00894 if (backward) {
00895 foreach (ResourceRequest *r, m_resourceRequests) {
00896 t1 = r->resource()->availableFrom();
00897 if (!t2.isValid() || t2 > t1)
00898 t2 = t1;
00899 }
00900
00901 return t2.daysTo(time);
00902 }
00903 foreach (ResourceRequest *r, m_resourceRequests) {
00904 t1 = r->resource()->availableUntil();
00905 if (!t2.isValid() || t2 < t1)
00906 t2 = t1;
00907 }
00908
00909 return time.daysTo(t2);
00910 }
00911
00912 Duration ResourceGroupRequest::duration(const DateTime &time, const Duration &_effort, bool backward) {
00913
00914 Duration e;
00915 if (_effort == Duration::zeroDuration) {
00916 return e;
00917 }
00918 bool sts=true;
00919 bool match = false;
00920 DateTime start = time;
00921 int inc = backward ? -1 : 1;
00922 DateTime end = start;
00923 Duration e1;
00924 Duration d(1, 0, 0);
00925 int nDays = numDays(time, backward) + 1;
00926 for (int i=0; !match && i <= nDays; ++i) {
00927
00928 end = end.addDays(inc);
00929 e1 = effort(start, d, backward, &sts);
00930
00931 if (e + e1 < _effort) {
00932 e += e1;
00933 start = end;
00934 } else if (e + e1 == _effort) {
00935 e += e1;
00936 match = true;
00937 } else {
00938 end = start;
00939 break;
00940 }
00941 }
00942
00943 d = Duration(0, 1, 0);
00944 for (int i=0; !match && i < 24; ++i) {
00945
00946 end = end.addSecs(inc*60*60);
00947 e1 = effort(start, d, backward, &sts);
00948 if (e + e1 < _effort) {
00949 e += e1;
00950 start = end;
00951 } else if (e + e1 == _effort) {
00952 e += e1;
00953 match = true;
00954 } else {
00955 end = start;
00956 break;
00957 }
00958
00959 }
00960
00961 d = Duration(0, 0, 1);
00962 for (int i=0; !match && i < 60; ++i) {
00963
00964 end = end.addSecs(inc*60);
00965 e1 = effort(start, d, backward, &sts);
00966 if (e + e1 < _effort) {
00967 e += e1;
00968 start = end;
00969 } else if (e + e1 == _effort) {
00970 e += e1;
00971 match = true;
00972 } else if (e + e1 > _effort) {
00973 end = start;
00974 break;
00975 }
00976
00977 }
00978
00979 d = Duration(0, 0, 0, 1);
00980 for (int i=0; !match && i < 60 && sts; ++i) {
00981
00982 end = end.addSecs(inc);
00983 e1 = effort(start, d, backward, &sts);
00984 if (e + e1 < _effort) {
00985 e += e1;
00986 start = end;
00987 } else if (e + e1 == _effort) {
00988 e += e1;
00989 match = true;
00990 } else if (e + e1 > _effort) {
00991 end = start;
00992 break;
00993 }
00994
00995 }
00996 d = Duration(0, 0, 0, 0, 1);
00997 for (int i=0; !match && i < 1000; ++i) {
00998
00999 end.setTime(end.time().addMSecs(inc));
01000 e1 = effort(start, d, backward, &sts);
01001 if (e + e1 < _effort) {
01002 e += e1;
01003 start = end;
01004 } else if (e + e1 == _effort) {
01005 e += e1;
01006 match = true;
01007 } else if (e + e1 > _effort) {
01008 break;
01009 }
01010
01011 }
01012 if (!match) {
01013 kError()<<k_funcinfo<<(task()?task()->name():"No task")<<" "<<time<<": Could not match effort."<<" Want: "<<_effort.toString(Duration::Format_Day)<<" got: "<<e.toString(Duration::Format_Day)<<" sts="<<sts<<endl;
01014 }
01015 DateTime t;
01016 if (e != Duration::zeroDuration) {
01017 t = backward ? availableAfter(end) : availableBefore(end);
01018 }
01019 end = t.isValid() ? t : time;
01020
01021 return (end>time?end-time:time-end);
01022 }
01023
01024 DateTime ResourceGroupRequest::availableAfter(const DateTime &time) {
01025 DateTime start;
01026 foreach (ResourceRequest *r, m_resourceRequests) {
01027 DateTime t = r->resource()->availableAfter(time);
01028 if (t.isValid() && (!start.isValid() || t < start))
01029 start = t;
01030 }
01031 if (start.isValid() && start < time)
01032 start = time;
01033
01034 return start;
01035 }
01036
01037 DateTime ResourceGroupRequest::availableBefore(const DateTime &time) {
01038 DateTime end;
01039 foreach (ResourceRequest *r, m_resourceRequests) {
01040 DateTime t = r->resource()->availableBefore(time);
01041 if (t.isValid() && (!end.isValid() || t > end))
01042 end = t;
01043 }
01044 if (!end.isValid() || end > time)
01045 end = time;
01046
01047 return end;
01048 }
01049
01050 void ResourceGroupRequest::makeAppointments(Schedule *schedule) {
01051
01052 foreach (ResourceRequest *r, m_resourceRequests) {
01053 r->makeAppointment(schedule);
01054 }
01055 }
01056
01057 void ResourceGroupRequest::reserve(const DateTime &start, const Duration &duration) {
01058 m_start = start;
01059 m_duration = duration;
01060 }
01061
01062 bool ResourceGroupRequest::isEmpty() const {
01063 return m_resourceRequests.isEmpty() && m_units == 0;
01064 }
01065
01066 Task *ResourceGroupRequest::task() const {
01067 return m_parent ? &(m_parent->task()) : 0;
01068 }
01069
01071 ResourceRequestCollection::ResourceRequestCollection(Task &task)
01072 : m_task(task) {
01073 }
01074
01075 ResourceRequestCollection::~ResourceRequestCollection() {
01076
01077 while (!m_requests.empty()) {
01078 delete m_requests.takeFirst();
01079 }
01080 }
01081
01082 ResourceGroupRequest *ResourceRequestCollection::find(ResourceGroup *group) const {
01083 foreach (ResourceGroupRequest *r, m_requests) {
01084 if (r->group() == group)
01085 return r;
01086 }
01087 return 0;
01088 }
01089
01090
01091 ResourceRequest *ResourceRequestCollection::find(Resource *resource) const {
01092 ResourceRequest *req = 0;
01093 QListIterator<ResourceGroupRequest*> it(m_requests);
01094 while (req == 0 && it.hasNext()) {
01095 req = it.next()->find(resource);
01096 }
01097 return req;
01098 }
01099
01100
01101
01102
01103
01104
01105 void ResourceRequestCollection::save(QDomElement &element) const {
01106
01107 foreach (ResourceGroupRequest *r, m_requests) {
01108 r->save(element);
01109 }
01110 }
01111
01112 int ResourceRequestCollection::units() const {
01113
01114 int units = 0;
01115 foreach (ResourceGroupRequest *r, m_requests) {
01116 units += r->units();
01117
01118 }
01119 return units;
01120 }
01121
01122 int ResourceRequestCollection::workUnits() const {
01123
01124 int units = 0;
01125 foreach (ResourceGroupRequest *r, m_requests) {
01126 units += r->workUnits();
01127 }
01128
01129 return units;
01130 }
01131
01132
01133
01134
01135
01136 Duration ResourceRequestCollection::duration(const DateTime &time, const Duration &effort, bool backward) {
01137
01138 if (isEmpty()) {
01139 return effort;
01140 }
01141 Duration dur;
01142 int units = workUnits();
01143 if (units == 0)
01144 units = 100;
01145 foreach (ResourceGroupRequest *r, m_requests) {
01146 if (r->isEmpty())
01147 continue;
01148 if (r->group()->type() == ResourceGroup::Type_Work) {
01149 Duration d = r->duration(time, (effort*r->workUnits())/units, backward);
01150 if (d > dur)
01151 dur = d;
01152 } else if (r->group()->type() == ResourceGroup::Type_Material) {
01153
01154 if (dur == Duration::zeroDuration)
01155 dur = effort;
01156 }
01157 }
01158 return dur;
01159 }
01160
01161 DateTime ResourceRequestCollection::availableAfter(const DateTime &time) {
01162 DateTime start;
01163 foreach (ResourceGroupRequest *r, m_requests) {
01164 DateTime t = r->availableAfter(time);
01165 if (t.isValid() && (!start.isValid() || t < start))
01166 start = t;
01167 }
01168 if (start.isValid() && start < time)
01169 start = time;
01170
01171 return start;
01172 }
01173
01174 DateTime ResourceRequestCollection::availableBefore(const DateTime &time) {
01175 DateTime end;
01176 foreach (ResourceGroupRequest *r, m_requests) {
01177 DateTime t = r->availableBefore(time);
01178 if (t.isValid() && (!end.isValid() ||t > end))
01179 end = t;
01180 }
01181 if (!end.isValid() || end > time)
01182 end = time;
01183 return end;
01184 }
01185
01186
01187 void ResourceRequestCollection::makeAppointments(Schedule *schedule) {
01188
01189 foreach (ResourceGroupRequest *r, m_requests) {
01190 r->makeAppointments(schedule);
01191 }
01192 }
01193
01194 void ResourceRequestCollection::reserve(const DateTime &start, const Duration &duration) {
01195
01196 foreach (ResourceGroupRequest *r, m_requests) {
01197 r->reserve(start, duration);
01198 }
01199 }
01200
01201 bool ResourceRequestCollection::isEmpty() const {
01202 foreach (ResourceGroupRequest *r, m_requests) {
01203 if (!r->isEmpty())
01204 return false;
01205 }
01206 return true;
01207 }
01208 #ifndef NDEBUG
01209
01210 void ResourceGroup::printDebug(QString indent)
01211 {
01212 kDebug()<<indent<<" + Resource group: "<<m_name<<" id="<<m_id<<endl;
01213 indent += " !";
01214 foreach (Resource *r, m_resources)
01215 r->printDebug(indent);
01216 }
01217 void Resource::printDebug(QString indent)
01218 {
01219 kDebug()<<indent<<" + Resource: "<<m_name<<" id="<<m_id<<endl;
01220 indent += " ";
01221 foreach (Schedule *s, m_schedules) {
01222 s->printDebug(indent);
01223 }
01224 indent += " !";
01225 }
01226
01227 void ResourceGroupRequest::printDebug(QString indent)
01228 {
01229 kDebug()<<indent<<" + Request to group: "<<(m_group ? m_group->name() : "None")<<" units="<<m_units<<"%"<<endl;
01230 indent += " !";
01231
01232 foreach (ResourceRequest *r, m_resourceRequests) {
01233 r->printDebug(indent);
01234 }
01235 }
01236
01237 void ResourceRequest::printDebug(QString indent)
01238 {
01239 kDebug()<<indent<<" + Request to resource: "<<(m_resource ? m_resource->name() : "None")<<" units="<<m_units<<"%"<<endl;
01240 }
01241
01242 void ResourceRequestCollection::printDebug(QString indent)
01243 {
01244 kDebug()<<indent<<" + Resource requests:"<<endl;
01245 foreach (ResourceGroupRequest *r, m_requests) {
01246 r->printDebug(indent+" ");
01247 }
01248 }
01249 #endif
01250
01251 }