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