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