F:/KPlato/koffice/kplato/kpttask.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 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 "kpttask.h"
00022 #include "kptproject.h"
00023 #include "kpttaskdialog.h"
00024 #include "kptduration.h"
00025 #include "kptrelation.h"
00026 #include "kptdatetime.h"
00027 #include "kptcalendar.h"
00028 #include "kpteffortcostmap.h"
00029 #include "kptschedule.h"
00030 
00031 #include <qdom.h>
00032 #include <qbrush.h>
00033 //Added by qt3to4:
00034 #include <QList>
00035 #include <kdebug.h>
00036 
00037 namespace KPlato
00038 {
00039 
00040 Task::Task(Node *parent) : Node(parent), m_resource() {
00041     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00042     Duration d(1, 0, 0);
00043     m_effort = new Effort(d);
00044     m_effort->setOptimisticRatio(-10);
00045     m_effort->setPessimisticRatio(20);
00046     m_requests = 0;
00047 
00048     if (m_parent)
00049         m_leader = m_parent->leader();
00050 }
00051 
00052 Task::Task(Task &task, Node *parent) 
00053     : Node(task, parent), 
00054       m_resource() {
00055     //kDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00056     m_requests = 0;
00057     
00058     m_effort = task.effort() ? new Effort(*(task.effort())) 
00059                              : new Effort(); // Avoid crash, (shouldn't be zero)
00060 }
00061 
00062 
00063 Task::~Task() {
00064     delete m_effort;
00065     while (!m_resource.isEmpty()) {
00066         delete m_resource.takeFirst();
00067     }
00068     while (!m_parentProxyRelations.isEmpty()) {
00069         delete m_parentProxyRelations.takeFirst();
00070     }
00071     while (!m_childProxyRelations.isEmpty()) {
00072         delete m_childProxyRelations.takeFirst();
00073     }
00074     while (!m_schedules.isEmpty()) {
00075         foreach (long k, m_schedules.uniqueKeys()) {
00076             delete m_schedules.take(k);
00077         }
00078     }
00079 }
00080 
00081 int Task::type() const {
00082         if ( numChildren() > 0) {
00083           return Node::Type_Summarytask;
00084         }
00085         else if ( 0 == effort()->expected().seconds() ) {
00086                 return Node::Type_Milestone;
00087         }
00088         else {
00089                 return Node::Type_Task;
00090         }
00091 }
00092 
00093 
00094 
00095 Duration *Task::getExpectedDuration() {
00096     //kDebug()<<k_funcinfo<<endl;
00097     // Duration should already be calculated
00098     return m_currentSchedule ? new Duration(m_currentSchedule->duration) : new Duration();
00099 }
00100 
00101 Duration *Task::getRandomDuration() {
00102     return 0L;
00103 }
00104 
00105 ResourceGroupRequest *Task::resourceGroupRequest(ResourceGroup *group) const {
00106     if (m_requests)
00107         return m_requests->find(group);
00108     return 0;
00109 }
00110 
00111 void Task::clearResourceRequests() {
00112     if (m_requests)
00113         m_requests->clear();
00114 }
00115 
00116 void Task::addRequest(ResourceGroup *group, int numResources) {
00117     addRequest(new ResourceGroupRequest(group, numResources));
00118 }
00119 
00120 void Task::addRequest(ResourceGroupRequest *request) {
00121     if (!m_requests)
00122         m_requests = new ResourceRequestCollection(*this);
00123     m_requests->addRequest(request);
00124 }
00125 
00126 void Task::takeRequest(ResourceGroupRequest *request) {
00127     if (m_requests) {
00128         m_requests->takeRequest(request);
00129         if (m_requests->isEmpty()) {
00130             delete m_requests;
00131             m_requests = 0;
00132         }
00133     }
00134 }
00135 
00136 int Task::units() const {
00137     if (!m_requests)
00138         return 0;
00139     return m_requests->units();
00140 }
00141 
00142 int Task::workUnits() const {
00143     if (!m_requests)
00144         return 0;
00145     return m_requests->workUnits();
00146 }
00147 
00148 void Task::makeAppointments() {
00149     if (m_currentSchedule == 0)
00150         return;
00151     if (type() == Node::Type_Task) {
00152         if (m_requests) {
00153             //kDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl;
00154             m_requests->makeAppointments(m_currentSchedule);
00155             //kDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl;
00156         }
00157     } else if (type() == Node::Type_Summarytask) {
00158         foreach (Node *n, m_nodes) {
00159             n->makeAppointments();
00160         }
00161     } else if (type() == Node::Type_Milestone) {
00162         //kDebug()<<k_funcinfo<<"Milestone not implemented"<<endl;
00163         // Well, shouldn't have resources anyway...
00164     }
00165 }
00166 
00167 void Task::calcResourceOverbooked() {
00168     if (m_currentSchedule)
00169         m_currentSchedule->calcResourceOverbooked();
00170 }
00171 
00172 // A new constraint means start/end times and duration must be recalculated
00173 void Task::setConstraint(Node::ConstraintType type) {
00174     m_constraint = type;
00175 }
00176 
00177 
00178 bool Task::load(QDomElement &element, Project &project) {
00179     // Load attributes (TODO: Handle different types of tasks, milestone, summary...)
00180     QString s;
00181     bool ok = false;
00182     m_id = element.attribute("id");
00183     
00184     m_name = element.attribute("name");
00185     m_leader = element.attribute("leader");
00186     m_description = element.attribute("description");
00187     //kDebug()<<k_funcinfo<<m_name<<": id="<<m_id<<endl;
00188 
00189     // Allow for both numeric and text
00190     QString constraint = element.attribute("scheduling","0");
00191     m_constraint = (Node::ConstraintType)constraint.toInt(&ok);
00192     if (!ok)
00193         Node::setConstraint(constraint); // hmmm, why do I need Node::?
00194 
00195     s = element.attribute("constraint-starttime");
00196     if (s != "")
00197         m_constraintStartTime = DateTime::fromString(s);
00198     s = element.attribute("constraint-endtime");
00199     if ( s != "")
00200         m_constraintEndTime = DateTime::fromString(s);
00201     
00202     m_startupCost = element.attribute("startup-cost", "0.0").toDouble();
00203     m_shutdownCost = element.attribute("shutdown-cost", "0.0").toDouble();
00204     
00205     m_wbs = element.attribute("wbs", "");
00206     
00207     // Load the project children
00208     QDomNodeList list = element.childNodes();
00209     for (unsigned int i=0; i<list.count(); ++i) {
00210         if (list.item(i).isElement()) {
00211             QDomElement e = list.item(i).toElement();
00212 
00213             if (e.tagName() == "project") {
00214                 // Load the subproject
00215                 Project *child = new Project(this);
00216                 if (child->load(e)) {
00217                     if (!project.addSubTask(child, this)) {
00218                         delete child;  // TODO: Complain about this
00219                     }
00220                 } else {
00221                     // TODO: Complain about this
00222                     delete child;
00223                 }
00224             } else if (e.tagName() == "task") {
00225                 // Load the task
00226                 Task *child = new Task(this);
00227                 if (child->load(e, project)) {
00228                     if (!project.addSubTask(child, this)) {
00229                         delete child;  // TODO: Complain about this
00230                     }
00231                 } else {
00232                     // TODO: Complain about this
00233                     delete child;
00234                 }
00235             } else if (e.tagName() == "resource") {
00236                 // TODO: Load the resource (projects don't have resources yet)
00237             } else if (e.tagName() == "effort") {
00238                 //  Load the effort
00239                 m_effort->load(e);
00240             } else if (e.tagName() == "resourcegroup-request") {
00241                 // Load the resource request
00242                 ResourceGroupRequest *r = new ResourceGroupRequest();
00243                 if (r->load(e, project)) {
00244                     addRequest(r);
00245                 } else {
00246                     kError()<<k_funcinfo<<"Failed to load resource request"<<endl;
00247                     delete r;
00248                 }
00249             } else if (e.tagName() == "progress") {
00250                 m_progress.started = (bool)e.attribute("started", "0").toInt();
00251                 m_progress.finished = (bool)e.attribute("finished", "0").toInt();
00252                 
00253                 s = e.attribute("startTime");
00254                 if (s != "")
00255                     m_progress.startTime = DateTime::fromString(s);
00256                 s = e.attribute("finishTime");
00257                 if (s != "")
00258                     m_progress.finishTime = DateTime::fromString(s);
00259                 m_progress.percentFinished = e.attribute("percent-finished", "0").toInt();
00260                 m_progress.remainingEffort = Duration::fromString(e.attribute("remaining-effort"));
00261                 m_progress.totalPerformed = Duration::fromString(e.attribute("performed-effort"));
00262             } else if (e.tagName() == "schedules") {
00263                 QDomNodeList lst = e.childNodes();
00264                 for (unsigned int i=0; i<lst.count(); ++i) {
00265                     if (lst.item(i).isElement()) {
00266                         QDomElement el = lst.item(i).toElement();
00267                         if (el.tagName() == "schedule") {
00268                             NodeSchedule *sch = new NodeSchedule();
00269                             if (sch->loadXML(el)) {
00270                                 sch->setNode(this);
00271                                 addSchedule(sch);
00272                             } else {
00273                                 kError()<<k_funcinfo<<"Failed to load schedule"<<endl;
00274                                 delete sch;
00275                             }
00276                         }
00277                     }
00278                 }
00279             }
00280         }
00281     }
00282     //kDebug()<<k_funcinfo<<m_name<<" loaded"<<endl;
00283     return true;
00284 }
00285 
00286 
00287 void Task::save(QDomElement &element)  const {
00288     QDomElement me = element.ownerDocument().createElement("task");
00289     element.appendChild(me);
00290 
00291     //TODO: Handle different types of tasks, milestone, summary...
00292     me.setAttribute("id", m_id);
00293     me.setAttribute("name", m_name);
00294     me.setAttribute("leader", m_leader);
00295     me.setAttribute("description", m_description);
00296 
00297     me.setAttribute("scheduling",constraintToString());
00298     me.setAttribute("constraint-starttime",m_constraintStartTime.toString(Qt::ISODate));
00299     me.setAttribute("constraint-endtime",m_constraintEndTime.toString(Qt::ISODate));    
00300 
00301     me.setAttribute("startup-cost", m_startupCost);
00302     me.setAttribute("shutdown-cost", m_shutdownCost);
00303     
00304     me.setAttribute("wbs", m_wbs);
00305     
00306     m_effort->save(me);
00307 
00308     QDomElement el = me.ownerDocument().createElement("progress");
00309     me.appendChild(el);
00310     el.setAttribute("started", m_progress.started);
00311     el.setAttribute("finished", m_progress.finished);
00312     el.setAttribute("startTime", m_progress.startTime.toString(Qt::ISODate));
00313     el.setAttribute("finishTime", m_progress.finishTime.toString(Qt::ISODate));
00314     el.setAttribute("percent-finished", m_progress.percentFinished);
00315     el.setAttribute("remaining-effort", m_progress.remainingEffort.toString());
00316     el.setAttribute("performed-effort", m_progress.totalPerformed.toString());
00317     
00318     if (!m_schedules.isEmpty()) {
00319         QDomElement schs = me.ownerDocument().createElement("schedules");
00320         me.appendChild(schs);
00321         foreach (Schedule *s, m_schedules) {
00322             if (!s->isDeleted()) {
00323                 s->saveXML(schs);
00324             }
00325         }
00326     }
00327     if (m_requests) {
00328         m_requests->save(me);
00329     }
00330     for (int i=0; i<numChildren(); i++) {
00331         childNode(i)->save(me);
00332     }
00333 }
00334 
00335 void Task::saveAppointments(QDomElement &element, long id) const {
00336     //kDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl;
00337     Schedule *sch = findSchedule(id);
00338     if (sch) {
00339         sch->saveAppointments(element);
00340     }
00341     foreach (Node *n, m_nodes) {
00342         n->saveAppointments(element, id);
00343     }
00344 }
00345 
00346 EffortCostMap Task::plannedEffortCostPrDay(const QDate &start, const QDate &end) const {
00347     //kDebug()<<k_funcinfo<<m_name<<endl;
00348     if (m_currentSchedule) {
00349         return m_currentSchedule->plannedEffortCostPrDay(start, end);
00350     }
00351     return EffortCostMap();
00352 }
00353 
00354 // Returns the total planned effort for this task (or subtasks) 
00355 Duration Task::plannedEffort() {
00356    //kDebug()<<k_funcinfo<<endl;
00357     Duration eff;
00358     if (type() == Node::Type_Summarytask) {
00359         foreach (Node *n, childNodeIterator()) {
00360             eff += n->plannedEffort();
00361         }
00362     } else if (m_currentSchedule) {
00363         eff = m_currentSchedule->plannedEffort();
00364     }
00365     return eff;
00366 }
00367 
00368 // Returns the total planned effort for this task (or subtasks) on date
00369 Duration Task::plannedEffort(const QDate &date) {
00370    //kDebug()<<k_funcinfo<<endl;
00371     Duration eff;
00372     if (type() == Node::Type_Summarytask) {
00373         foreach (Node *n, childNodeIterator()) {
00374             eff += n->plannedEffort(date);
00375         }
00376     } else if (m_currentSchedule) {
00377         eff = m_currentSchedule->plannedEffort(date);
00378     }
00379     return eff;
00380 }
00381 
00382 // Returns the total planned effort for this task (or subtasks) upto and including date
00383 Duration Task::plannedEffortTo(const QDate &date) {
00384     //kDebug()<<k_funcinfo<<endl;
00385     Duration eff;
00386     if (type() == Node::Type_Summarytask) {
00387         foreach (Node *n, childNodeIterator()) {
00388             eff += n->plannedEffortTo(date);
00389         }
00390     } else if (m_currentSchedule) {
00391         eff = m_currentSchedule->plannedEffortTo(date);
00392     }
00393     return eff;
00394 }
00395 
00396 // Returns the total planned effort for this task (or subtasks) 
00397 Duration Task::actualEffort() {
00398    //kDebug()<<k_funcinfo<<endl;
00399     Duration eff;
00400     if (type() == Node::Type_Summarytask) {
00401         foreach (Node *n, childNodeIterator()) {
00402             eff += n->actualEffort();
00403         }
00404     } else {
00405         eff = m_progress.totalPerformed;
00406     }
00407     /* If we want to register pr resource...
00408     } else if (m_currentSchedule) {
00409         eff = m_currentSchedule->actualEffort();
00410     }*/
00411     return eff;
00412 }
00413 
00414 // Returns the total planned effort for this task (or subtasks) on date
00415 Duration Task::actualEffort(const QDate &date) {
00416    //kDebug()<<k_funcinfo<<endl;
00417     Duration eff;
00418     if (type() == Node::Type_Summarytask) {
00419         foreach (Node *n, childNodeIterator()) {
00420             eff += n->actualEffort(date);
00421         }
00422     } else if (m_currentSchedule) {
00423         eff = m_currentSchedule->actualEffort(date);
00424     }
00425     return eff;
00426 }
00427 
00428 // Returns the total planned effort for this task (or subtasks) on date
00429 Duration Task::actualEffortTo(const QDate &date) {
00430    //kDebug()<<k_funcinfo<<endl;
00431     Duration eff;
00432     if (type() == Node::Type_Summarytask) {
00433         foreach (Node *n, childNodeIterator()) {
00434             eff += n->actualEffortTo(date);
00435         }
00436     } else if (m_currentSchedule) {
00437         eff = m_currentSchedule->actualEffortTo(date);
00438     }
00439     return eff;
00440 }
00441 
00442 double Task::plannedCost() {
00443     //kDebug()<<k_funcinfo<<endl;
00444     double c = 0;
00445     if (type() == Node::Type_Summarytask) {
00446         foreach (Node *n, childNodeIterator()) {
00447             c += n->plannedCost();
00448         }
00449     } else if (m_currentSchedule) {
00450         c = m_currentSchedule->plannedCost();
00451     }
00452     return c;
00453 }
00454 
00455 double Task::plannedCost(const QDate &date) {
00456     //kDebug()<<k_funcinfo<<endl;
00457     double c = 0;
00458     if (type() == Node::Type_Summarytask) {
00459         foreach (Node *n, childNodeIterator()) {
00460             c += n->plannedCost(date);
00461         }
00462     } else if (m_currentSchedule) {
00463         c = m_currentSchedule->plannedCost(date);
00464     }
00465     return c;
00466 }
00467 
00468 double Task::plannedCostTo(const QDate &date) {
00469     //kDebug()<<k_funcinfo<<endl;
00470     double c = 0;
00471     if (type() == Node::Type_Summarytask) {
00472         foreach (Node *n, childNodeIterator()) {
00473             c += n->plannedCostTo(date);
00474         }
00475     } else if (m_currentSchedule) {
00476         c = m_currentSchedule->plannedCostTo(date);
00477     }
00478     return c;
00479 }
00480 
00481 double Task::actualCost() {
00482     //kDebug()<<k_funcinfo<<endl;
00483     double c = 0;
00484     if (type() == Node::Type_Summarytask) {
00485         foreach (Node *n, childNodeIterator()) {
00486             c += n->actualCost();
00487         }
00488     } else if (m_currentSchedule) {
00489         c = m_currentSchedule->actualCost();
00490     }
00491     return c;
00492 }
00493 
00494 double Task::actualCost(const QDate &date) {
00495     //kDebug()<<k_funcinfo<<endl;
00496     double c = 0;
00497     if (type() == Node::Type_Summarytask) {
00498         foreach (Node *n, childNodeIterator()) {
00499             c += n->actualCost(date);
00500         }
00501     } else if (m_currentSchedule) {
00502         c = m_currentSchedule->actualCost(date);
00503     }
00504     return c;
00505 }
00506 
00507 double Task::actualCostTo(const QDate &date) {
00508     //kDebug()<<k_funcinfo<<endl;
00509     double c = 0;
00510     if (type() == Node::Type_Summarytask) {
00511         foreach (Node *n, childNodeIterator()) {
00512             c += n->actualCostTo(date);
00513         }
00514     } else if (m_currentSchedule) {
00515         c = m_currentSchedule->actualCostTo(date);
00516     }
00517     return c;
00518 }
00519 
00520 //FIXME Handle summarytasks
00521 double Task::effortPerformanceIndex(const QDate &date, bool *error) {
00522     double res = 0.0;
00523     Duration ae = actualEffortTo(date);
00524     
00525     bool e = (ae == Duration::zeroDuration || m_progress.percentFinished == 0);
00526     if (error) {
00527         *error = e;
00528     }
00529     if (!e) {
00530         res = (plannedEffortTo(date).toDouble() * ((double)m_progress.percentFinished/100.0) / ae.toDouble());
00531     }
00532     return res;
00533 }
00534 
00535 //FIXME Handle summarytasks
00536 double Task::costPerformanceIndex(const QDate &date, bool *error) {
00537     double res = 0.0;
00538     Duration ac = qint64(actualCostTo(date));
00539     
00540     bool e = (ac == Duration::zeroDuration || m_progress.percentFinished == 0);
00541     if (error) {
00542         *error = e;
00543     }
00544     if (!e) {
00545         res = (plannedCostTo(date) * m_progress.percentFinished)/(100 * actualCostTo(date));
00546     }
00547     return res;
00548 }
00549 
00550 void Task::initiateCalculation(Schedule &sch) {
00551     //kDebug()<<k_funcinfo<<m_name<<" schedule: "<<(sch?sch->name():"None")<<" id="<<(sch?sch->id():-1)<<endl;
00552     m_visitedForward = false;
00553     m_visitedBackward = false;
00554     m_currentSchedule = createSchedule(&sch);
00555     m_currentSchedule->initiateCalculation();
00556     clearProxyRelations();
00557     Node::initiateCalculation(sch);
00558 }
00559 
00560 
00561 void Task::initiateCalculationLists(QList<Node*> &startnodes, QList<Node*> &endnodes, QList<Node*> &summarytasks/*, QList<Node*> &milestones*/) {
00562     //kDebug()<<k_funcinfo<<m_name<<endl;
00563     if (type() == Node::Type_Summarytask) {
00564         summarytasks.append(this);
00565         // propagate my relations to my children and dependent nodes
00566         foreach (Node *n, m_nodes) {
00567             if (!dependParentNodes().isEmpty()) 
00568                 n->addParentProxyRelations(dependParentNodes());
00569             if (!dependChildNodes().isEmpty()) 
00570                 n->addChildProxyRelations(dependChildNodes());
00571             n->initiateCalculationLists(startnodes, endnodes, summarytasks);
00572         }
00573     } else {
00574         if (isEndNode()) {
00575             endnodes.append(this);
00576             //kDebug()<<k_funcinfo<<"endnodes append: "<<m_name<<endl;
00577         }
00578         if (isStartNode()) {
00579             startnodes.append(this);
00580             //kDebug()<<k_funcinfo<<"startnodes append: "<<m_name<<endl;
00581         }
00582     }
00583 }
00584 
00585 DateTime Task::calculatePredeccessors(const QList<Relation*> &list, int use) {
00586     DateTime time;
00587     foreach (Relation *r, list) {
00588         if (r->parent()->type() == Type_Summarytask) {
00589             //kDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl;
00590             continue; // skip summarytasks
00591         }
00592         DateTime t = r->parent()->calculateForward(use); // early finish
00593         switch (r->type()) {
00594             case Relation::StartStart:
00595                 // I can't start earlier than my predesseccor
00596                 t = r->parent()->getEarliestStart() + r->lag();
00597                 break;
00598             case Relation::FinishFinish:
00599                 // I can't finish earlier than my predeccessor, so
00600                 // I can't start earlier than it's (earlyfinish+lag)- my duration
00601                 t += r->lag();
00602                 t -= duration(t, use, true);
00603                 break;
00604             default:
00605                 t += r->lag();
00606                 break;
00607         }
00608         if (!time.isValid() || t > time)
00609             time = t;
00610     }
00611     //kDebug()<<time.toString()<<"                  "<<m_name<<" calculatePredeccessors() ("<<list.count()<<")"<<endl;
00612     return time;
00613 }
00614 DateTime Task::calculateForward(int use) {
00615     //kDebug()<<k_funcinfo<<m_name<<<<endl;
00616     if (m_currentSchedule == 0) {
00617         return DateTime();
00618     }
00619     Schedule *cs = m_currentSchedule;
00620     if (m_visitedForward) {
00621     //kDebug()<<earliestStart.toString()<<" + "<<m_durationBackward.toString()<<" "<<m_name<<" calculateForward() (visited)"<<endl;
00622         return cs->earliestStart + m_durationForward;
00623     }
00624     // First, calculate all predecessors
00625     if (!dependParentNodes().isEmpty()) {
00626         DateTime time = calculatePredeccessors(dependParentNodes(), use);
00627         if (time.isValid() && time > cs->earliestStart) {
00628             cs->earliestStart = time;
00629         }
00630     }
00631     if (!m_parentProxyRelations.isEmpty()) {
00632         DateTime time = calculatePredeccessors(m_parentProxyRelations, use);
00633         if (time.isValid() && time > cs->earliestStart) {
00634             cs->earliestStart = time;
00635         }
00636     }
00637     if (type() == Node::Type_Task) {
00638         m_durationForward = m_effort->effort(use);
00639         switch (constraint()) {
00640             case Node::ASAP:
00641             case Node::ALAP:
00642                 cs->earliestStart = workStartAfter(cs->earliestStart);
00643                 m_durationForward = duration(cs->earliestStart, use, false);
00644                 //kDebug()<<k_funcinfo<<m_name<<": "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<endl;
00645                 break;
00646             case Node::MustFinishOn:
00647                 m_durationForward = duration(m_constraintEndTime, use, true);
00648                 cs->earliestStart = m_constraintEndTime - m_durationForward;
00649                 break;
00650             case Node::FinishNotLater:
00651                 m_durationForward = duration(cs->earliestStart, use, false);
00652                 if (cs->earliestStart + m_durationForward > m_constraintEndTime) {
00653                     m_durationForward = duration(m_constraintEndTime, use, true);
00654                     cs->earliestStart = m_constraintEndTime - m_durationForward;
00655                 }
00656                 break;
00657             case Node::MustStartOn:
00658                 cs->earliestStart = m_constraintStartTime;
00659                 m_durationForward = duration(cs->earliestStart, use, false);
00660                 break;
00661             case Node::StartNotEarlier:
00662                 if (cs->earliestStart < m_constraintStartTime) {
00663                     cs->earliestStart = m_constraintStartTime;
00664                 }
00665                 m_durationForward = duration(cs->earliestStart, use, false);
00666                 break;
00667             case Node::FixedInterval: {
00668                 cs->earliestStart = m_constraintStartTime;
00669                 m_durationForward = m_constraintEndTime - m_constraintStartTime;
00670                 break;
00671             }
00672         }
00673     } else if (type() == Node::Type_Milestone) {
00674         m_durationForward = Duration::zeroDuration;
00675         switch (constraint()) {
00676             case Node::MustFinishOn:
00677                 cs->earliestStart = m_constraintEndTime;
00678                 break;
00679             case Node::FinishNotLater:
00680                 if (cs->earliestStart > m_constraintEndTime) {
00681                     cs->earliestStart = m_constraintEndTime;
00682                 }
00683                 break;
00684             case Node::MustStartOn:
00685                 cs->earliestStart = m_constraintStartTime;
00686                 break;
00687             case Node::StartNotEarlier:
00688                 if (cs->earliestStart < m_constraintStartTime) {
00689                     cs->earliestStart = m_constraintStartTime;
00690                 }
00691                 break;
00692             case Node::FixedInterval:
00693                 cs->earliestStart = m_constraintStartTime;
00694                 break;
00695             default:
00696                 break;
00697         }
00698         //kDebug()<<k_funcinfo<<m_name<<" "<<earliestStart.toString()<<endl
00699     } else if (type() == Node::Type_Summarytask) {
00700         kWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
00701     } else { // ???
00702         m_durationForward = Duration::zeroDuration;
00703     }
00704     
00705     //kDebug()<<"Earlyfinish: "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<" "<<m_name<<" calculateForward()"<<endl;
00706     m_visitedForward = true;
00707     return cs->earliestStart + m_durationForward;
00708 }
00709 
00710 DateTime Task::calculateSuccessors(const QList<Relation*> &list, int use) {
00711     DateTime time;
00712     foreach (Relation *r, list) {
00713         if (r->child()->type() == Type_Summarytask) {
00714             //kDebug()<<k_funcinfo<<"Skip summarytask: "<<r->parent()->name()<<endl;
00715             continue; // skip summarytasks
00716         }
00717         DateTime t = r->child()->calculateBackward(use);
00718         switch (r->type()) {
00719             case Relation::StartStart:
00720                 // I must start before my successor, so
00721                 // I can't finish later than it's (starttime-lag) + my duration
00722                 t -= r->lag();
00723                 t += duration(t, use, false);
00724                 break;
00725             case Relation::FinishFinish:
00726                 // My successor cannot finish before me, so
00727                 // I can't finish later than it's latest finish - lag
00728                 t = r->child()->getLatestFinish() -  r->lag();
00729                 break;
00730             default:
00731                 t -= r->lag();
00732                 break;
00733         }
00734         if (!time.isValid() || t < time)
00735             time = t;
00736     }
00737     //kDebug()<<time.toString()<<"                  "<<m_name<<" calculateSuccessors() ("<<list.count()<<")"<<endl;
00738     return time;
00739 }
00740 DateTime Task::calculateBackward(int use) {
00741     //kDebug()<<k_funcinfo<<m_name<<endl;
00742     if (m_currentSchedule == 0) {
00743         return DateTime();
00744     }
00745     Schedule *cs = m_currentSchedule;
00746     if (m_visitedBackward) {
00747     //kDebug()<<latestFinish.toString()<<" - "<<m_durationBackward.toString()<<" "<<m_name<<" calculateBackward() (visited)"<<endl;
00748         return cs->latestFinish - m_durationBackward;
00749     }
00750     // First, calculate all successors
00751     if (!dependChildNodes().isEmpty()) {
00752         DateTime time = calculateSuccessors(dependChildNodes(), use);
00753         if (time.isValid() && time < cs->latestFinish) {
00754             cs->latestFinish = time;
00755         }
00756     }
00757     if (!m_childProxyRelations.isEmpty()) {
00758         DateTime time = calculateSuccessors(m_childProxyRelations, use);
00759         if (time.isValid() && time < cs->latestFinish) {
00760             cs->latestFinish = time;
00761         }
00762     }
00763     //kDebug()<<k_funcinfo<<m_name<<": latestFinish="<<cs->latestFinish<<endl;
00764     if (type() == Node::Type_Task) {
00765         m_durationBackward = m_effort->effort(use);
00766         switch (constraint()) {
00767             case Node::ASAP:
00768             case Node::ALAP:
00769                 cs->latestFinish = workFinishBefore(cs->latestFinish);                m_durationBackward = duration(cs->latestFinish, use, true);
00770                 break;
00771             case Node::MustStartOn:
00772                 m_durationBackward = duration(m_constraintStartTime, use, false);
00773                 cs->latestFinish = m_constraintStartTime + m_durationBackward;
00774                 break;
00775             case Node::StartNotEarlier:
00776                 m_durationBackward = duration(cs->latestFinish, use, true);
00777                 if (cs->latestFinish - m_durationBackward < m_constraintStartTime) {
00778                     m_durationBackward = duration(m_constraintStartTime, use, false);
00779                     cs->latestFinish = m_constraintStartTime + m_durationBackward;
00780                 }
00781                 break;
00782             case Node::MustFinishOn:
00783                 cs->latestFinish = m_constraintEndTime;
00784                 m_durationBackward = duration(cs->latestFinish, use, true);
00785                 break;
00786             case Node::FinishNotLater:
00787                 if (cs->latestFinish > m_constraintEndTime) {
00788                     cs->latestFinish = m_constraintEndTime;
00789                 }
00790                 m_durationBackward = duration(cs->latestFinish, use, true);
00791                 break;
00792             case Node::FixedInterval: {
00793                 cs->latestFinish = m_constraintEndTime;
00794                 m_durationBackward = m_constraintEndTime - m_constraintStartTime;
00795                 break;
00796             }
00797         }
00798     } else if (type() == Node::Type_Milestone) {
00799         m_durationBackward = Duration::zeroDuration;
00800         switch (constraint()) {
00801             case Node::MustFinishOn:
00802                 cs->latestFinish = m_constraintEndTime;
00803                 break;
00804             case Node::FinishNotLater:
00805                 if (cs->latestFinish > m_constraintEndTime) {
00806                     cs->latestFinish = m_constraintEndTime;
00807                 }
00808                 break;
00809             case Node::MustStartOn:
00810                 cs->latestFinish = m_constraintStartTime;
00811                 break;
00812             case Node::StartNotEarlier:
00813                 if (cs->latestFinish < m_constraintStartTime) {
00814                     cs->latestFinish = m_constraintStartTime;
00815                 }
00816                 break;
00817             case Node::FixedInterval:
00818                 cs->latestFinish = m_constraintEndTime;
00819                 break;
00820             default:
00821                 break;
00822         }
00823         //kDebug()<<k_funcinfo<<m_name<<" "<<cs->latestFinish<<endl;
00824     } else if (type() == Node::Type_Summarytask) {
00825         kWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
00826     } else { // ???
00827         m_durationBackward = Duration::zeroDuration;
00828     }
00829     //kDebug()<<"Latestart: "<<cs->latestFinish<<"-"<<m_durationBackward.toString()<<"="<<(cs->latestFinish-m_durationBackward).toString()<<" "<<m_name<<" calculateBackward()"<<endl;
00830     m_visitedBackward = true;
00831     return cs->latestFinish - m_durationBackward;
00832 }
00833 
00834 DateTime Task::schedulePredeccessors(const QList<Relation*> &list, int use) {
00835     DateTime time;
00836     foreach (Relation *r, list) {
00837         if (r->parent()->type() == Type_Summarytask) {
00838             //kDebug()<<k_funcinfo<<"Skip summarytask: "<<r->parent()->name()<<endl;
00839             continue; // skip summarytasks
00840         }
00841         // schedule the predecessors
00842         DateTime earliest = r->parent()->getEarliestStart();
00843         DateTime t = r->parent()->scheduleForward(earliest, use);
00844         switch (r->type()) {
00845             case Relation::StartStart:
00846                 // I can't start before my predesseccor
00847                 t = r->parent()->startTime() + r->lag();
00848                 break;
00849             case Relation::FinishFinish:
00850                 // I can't end before my predecessor, so
00851                 // I can't start before it's endtime - my duration
00852                 t -= duration(t + r->lag(), use, true);
00853                 break;
00854             default:
00855                 t += r->lag();
00856                 break;
00857         }
00858         if (!time.isValid() || t > time)
00859             time = t;
00860     }
00861     //kDebug()<<time.toString()<<" "<<m_name<<" schedulePredeccessors()"<<endl;
00862     return time;
00863 }
00864 
00865 DateTime Task::scheduleForward(const DateTime &earliest, int use) {
00866     //kDebug()<<k_funcinfo<<m_name<<" earliest="<<earliest<<endl;
00867     if (m_currentSchedule == 0) {
00868         return DateTime();
00869     }
00870     Schedule *cs = m_currentSchedule;
00871     if (m_visitedForward) {
00872         return cs->endTime;
00873     }
00874     cs->notScheduled = false;
00875     cs->startTime = earliest > cs->earliestStart ? earliest : cs->earliestStart;
00876     // First, calculate all my own predecessors
00877     DateTime time = schedulePredeccessors(dependParentNodes(), use);
00878     if (time.isValid() && time > cs->startTime) {
00879         cs->startTime = time;
00880         //kDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl;
00881     }
00882     // Then my parents
00883     time = schedulePredeccessors(m_parentProxyRelations, use);
00884     if (time.isValid() && time > cs->startTime) {
00885         cs->startTime = time;
00886         //kDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl;
00887     }
00888     //kDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
00889     if(type() == Node::Type_Task) {
00890         cs->duration = m_effort->effort(use);
00891         switch (m_constraint) {
00892         case Node::ASAP:
00893             // cs->startTime calculated above
00894             //kDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
00895             cs->startTime = workStartAfter(cs->startTime);
00896             cs->duration = duration(cs->startTime, use, false);
00897             cs->endTime = cs->startTime + cs->duration;
00898             //kDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
00899             break;
00900         case Node::ALAP:
00901             // cd->startTime calculated above
00902             cs->duration = duration(cs->latestFinish, use, true);
00903             cs->endTime = cs->latestFinish;
00904             cs->startTime = cs->endTime - cs->duration;
00905             //kDebug()<<k_funcinfo<<m_name<<" endTime="<<cs->endTime<<" latest="<<cs->latestFinish<<endl;
00906             break;
00907         case Node::StartNotEarlier:
00908             // cs->startTime calculated above
00909             //kDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cd->startTime.toString()<<endl;            
00910             if (cs->startTime < m_constraintStartTime) {
00911                 cs->startTime = m_constraintStartTime;
00912             }
00913             cs->startTime = workStartAfter(cs->startTime);
00914             cs->duration = duration(cs->startTime, use, false);
00915             cs->endTime = cs->startTime + cs->duration;
00916             if (cs->endTime > cs->latestFinish) {
00917                 cs->schedulingError = true;
00918             }
00919             break;
00920         case Node::FinishNotLater:
00921             // cs->startTime calculated above
00922             //kDebug()<<"FinishNotLater="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
00923             cs->duration = duration(cs->startTime, use, false);
00924             cs->endTime = cs->startTime + cs->duration;
00925             if (cs->endTime > m_constraintEndTime) {
00926                 cs->schedulingError = true;
00927                 cs->endTime = m_constraintEndTime;
00928                 cs->duration = duration(cs->endTime, use, true);
00929                 cs->startTime = cs->endTime - cs->duration;
00930             }
00931             break;
00932         case Node::MustStartOn:
00933             // cs->startTime calculated above
00934             //kDebug()<<"MustStartOn="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
00935             if (m_constraintStartTime < cs->startTime ||
00936                 m_constraintStartTime > cs->latestFinish - m_durationBackward) {
00937                 cs->schedulingError = true;
00938             }
00939             cs->startTime = m_constraintStartTime;
00940             cs->duration = duration(cs->startTime, use, false);
00941             cs->endTime = cs->startTime + cs->duration;
00942             break;
00943         case Node::MustFinishOn:
00944             // cs->startTime calculated above
00945             //kDebug()<<"MustFinishOn="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
00946             if (m_constraintEndTime > cs->latestFinish ||
00947                 m_constraintEndTime < cs->earliestStart + m_durationForward) {
00948                 cs->schedulingError = true;
00949             }
00950             cs->endTime = m_constraintEndTime;
00951             cs->duration = duration(cs->endTime, use, true);
00952             cs->startTime = cs->endTime - cs->duration;
00953             break;
00954         case Node::FixedInterval: {
00955             // cs->startTime calculated above
00956             //kDebug()<<"FixedInterval="<<m_constraintStartTime<<" "<<cs->startTime<<endl;
00957             if (cs->startTime < cs->earliestStart) {
00958                 cs->schedulingError = true;
00959             }
00960             cs->startTime = m_constraintStartTime;
00961             cs->endTime = m_constraintEndTime;
00962             cs->duration = cs->endTime - cs->startTime;
00963             cs->workStartTime = m_constraintStartTime;
00964             cs->workEndTime = m_constraintEndTime;
00965             //kDebug()<<"FixedInterval="<<cs->startTime<<", "<<cs->endTime<<endl;
00966             break;
00967         }
00968         default:
00969             break;
00970         }
00971         if (m_requests) {
00972             m_requests->reserve(cs->startTime, cs->duration);
00973         }
00974     } else if (type() == Node::Type_Milestone) {
00975         switch (m_constraint) {
00976         case Node::ASAP: {
00977             cs->endTime = cs->startTime;
00978             break;
00979         }
00980         case Node::ALAP: {
00981             cs->startTime = cs->latestFinish;
00982             cs->endTime = cs->latestFinish;
00983             break;
00984         }
00985         case Node::MustStartOn:
00986         case Node::FixedInterval:
00987             //kDebug()<<"Forw, MustStartOn: "<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
00988             if (m_constraintStartTime < cs->startTime ||
00989                 m_constraintStartTime > cs->latestFinish) {
00990                 cs->schedulingError = true;
00991             }
00992             cs->startTime = m_constraintStartTime;
00993             cs->endTime = m_constraintStartTime;
00994             break;
00995         case Node::MustFinishOn:
00996             if (m_constraintEndTime < cs->startTime ||
00997                 m_constraintEndTime > cs->latestFinish) {
00998                 cs->schedulingError = true;
00999             }
01000             cs->startTime = m_constraintEndTime;
01001             cs->endTime = m_constraintEndTime;
01002             break;
01003         case Node::StartNotEarlier:
01004             if (cs->startTime < m_constraintStartTime) {
01005                 cs->schedulingError = true;
01006             }
01007             cs->endTime = cs->startTime;
01008             break;
01009         case Node::FinishNotLater:
01010             if (cs->startTime > m_constraintEndTime) {
01011                 cs->schedulingError = true;
01012             }
01013             cs->endTime = cs->startTime;
01014             break;
01015         default:
01016             break;
01017         }
01018         cs->duration = Duration::zeroDuration;
01019         //kDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime<<", "<<cs->endTime<<endl;
01020     } else if (type() == Node::Type_Summarytask) {
01021         //shouldn't come here
01022         cs->endTime = cs->startTime;
01023         cs->duration = cs->endTime - cs->startTime;
01024         kWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
01025     }
01026     //kDebug()<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<" "<<m_name<<" scheduleForward()"<<endl;
01027     m_visitedForward = true;
01028     return cs->endTime;
01029 }
01030 
01031 DateTime Task::scheduleSuccessors(const QList<Relation*> &list, int use) {
01032     DateTime time;
01033     foreach (Relation *r, list) {
01034         if (r->child()->type() == Type_Summarytask) {
01035             //kDebug()<<k_funcinfo<<"Skip summarytask: "<<r->child()->name()<<endl;
01036             continue;
01037         }
01038         // get the successors starttime
01039         DateTime latest = r->child()->getLatestFinish();
01040         DateTime t = r->child()->scheduleBackward(latest, use);
01041         switch (r->type()) {
01042             case Relation::StartStart:
01043                 // I can't start before my successor, so
01044                 // I can't finish later than it's starttime + my duration
01045                 t += duration(t - r->lag(), use, false);
01046                 break;
01047             case Relation::FinishFinish:
01048                 t = r->child()->endTime() - r->lag();
01049                 break;
01050             default:
01051                 t -= r->lag();
01052                 break;
01053         }
01054         if (!time.isValid() || t < time)
01055             time = t;
01056    }
01057    return time;
01058 }
01059 DateTime Task::scheduleBackward(const DateTime &latest, int use) {
01060     //kDebug()<<k_funcinfo<<m_name<<": latest="<<latest<<endl;
01061     if (m_currentSchedule == 0) {
01062         return DateTime();
01063     }
01064     Schedule *cs = m_currentSchedule;
01065     if (m_visitedBackward) {
01066         return cs->startTime;
01067     }
01068     cs->notScheduled = false;
01069     cs->endTime = latest < cs->latestFinish ? latest : cs->latestFinish;
01070     // First, calculate all my own successors
01071     DateTime time = scheduleSuccessors(dependChildNodes(), use);
01072     if (time.isValid() && time < cs->endTime) {
01073         cs->endTime = time;
01074     }
01075     // Then my parents
01076     time = scheduleSuccessors(m_childProxyRelations, use);
01077     if (time.isValid() && time < cs->endTime) {
01078         cs->endTime = time;
01079     }
01080     if (type() == Node::Type_Task) {
01081         cs->duration = m_effort->effort(use);
01082         switch (m_constraint) {
01083         case Node::ASAP: {
01084             // cs->endTime calculated above
01085             //kDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<"  early="<<cs->earliestStart<<endl;
01086             cs->endTime = workFinishBefore(cs->endTime);
01087             cs->duration = duration(cs->earliestStart, use, false);
01088             cs->startTime = cs->earliestStart;
01089             DateTime e = cs->startTime + cs->duration;
01090             if (e > cs->endTime) {
01091                 cs->schedulingError = true;
01092             }
01093             cs->endTime = e;
01094             //kDebug()<<k_funcinfo<<m_name<<": start="<<cs->startTime<<"+"<<cs->duration.toString()<<"="<<e<<" -> end="<<cs->endTime<<endl;
01095             break;
01096         }
01097         case Node::ALAP:
01098             // cs->endTime calculated above
01099             //kDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<"  late="<<cs->latestFinish<<endl;
01100             cs->endTime = workFinishBefore(cs->endTime);
01101             cs->duration = duration(cs->endTime, use, true);
01102             cs->startTime = cs->endTime - cs->duration;
01103             //kDebug()<<k_funcinfo<<m_name<<": lateStart="<<cs->startTime<<endl;
01104             break;
01105         case Node::StartNotEarlier:
01106             // cs->endTime calculated above
01107             //kDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cs->endTime.toString()<<endl;
01108             cs->endTime = workFinishBefore(cs->endTime);
01109             cs->duration = duration(cs->endTime, use, true);
01110             cs->startTime = cs->endTime - cs->duration;
01111             if (cs->startTime < m_constraintStartTime) {
01112                 cs->schedulingError = true;
01113                 cs->startTime = m_constraintStartTime;
01114                 cs->duration = duration(cs->startTime, use, false);
01115                 cs->endTime = cs->startTime + cs->duration;
01116             }
01117             break;
01118         case Node::FinishNotLater:
01119             // cs->endTime calculated above
01120             //kDebug()<<"FinishNotLater="<<m_constraintEndTime.toString()<<" "<<cs->endTime.toString()<<endl;            
01121             if (cs->endTime > m_constraintEndTime) {
01122                 cs->schedulingError = true;
01123                 cs->endTime = m_constraintEndTime;
01124             }
01125             cs->endTime = workFinishBefore(cs->endTime);
01126             cs->duration = duration(cs->endTime, use, true);
01127             cs->startTime = cs->endTime - cs->duration;
01128             break;
01129         case Node::MustStartOn:
01130             // cs->endTime calculated above
01131             //kDebug()<<"MustStartOn="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
01132             if (m_constraintStartTime < cs->earliestStart ||
01133                 m_constraintStartTime > cs->latestFinish - m_durationBackward) {
01134                 cs->schedulingError = true;
01135             }
01136             cs->startTime = m_constraintStartTime;
01137             cs->duration = duration(cs->startTime, use, false);
01138             cs->endTime = cs->startTime + cs->duration;
01139             break;
01140         case Node::MustFinishOn:
01141             // cs->endTime calculated above
01142             //kDebug()<<"MustFinishOn="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
01143             if (m_constraintEndTime > cs->latestFinish ||
01144                 m_constraintEndTime < cs->earliestStart + m_durationForward) {
01145                 cs->schedulingError = true;
01146             }
01147             cs->endTime = m_constraintEndTime;
01148             cs->duration = duration(cs->endTime, use, true);
01149             cs->startTime = cs->endTime - cs->duration;
01150             break;
01151         case Node::FixedInterval: {
01152             // cs->endTime calculated above
01153             //kDebug()<<k_funcinfo<<"FixedInterval="<<m_constraintEndTime<<" "<<cs->endTime<<endl;
01154             if (m_constraintEndTime > cs->endTime) {
01155                 cs->schedulingError = true;
01156                 //kDebug()<<k_funcinfo<<"FixedInterval error: "<<m_constraintEndTime<<" >  "<<cs->endTime<<endl;
01157             }
01158             cs->startTime = m_constraintStartTime;
01159             cs->endTime = m_constraintEndTime;
01160             cs->duration = cs->endTime - cs->startTime;
01161             cs->workStartTime = m_constraintStartTime;
01162             cs->workEndTime = m_constraintEndTime;
01163             break;
01164         }
01165         default:
01166             break;
01167         }
01168         if (m_requests) {
01169             m_requests->reserve(cs->startTime, cs->duration);
01170         }
01171     } else if (type() == Node::Type_Milestone) {
01172         switch (m_constraint) {
01173         case Node::ASAP:
01174             cs->startTime = cs->earliestStart;
01175             cs->endTime = cs->earliestStart;
01176             break;
01177         case Node::ALAP:
01178             cs->startTime = cs->latestFinish;
01179             cs->endTime = cs->latestFinish;
01180             break;
01181         case Node::MustStartOn:
01182         case Node::FixedInterval:
01183             if (m_constraintStartTime < cs->earliestStart ||
01184                 m_constraintStartTime > cs->endTime) {
01185                 cs->schedulingError = true;
01186             }
01187             cs->startTime = cs->earliestStart;
01188             cs->endTime = cs->earliestStart;
01189             break;
01190         case Node::MustFinishOn:
01191             if (m_constraintEndTime < cs->earliestStart ||
01192                 m_constraintEndTime > cs->endTime) {
01193                 cs->schedulingError = true;
01194             }
01195             cs->startTime = cs->earliestStart;
01196             cs->endTime = cs->earliestStart;
01197             break;
01198         case Node::StartNotEarlier:
01199             if (m_constraintStartTime > cs->endTime) {
01200                 cs->schedulingError = true;
01201             }
01202             cs->startTime = cs->endTime;
01203             break;
01204         case Node::FinishNotLater:
01205             if (m_constraintEndTime < cs->endTime) {
01206                 cs->schedulingError = true;
01207             }
01208             cs->startTime = cs->endTime;
01209             break;
01210         default:
01211             break;
01212         }
01213         cs->duration = Duration::zeroDuration;
01214     } else if (type() == Node::Type_Summarytask) {
01215         //shouldn't come here
01216         cs->startTime = cs->endTime;
01217         cs->duration = cs->endTime - cs->startTime;
01218         kWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
01219     }
01220     //kDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<endl;
01221     m_visitedBackward = true;
01222     return cs->startTime;
01223 }
01224 
01225 void Task::adjustSummarytask() {
01226     if (m_currentSchedule == 0)
01227         return;
01228     if (type() == Type_Summarytask) {
01229         DateTime start = m_currentSchedule->latestFinish;
01230         DateTime end = m_currentSchedule->earliestStart;
01231         foreach (Node *n, m_nodes) {
01232             n->adjustSummarytask();
01233             if (n->startTime() < start)
01234                 start = n->startTime();
01235             if (n->endTime() > end)
01236                 end = n->endTime();
01237         }
01238         m_currentSchedule->startTime = start;
01239         m_currentSchedule->endTime = end;
01240         m_currentSchedule->duration = end - start;
01241         m_currentSchedule->notScheduled = false;
01242         //kDebug()<<k_funcinfo<<cs->name<<": "<<m_currentSchedule->startTime.toString()<<" : "<<m_currentSchedule->endTime.toString()<<endl;
01243     }
01244 }
01245 
01246 Duration Task::calcDuration(const DateTime &time, const Duration &effort, bool backward) {
01247     //kDebug()<<"--------> calcDuration "<<(backward?"(B) ":"(F) ")<<m_name<<" time="<<time<<" effort="<<effort.toString(Duration::Format_Day)<<endl;
01248     
01249     // Allready checked: m_effort, m_currentSchedule and time.
01250     Duration dur = effort; // use effort as default duration
01251     if (m_effort->type() == Effort::Type_Effort) {
01252         if (m_requests == 0 || m_requests->isEmpty()) {
01253             m_currentSchedule->resourceError = true;
01254             return effort;
01255         }
01256         dur = m_requests->duration(time, effort, backward);
01257         if (dur == Duration::zeroDuration) {
01258             kWarning()<<k_funcinfo<<"zero duration: Resource not available"<<endl;
01259             m_currentSchedule->resourceNotAvailable = true;
01260             dur = effort; //???
01261         }
01262         return dur;
01263     }
01264     if (m_effort->type() == Effort::Type_FixedDuration) {
01265         //TODO: Different types of fixed duration
01266         return dur; //
01267     }
01268     kError()<<k_funcinfo<<"Unsupported effort type: "<<m_effort->type()<<endl;
01269     return dur;
01270 }
01271 
01272 void Task::clearProxyRelations() {
01273     m_parentProxyRelations.clear();
01274     m_childProxyRelations.clear();
01275 }
01276 
01277 void Task::addParentProxyRelations(QList<Relation*> &list) {
01278     //kDebug()<<k_funcinfo<<m_name<<endl;
01279     if (type() == Type_Summarytask) {
01280         // propagate to my children
01281         //kDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl;
01282         foreach (Node *n, m_nodes) {
01283             n->addParentProxyRelations(list);
01284             n->addParentProxyRelations(dependParentNodes());
01285         }        
01286     } else {
01287         // add 'this' as child relation to the relations parent
01288         //kDebug()<<k_funcinfo<<m_name<<" is not summary task"<<endl;
01289         foreach (Relation *r, list) {
01290             r->parent()->addChildProxyRelation(this, r);
01291             // add a parent relation to myself
01292             addParentProxyRelation(r->parent(), r);
01293         }
01294     }
01295 }
01296 
01297 void Task::addChildProxyRelations(QList<Relation*> &list) {
01298     //kDebug()<<k_funcinfo<<m_name<<endl;
01299     if (type() == Type_Summarytask) {
01300         // propagate to my children
01301         //kDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl;
01302         foreach (Node *n, m_nodes) {
01303             n->addChildProxyRelations(list);
01304             n->addChildProxyRelations(dependChildNodes());
01305         }        
01306     } else {
01307         // add 'this' as parent relation to the relations child
01308         //kDebug()<<k_funcinfo<<m_name<<" is not summary task"<<endl;
01309         foreach (Relation *r, list) {
01310             r->child()->addParentProxyRelation(this, r);
01311             // add a child relation to myself
01312             addChildProxyRelation(r->child(), r);
01313         }
01314     }
01315 }
01316 
01317 void Task::addParentProxyRelation(Node *node, const Relation *rel) {
01318     if (node->type() != Type_Summarytask) {
01319         if (type() == Type_Summarytask) {
01320             //kDebug()<<"Add parent proxy from my children "<<m_name<<" to "<<node->name()<<endl;
01321             foreach (Node *n, m_nodes) {
01322                 n->addParentProxyRelation(node, rel);
01323             }
01324         } else {
01325             //kDebug()<<"Add parent proxy from "<<node->name()<<" to (me) "<<m_name<<endl;
01326             m_parentProxyRelations.append(new ProxyRelation(node, this, rel->type(), rel->lag()));
01327         }
01328     }
01329 }
01330 
01331 void Task::addChildProxyRelation(Node *node, const Relation *rel) {
01332     if (node->type() != Type_Summarytask) {
01333         if (type() == Type_Summarytask) {
01334             //kDebug()<<"Add child proxy from my children "<<m_name<<" to "<<node->name()<<endl;
01335             foreach (Node *n, m_nodes) {
01336                 n->addChildProxyRelation(node, rel);
01337             }
01338         } else {
01339             //kDebug()<<"Add child proxy from (me) "<<m_name<<" to "<<node->name()<<endl;
01340             m_childProxyRelations.append(new ProxyRelation(this, node, rel->type(), rel->lag()));
01341         }
01342     }
01343 }
01344 
01345 bool Task::isEndNode() const {
01346     foreach (Relation *r, m_dependChildNodes) {
01347         if (r->type() == Relation::FinishStart)
01348             return false;
01349     }
01350     foreach (Relation *r, m_childProxyRelations) {
01351         if (r->type() == Relation::FinishStart)
01352             return false;
01353     }
01354     return true;
01355 }
01356 bool Task::isStartNode() const {
01357     foreach (Relation *r, m_dependParentNodes) {
01358         if (r->type() == Relation::FinishStart ||
01359             r->type() == Relation::StartStart)
01360             return false;
01361     }
01362     foreach (Relation *r, m_parentProxyRelations) {
01363         if (r->type() == Relation::FinishStart ||
01364             r->type() == Relation::StartStart)
01365             return false;
01366     }
01367     return true;
01368 }
01369 
01370 DateTime Task::workStartTime() const {
01371     if (m_currentSchedule == 0)
01372          return DateTime();
01373     if (m_requests)
01374         return m_currentSchedule->workStartTime;
01375     return m_currentSchedule->startTime;
01376 }
01377 
01378 DateTime Task::workEndTime() const {
01379     if (m_currentSchedule == 0)
01380          return DateTime();
01381     return m_currentSchedule->endTime;
01382 }
01383 
01384 DateTime Task::workStartAfter(const DateTime &dt) {
01385     if (m_requests) {
01386         DateTime t = m_requests->availableAfter(dt);
01387         return t.isValid() ? t : dt;
01388     }
01389     return dt;
01390 }
01391 
01392 DateTime Task::workFinishBefore(const DateTime &dt) {
01393     if (m_requests) {
01394         return m_requests->availableBefore(dt);
01395     }
01396     return dt;
01397 }
01398 
01399 Duration Task::positiveFloat() {
01400     if (m_currentSchedule == 0 || 
01401         m_currentSchedule->schedulingError ||
01402         effortMetError()) {
01403         return Duration::zeroDuration;
01404     }
01405     Duration f;
01406     if (type() == Node::Type_Milestone) {
01407         if (m_currentSchedule->startTime < m_currentSchedule->latestFinish) {
01408             f = m_currentSchedule->latestFinish - m_currentSchedule->startTime;
01409         }
01410     } else if (m_effort->type() == Effort::Type_FixedDuration) {
01411         if (m_currentSchedule->endTime.isValid()) {
01412             if (m_currentSchedule->endTime < m_currentSchedule->latestFinish) {
01413                 f = m_currentSchedule->latestFinish - m_currentSchedule->endTime;
01414             }
01415         }
01416     } else {
01417         if (m_currentSchedule->workEndTime.isValid())
01418             if (m_currentSchedule->workEndTime < m_currentSchedule->latestFinish) {
01419             f = m_currentSchedule->latestFinish - m_currentSchedule->workEndTime;
01420         } else if (m_currentSchedule->endTime.isValid()) {
01421             if (m_currentSchedule->endTime < m_currentSchedule->latestFinish) {
01422                 f = m_currentSchedule->latestFinish - m_currentSchedule->endTime;
01423             }
01424         }
01425     }
01426     //kDebug()<<k_funcinfo<<f.toString()<<endl;
01427     return f;
01428 }
01429 
01430 bool Task::isCritical() const {
01431     Schedule *cs = m_currentSchedule;
01432     if (cs == 0) {
01433         return false;
01434     }
01435     return cs->earliestStart >= cs->startTime && cs->latestFinish <= cs->endTime;
01436 }
01437 
01438 bool Task::calcCriticalPath(bool fromEnd) {
01439     if (m_currentSchedule == 0)
01440         return false;
01441     //kDebug()<<k_funcinfo<<m_name<<" fromEnd="<<fromEnd<<" cp="<<m_currentSchedule->inCriticalPath<<endl;
01442     if (m_currentSchedule->inCriticalPath) {
01443         return true; // path already calculated
01444     }
01445     if (!isCritical()) {
01446         return false;
01447     }
01448     if (fromEnd) {
01449         if (isEndNode()) {
01450             m_currentSchedule->inCriticalPath = true;
01451             //kDebug()<<k_funcinfo<<m_name<<" end node"<<endl;
01452             return true;
01453         }
01454         foreach (Relation *r, m_childProxyRelations) {
01455             if (r->child()->calcCriticalPath(fromEnd)) {
01456                 m_currentSchedule->inCriticalPath = true;
01457             }
01458         }
01459         foreach (Relation *r, m_dependChildNodes) {
01460             if (r->child()->calcCriticalPath(fromEnd)) {
01461                 m_currentSchedule->inCriticalPath = true;
01462             }
01463         }
01464     } else {
01465         if (isStartNode()) {
01466             m_currentSchedule->inCriticalPath = true;
01467             //kDebug()<<k_funcinfo<<m_name<<" start node"<<endl;
01468             return true;
01469         }
01470         foreach (Relation *r, m_parentProxyRelations) {
01471             if (r->parent()->calcCriticalPath(fromEnd)) {
01472                 m_currentSchedule->inCriticalPath = true;
01473             }
01474         }
01475         foreach (Relation *r, m_dependParentNodes) {
01476             if (r->parent()->calcCriticalPath(fromEnd)) {
01477                 m_currentSchedule->inCriticalPath = true;
01478             }
01479         }
01480     }
01481     //kDebug()<<k_funcinfo<<m_name<<" return cp="<<m_currentSchedule->inCriticalPath<<endl;
01482     return m_currentSchedule->inCriticalPath;
01483 }
01484 
01485 void Task::setCurrentSchedule(long id) {
01486     setCurrentSchedulePtr(findSchedule(id));
01487     Node::setCurrentSchedule(id);
01488 }
01489 
01490 bool Task::effortMetError() const {
01491     if (m_currentSchedule->notScheduled) {
01492         return false;
01493     }
01494     return m_currentSchedule->plannedEffort() < effort()->effort(static_cast<Effort::Use>(m_currentSchedule->type()));
01495 }
01496 
01497 #ifndef NDEBUG
01498 void Task::printDebug(bool children, QByteArray indent) {
01499     kDebug()<<indent<<"+ Task node: "<<name()<<" type="<<type()<<endl;
01500     indent += "!  ";
01501     kDebug()<<indent<<"Requested resources (total): "<<units()<<"%"<<endl;
01502     kDebug()<<indent<<"Requested resources (work): "<<workUnits()<<"%"<<endl;
01503     if (m_requests)
01504         m_requests->printDebug(indent);
01505     
01506     Node::printDebug(children, indent);
01507 
01508 }
01509 
01510 #endif
01511 
01512 }  //KPlato namespace

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