F:/KPlato/koffice/kplato/kptresource.cc

Aller à la documentation de ce fichier.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Thomas zander <zander@kde.org>
00003    Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
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 //Added by qt3to4:
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     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00044 }
00045 
00046 ResourceGroup::~ResourceGroup() {
00047     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00048     if (findId() == this) {
00049         removeId(); // only remove myself (I may be just a working copy)
00050     }
00051     while (!m_resources.isEmpty()) {
00052         delete m_resources.takeFirst();
00053     }
00054     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00055 }
00056 
00057 bool ResourceGroup::setId(QString id) {
00058     //kDebug()<<k_funcinfo<<id<<endl;
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         //kDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
00067         removeId();
00068     } else if (g) {
00069         //Hmmm, shouldn't happen
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(); // hmmm
00075         return false;
00076     }
00077     m_id = id;
00078     insertId(id);
00079     //kDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
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     //kDebug()<<k_funcinfo<<endl;
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                     // Load the resource
00147                         Resource *child = new Resource(m_project);
00148                     if (child->load(e))
00149                         addResource(child, 0);
00150                         else
00151                             // TODO: Complain about this
00152                         delete child;
00153             }
00154         }
00155     }
00156     return true;
00157 }
00158 
00159 void ResourceGroup::save(QDomElement &element)  const {
00160     //kDebug()<<k_funcinfo<<endl;
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     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00223 }
00224 
00225 Resource::Resource(Resource *resource) { 
00226     //kDebug()<<k_funcinfo<<"("<<this<<") from ("<<resource<<")"<<endl;
00227     copy(resource); 
00228 }
00229 
00230 Resource::~Resource() {
00231     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00232     if (findId() == this) {
00233         removeId(); // only remove myself (I may be just a working copy)
00234     }
00235     foreach (ResourceRequest *r, m_requests) {
00236         r->setResource(0); // avoid the request to mess with my list
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     //kDebug()<<k_funcinfo<<id<<endl;
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         //kDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
00256         removeId();
00257     } else if (r) {
00258         //Hmmm, shouldn't happen
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(); // hmmm
00264         return false;
00265     }
00266     m_id = id;
00267     insertId(id);
00268     //kDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
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             //kDebug()<<k_funcinfo<<m_name<<": inserted id="<<m_id<<endl;
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     //m_appointments = resource->appointments(); // Note
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(); // available units in percent
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     //kDebug()<<k_funcinfo<<endl;
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 /*after*/) {
00343     return DateTime();
00344 }
00345 
00346 DateTime Resource::getBestAvailableTime(Duration /*duration*/) {
00347     return DateTime();
00348 }
00349 
00350 DateTime Resource::getBestAvailableTime(const DateTime /*after*/, const Duration /*duration*/) {
00351     return DateTime();
00352 }
00353 
00354 bool Resource::load(QDomElement &element) {
00355     //kDebug()<<k_funcinfo<<endl;
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     //kDebug()<<k_funcinfo<<endl;
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 */*task*/) {
00396     bool busy = false;
00397 /*
00398     foreach (Appointment *a, m_appointments) {
00399         if (a->isBusy(task->startTime(), task->endTime())) {
00400             busy = true;
00401             break;
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     //kDebug()<<k_funcinfo<<lst.count()<<endl;
00412     return lst;
00413 }
00414 
00415 Appointment *Resource::findAppointment(Node */*node*/) {
00416 /*
00417     foreach (Appointment *a, m_appointments) {
00418         if (a->node() == node)
00419             return a;
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     //kDebug()<<k_funcinfo<<endl;
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         //kDebug()<<k_funcinfo<<time.toString()<<" to "<<end.toString()<<endl;
00496         if (!time.isValid() || !end.isValid()) {
00497             kWarning()<<k_funcinfo<<"Invalid time"<<endl;
00498             return;
00499         }
00500         if (!cal->hasInterval(time, end)) {
00501             //kDebug()<<time.toString()<<" to "<<end.toString()<<": No (more) interval(s)"<<endl;
00502             kWarning()<<k_funcinfo<<m_name<<": Resource only partially available"<<endl;
00503             //node->resourceNotAvailable = true;
00504             return; // nothing more to do
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; // hmmm, didn't get a new interval, avoid loop
00513         addAppointment(node, i.first, i.second, m_units);
00514         //kDebug()<<k_funcinfo<<"Add :"<<i.first.toString()<<" to "<<i.second.toString()<<endl;
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     //kDebug()<<k_funcinfo<<m_name<< ": "<<node->node()->name()<<": "<<node->startTime.toString()<<" dur "<<node->duration.toString()<<endl;
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             // Allocate the whole period
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     //TODO: units and standard non-working days
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     //kDebug()<<k_funcinfo<<time.toString()<<" to "<<end.toString()<<endl;
00567     makeAppointment(node, time, end);
00568 }
00569 
00570 // the amount of effort we can do within the duration
00571 Duration Resource::effort(const DateTime &start, const Duration &duration, bool backward, bool *ok) const {
00572     //kDebug()<<k_funcinfo<<m_name<<": "<<start.date().toString()<<" for duration "<<duration.toString(Duration::Format_Day)<<endl;
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             //kDebug()<<k_funcinfo<<m_name<<": Not available (start="<<start<<", "<<limit<<")"<<endl;
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     //kDebug()<<k_funcinfo<<start.toString()<<" e="<<e.toString(Duration::Format_Day)<<" ("<<m_units<<")"<<endl;
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         //kDebug()<<k_funcinfo<<time.toString()<<"="<<t.toString()<<" "<<m_name<<endl;
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         //TODO
00631     }
00632     //kDebug()<<k_funcinfo<<time.toString()<<"="<<t.toString()<<" "<<m_name<<endl;
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         //kDebug()<<k_funcinfo<<time.toString()<<"="<<t.toString()<<" "<<m_name<<endl;
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     //kDebug()<<k_funcinfo<<t<<", "<<lmt<<endl;
00664     t = cal->firstAvailableBefore(t, lmt);
00665     if (checkAppointments) {
00666         //TODO
00667     }
00668     //kDebug()<<k_funcinfo<<m_name<<" returns: "<<time<<"="<<t<<" "<<endl;
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     //kDebug()<<k_funcinfo<<m_name<<": "<<start.toString()<<" - "<<end.toString()<<" cs=("<<m_currentSchedule<<")"<<endl;
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     //kDebug()<<k_funcinfo<<"("<<this<<") Request to: "<<(resource ? resource->name() : QString("None"))<<endl;
00731 }
00732 
00733 ResourceRequest::~ResourceRequest() {
00734     //kDebug()<<k_funcinfo<<"("<<this<<") resource: "<<(m_resource ? m_resource->name() : QString("None"))<<endl;
00735     if (m_resource)
00736         m_resource->unregisterRequest(this);
00737     m_resource = 0;
00738 }
00739 
00740 bool ResourceRequest::load(QDomElement &element, Project &project) {
00741     //kDebug()<<k_funcinfo<<endl;
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     //kDebug()<<k_funcinfo<<m_resource->name()<<": units="<<m_units<<endl;
00760     return m_units;
00761 }
00762 
00763 int ResourceRequest::workUnits() const {
00764     if (m_resource->type() == Resource::Type_Work)
00765         return units();
00766         
00767     //kDebug()<<k_funcinfo<<"units=0"<<endl;
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     //kDebug()<<k_funcinfo<<"Request to: "<<(group ? group->name() : QString("None"))<<endl;
00780     if (group)
00781         group->registerRequest(this);
00782 }
00783 
00784 ResourceGroupRequest::~ResourceGroupRequest() {
00785     //kDebug()<<k_funcinfo<<"Group: "<<m_group->name()<<endl;
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     //kDebug()<<k_funcinfo<<"("<<request<<") to Group: "<<m_group->name()<<endl;
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     //kDebug()<<k_funcinfo<<endl;
00820     m_group = project.findResourceGroup(element.attribute("group-id"));
00821     if (m_group == 0) {
00822         //kDebug()<<k_funcinfo<<"The referenced resource group does not exist: group id="<<element.attribute("group-id")<<endl;
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     //kDebug()<<k_funcinfo<<"units="<<units<<endl;
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     //kDebug()<<k_funcinfo<<"units="<<units<<endl;
00875     return units;
00876 }
00877 
00878 //TODO: handle nonspecific resources
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         //kDebug()<<k_funcinfo<<(backward?"(B)":"(F)" )<<it.current()->resource()->name()<<": time="<<time<<" dur="<<duration.toString()<<"gave e="<<e.toString()<<endl;
00887     }
00888     //kDebug()<<k_funcinfo<<time.toString()<<"d="<<duration.toString()<<": e="<<e.toString()<<endl;
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         //kDebug()<<k_funcinfo<<"bw "<<time.toString()<<": "<<t2.daysTo(time)<<endl;
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     //kDebug()<<k_funcinfo<<"fw "<<time.toString()<<": "<<time.daysTo(t2)<<endl;
00909     return time.daysTo(t2);
00910 }
00911 
00912 Duration ResourceGroupRequest::duration(const DateTime &time, const Duration &_effort, bool backward) {
00913     //kDebug()<<k_funcinfo<<"--->"<<(backward?"(B) ":"(F) ")<<m_group->name()<<" "<<time.toString()<<": effort: "<<_effort.toString(Duration::Format_Day)<<" ("<<_effort.milliseconds()<<")"<<endl;
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); // 1 day
00925     int nDays = numDays(time, backward) + 1;
00926     for (int i=0; !match && i <= nDays; ++i) {
00927         // days
00928         end = end.addDays(inc);
00929         e1 = effort(start, d, backward, &sts);
00930         //kDebug()<<"["<<i<<"of"<<nDays<<"] "<<(backward?"(B)":"(F):")<<"  start="<<start<<" e+e1="<<(e+e1).toString()<<" match "<<_effort.toString()<<endl;
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     //kDebug()<<"duration "<<(backward?"backward ":"forward: ")<<start.toString()<<" - "<<end.toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")  match="<<match<<" sts="<<sts<<endl;
00943     d = Duration(0, 1, 0); // 1 hour
00944     for (int i=0; !match && i < 24; ++i) {
00945         // hours
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         //kDebug()<<"duration(h)["<<i<<"]"<<(backward?"backward ":"forward:")<<" time="<<start.time().toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")"<<endl;
00959     }
00960     //kDebug()<<"duration "<<(backward?"backward ":"forward: ")<<start.toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")  match="<<match<<" sts="<<sts<<endl;
00961     d = Duration(0, 0, 1); // 1 minute
00962     for (int i=0; !match && i < 60; ++i) {
00963         //minutes
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         //kDebug()<<"duration(m) "<<(backward?"backward":"forward:")<<"  time="<<start.time().toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")"<<endl;
00977     }
00978     //kDebug()<<"duration "<<(backward?"backward":"forward:")<<"  start="<<start.toString()<<" e="<<e.toString()<<" match="<<match<<" sts="<<sts<<endl;
00979     d = Duration(0, 0, 0, 1); // 1 second
00980     for (int i=0; !match && i < 60 && sts; ++i) {
00981         //seconds
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         //kDebug()<<"duration(s)["<<i<<"]"<<(backward?"backward":"forward:")<<" time="<<start.time().toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")"<<endl;
00995     }
00996     d = Duration(0, 0, 0, 0, 1); // 1 millisecond
00997     for (int i=0; !match && i < 1000; ++i) {
00998         //milliseconds
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         //kDebug()<<"duration(ms)["<<i<<"]"<<(backward?"backward":"forward:")<<" time="<<start.time().toString()<<" e="<<e.toString()<<" ("<<e.milliseconds()<<")"<<endl;
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     //kDebug()<<k_funcinfo<<"<---"<<(backward?"(B) ":"(F) ")<<m_group->name()<<": "<<end.toString()<<"-"<<time.toString()<<"="<<(end - time).toString()<<" effort: "<<_effort.toString(Duration::Format_Day)<<endl;
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     //kDebug()<<k_funcinfo<<time.toString()<<"="<<start.toString()<<" "<<m_group->name()<<endl;
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     //kDebug()<<k_funcinfo<<time.toString()<<"="<<end.toString()<<" "<<m_group->name()<<endl;
01047     return end;
01048 }
01049 
01050 void ResourceGroupRequest::makeAppointments(Schedule *schedule) {
01051     //kDebug()<<k_funcinfo<<endl;
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     //kDebug()<<k_funcinfo<<"Group: "<<m_group->name()<<endl;
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; // we assume only one request to the same group
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 // bool ResourceRequestCollection::load(QDomElement &element, Project &project) {
01101 //     //kDebug()<<k_funcinfo<<endl;
01102 //     return true;
01103 // }
01104 
01105 void ResourceRequestCollection::save(QDomElement &element) const {
01106     //kDebug()<<k_funcinfo<<endl;
01107     foreach (ResourceGroupRequest *r, m_requests) {
01108         r->save(element);
01109     }
01110 }
01111 
01112 int ResourceRequestCollection::units() const {
01113     //kDebug()<<k_funcinfo<<endl;
01114     int units = 0;
01115     foreach (ResourceGroupRequest *r, m_requests) {
01116         units += r->units();
01117         //kDebug()<<k_funcinfo<<" Group: "<<r->group()->name()<<" now="<<units<<endl;
01118     }
01119     return units;
01120 }
01121 
01122 int ResourceRequestCollection::workUnits() const {
01123     //kDebug()<<k_funcinfo<<endl;
01124     int units = 0;
01125     foreach (ResourceGroupRequest *r, m_requests) {
01126         units += r->workUnits();
01127     }
01128     //kDebug()<<k_funcinfo<<" units="<<units<<endl;
01129     return units;
01130 }
01131 
01132 // Returns the longest duration needed by any of the groups.
01133 // The effort is distributed on "work type" resourcegroups in proportion to
01134 // the amount of resources requested for each group.
01135 // "Material type" of resourcegroups does not (atm) affect the duration.
01136 Duration ResourceRequestCollection::duration(const DateTime &time, const Duration &effort, bool backward) {
01137     //kDebug()<<k_funcinfo<<"time="<<time.toString()<<" effort="<<effort.toString(Duration::Format_Day)<<" backward="<<backward<<endl;
01138     if (isEmpty()) {
01139         return effort;
01140     }
01141     Duration dur;
01142     int units = workUnits();
01143     if (units == 0)
01144         units = 100; //hmmmm
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             //TODO
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     //kDebug()<<k_funcinfo<<time.toString()<<"="<<start.toString()<<endl;
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     //kDebug()<<k_funcinfo<<endl;
01189     foreach (ResourceGroupRequest *r, m_requests) {
01190         r->makeAppointments(schedule);
01191     }
01192 }
01193 
01194 void ResourceRequestCollection::reserve(const DateTime &start, const Duration &duration) {
01195     //kDebug()<<k_funcinfo<<endl;
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/*<<" Overbooked="<<isOverbooked()*/<<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 }  //KPlato namespace

Généré le Wed Nov 22 23:40:57 2006 pour KPlato par  doxygen 1.5.1-p1