1
/* This file is part of the KDE project
2
Copyright (C) 2001 Thomas zander <zander@kde.org>
3
Copyright (C) 2004 Dag Andersen <danders@get2net.dk>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
* Boston, MA 02110-1301, USA.
22
#include "kptproject.h"
23
#include "kpttaskdialog.h"
24
#include "kptduration.h"
25
#include "kptrelation.h"
26
#include "kptdatetime.h"
27
#include "kptcalendar.h"
28
#include "kpteffortcostmap.h"
29
#include "kptschedule.h"
38
Task::Task(Node *parent) : Node(parent), m_resource() {
39
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
40
m_resource.setAutoDelete(true);
42
m_effort = new Effort(d);
43
m_effort->setOptimisticRatio(-10);
44
m_effort->setPessimisticRatio(20);
48
m_leader = m_parent->leader();
50
m_schedules.setAutoDelete(true);
51
m_parentProxyRelations.setAutoDelete(true);
52
m_childProxyRelations.setAutoDelete(true);
55
Task::Task(Task &task, Node *parent)
58
//kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
59
m_resource.setAutoDelete(true);
61
m_parentProxyRelations.setAutoDelete(true);
62
m_childProxyRelations.setAutoDelete(true);
65
m_effort = task.effort() ? new Effort(*(task.effort()))
66
: new Effort(); // Avoid crash, (shouldn't be zero)
74
int Task::type() const {
75
if ( numChildren() > 0) {
76
return Node::Type_Summarytask;
78
else if ( 0 == effort()->expected().seconds() ) {
79
return Node::Type_Milestone;
82
return Node::Type_Task;
88
Duration *Task::getExpectedDuration() {
89
//kdDebug()<<k_funcinfo<<endl;
90
// Duration should already be calculated
91
return m_currentSchedule ? new Duration(m_currentSchedule->duration) : new Duration();
94
Duration *Task::getRandomDuration() {
98
ResourceGroupRequest *Task::resourceGroupRequest(ResourceGroup *group) const {
100
return m_requests->find(group);
104
void Task::clearResourceRequests() {
109
void Task::addRequest(ResourceGroup *group, int numResources) {
110
addRequest(new ResourceGroupRequest(group, numResources));
113
void Task::addRequest(ResourceGroupRequest *request) {
115
m_requests = new ResourceRequestCollection(*this);
116
m_requests->addRequest(request);
119
void Task::takeRequest(ResourceGroupRequest *request) {
121
m_requests->takeRequest(request);
122
if (m_requests->isEmpty()) {
129
int Task::units() const {
132
return m_requests->units();
135
int Task::workUnits() const {
138
return m_requests->workUnits();
141
void Task::makeAppointments() {
142
if (m_currentSchedule == 0)
144
if (type() == Node::Type_Task) {
146
//kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl;
147
m_requests->makeAppointments(m_currentSchedule);
148
//kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl;
150
} else if (type() == Node::Type_Summarytask) {
151
QPtrListIterator<Node> nit(m_nodes);
152
for ( ; nit.current(); ++nit ) {
153
nit.current()->makeAppointments();
155
} else if (type() == Node::Type_Milestone) {
156
//kdDebug()<<k_funcinfo<<"Milestone not implemented"<<endl;
157
// Well, shouldn't have resources anyway...
161
void Task::calcResourceOverbooked() {
162
if (m_currentSchedule)
163
m_currentSchedule->calcResourceOverbooked();
166
// A new constraint means start/end times and duration must be recalculated
167
void Task::setConstraint(Node::ConstraintType type) {
172
bool Task::load(QDomElement &element, Project &project) {
173
// Load attributes (TODO: Handle different types of tasks, milestone, summary...)
176
m_id = element.attribute("id");
178
m_name = element.attribute("name");
179
m_leader = element.attribute("leader");
180
m_description = element.attribute("description");
181
//kdDebug()<<k_funcinfo<<m_name<<": id="<<m_id<<endl;
183
// Allow for both numeric and text
184
QString constraint = element.attribute("scheduling","0");
185
m_constraint = (Node::ConstraintType)constraint.toInt(&ok);
187
Node::setConstraint(constraint); // hmmm, why do I need Node::?
189
s = element.attribute("constraint-starttime");
191
m_constraintStartTime = DateTime::fromString(s);
192
s = element.attribute("constraint-endtime");
194
m_constraintEndTime = DateTime::fromString(s);
196
m_startupCost = element.attribute("startup-cost", "0.0").toDouble();
197
m_shutdownCost = element.attribute("shutdown-cost", "0.0").toDouble();
199
m_wbs = element.attribute("wbs", "");
201
// Load the project children
202
QDomNodeList list = element.childNodes();
203
for (unsigned int i=0; i<list.count(); ++i) {
204
if (list.item(i).isElement()) {
205
QDomElement e = list.item(i).toElement();
207
if (e.tagName() == "project") {
208
// Load the subproject
209
Project *child = new Project(this);
210
if (child->load(e)) {
213
// TODO: Complain about this
216
} else if (e.tagName() == "task") {
218
Task *child = new Task(this);
219
if (child->load(e, project)) {
222
// TODO: Complain about this
225
} else if (e.tagName() == "resource") {
226
// TODO: Load the resource (projects don't have resources yet)
227
} else if (e.tagName() == "effort") {
230
} else if (e.tagName() == "resourcegroup-request") {
231
// Load the resource request
232
ResourceGroupRequest *r = new ResourceGroupRequest();
233
if (r->load(e, project)) {
236
kdError()<<k_funcinfo<<"Failed to load resource request"<<endl;
239
} else if (e.tagName() == "progress") {
240
m_progress.started = (bool)e.attribute("started", "0").toInt();
241
m_progress.finished = (bool)e.attribute("finished", "0").toInt();
243
s = e.attribute("startTime");
245
m_progress.startTime = DateTime::fromString(s);
246
s = e.attribute("finishTime");
248
m_progress.finishTime = DateTime::fromString(s);
249
m_progress.percentFinished = e.attribute("percent-finished", "0").toInt();
250
m_progress.remainingEffort = Duration::fromString(e.attribute("remaining-effort"));
251
m_progress.totalPerformed = Duration::fromString(e.attribute("performed-effort"));
252
} else if (e.tagName() == "schedules") {
253
QDomNodeList lst = e.childNodes();
254
for (unsigned int i=0; i<lst.count(); ++i) {
255
if (lst.item(i).isElement()) {
256
QDomElement el = lst.item(i).toElement();
257
if (el.tagName() == "schedule") {
258
NodeSchedule *sch = new NodeSchedule();
259
if (sch->loadXML(el)) {
263
kdError()<<k_funcinfo<<"Failed to load schedule"<<endl;
272
//kdDebug()<<k_funcinfo<<m_name<<" loaded"<<endl;
277
void Task::save(QDomElement &element) const {
278
QDomElement me = element.ownerDocument().createElement("task");
279
element.appendChild(me);
281
//TODO: Handle different types of tasks, milestone, summary...
282
me.setAttribute("id", m_id);
283
me.setAttribute("name", m_name);
284
me.setAttribute("leader", m_leader);
285
me.setAttribute("description", m_description);
287
me.setAttribute("scheduling",constraintToString());
288
me.setAttribute("constraint-starttime",m_constraintStartTime.toString(Qt::ISODate));
289
me.setAttribute("constraint-endtime",m_constraintEndTime.toString(Qt::ISODate));
291
me.setAttribute("startup-cost", m_startupCost);
292
me.setAttribute("shutdown-cost", m_shutdownCost);
294
me.setAttribute("wbs", m_wbs);
298
QDomElement el = me.ownerDocument().createElement("progress");
300
el.setAttribute("started", m_progress.started);
301
el.setAttribute("finished", m_progress.finished);
302
el.setAttribute("startTime", m_progress.startTime.toString(Qt::ISODate));
303
el.setAttribute("finishTime", m_progress.finishTime.toString(Qt::ISODate));
304
el.setAttribute("percent-finished", m_progress.percentFinished);
305
el.setAttribute("remaining-effort", m_progress.remainingEffort.toString());
306
el.setAttribute("performed-effort", m_progress.totalPerformed.toString());
308
if (!m_schedules.isEmpty()) {
309
QDomElement schs = me.ownerDocument().createElement("schedules");
310
me.appendChild(schs);
311
QIntDictIterator<Schedule> it = m_schedules;
312
for (; it.current(); ++it) {
313
if (!it.current()->isDeleted()) {
314
it.current()->saveXML(schs);
319
m_requests->save(me);
321
for (int i=0; i<numChildren(); i++) {
322
getChildNode(i)->save(me);
326
void Task::saveAppointments(QDomElement &element, long id) const {
327
//kdDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl;
328
Schedule *sch = findSchedule(id);
330
sch->saveAppointments(element);
332
QPtrListIterator<Node> it(m_nodes);
333
for (; it.current(); ++it ) {
334
it.current()->saveAppointments(element, id);
338
EffortCostMap Task::plannedEffortCostPrDay(const QDate &start, const QDate &end) const {
339
//kdDebug()<<k_funcinfo<<m_name<<endl;
340
if (m_currentSchedule) {
341
return m_currentSchedule->plannedEffortCostPrDay(start, end);
343
return EffortCostMap();
346
// Returns the total planned effort for this task (or subtasks)
347
Duration Task::plannedEffort() {
348
//kdDebug()<<k_funcinfo<<endl;
350
if (type() == Node::Type_Summarytask) {
351
QPtrListIterator<Node> it(childNodeIterator());
352
for (; it.current(); ++it) {
353
eff += it.current()->plannedEffort();
355
} else if (m_currentSchedule) {
356
eff = m_currentSchedule->plannedEffort();
361
// Returns the total planned effort for this task (or subtasks) on date
362
Duration Task::plannedEffort(const QDate &date) {
363
//kdDebug()<<k_funcinfo<<endl;
365
if (type() == Node::Type_Summarytask) {
366
QPtrListIterator<Node> it(childNodeIterator());
367
for (; it.current(); ++it) {
368
eff += it.current()->plannedEffort(date);
370
} else if (m_currentSchedule) {
371
eff = m_currentSchedule->plannedEffort(date);
376
// Returns the total planned effort for this task (or subtasks) upto and including date
377
Duration Task::plannedEffortTo(const QDate &date) {
378
//kdDebug()<<k_funcinfo<<endl;
380
if (type() == Node::Type_Summarytask) {
381
QPtrListIterator<Node> it(childNodeIterator());
382
for (; it.current(); ++it) {
383
eff += it.current()->plannedEffortTo(date);
385
} else if (m_currentSchedule) {
386
eff = m_currentSchedule->plannedEffortTo(date);
391
// Returns the total planned effort for this task (or subtasks)
392
Duration Task::actualEffort() {
393
//kdDebug()<<k_funcinfo<<endl;
395
if (type() == Node::Type_Summarytask) {
396
QPtrListIterator<Node> it(childNodeIterator());
397
for (; it.current(); ++it) {
398
eff += it.current()->actualEffort();
401
eff = m_progress.totalPerformed;
403
/* If we want to register pr resource...
404
} else if (m_currentSchedule) {
405
eff = m_currentSchedule->actualEffort();
410
// Returns the total planned effort for this task (or subtasks) on date
411
Duration Task::actualEffort(const QDate &date) {
412
//kdDebug()<<k_funcinfo<<endl;
414
if (type() == Node::Type_Summarytask) {
415
QPtrListIterator<Node> it(childNodeIterator());
416
for (; it.current(); ++it) {
417
eff += it.current()->actualEffort(date);
419
} else if (m_currentSchedule) {
420
eff = m_currentSchedule->actualEffort(date);
425
// Returns the total planned effort for this task (or subtasks) on date
426
Duration Task::actualEffortTo(const QDate &date) {
427
//kdDebug()<<k_funcinfo<<endl;
429
if (type() == Node::Type_Summarytask) {
430
QPtrListIterator<Node> it(childNodeIterator());
431
for (; it.current(); ++it) {
432
eff += it.current()->actualEffortTo(date);
434
} else if (m_currentSchedule) {
435
eff = m_currentSchedule->actualEffortTo(date);
440
double Task::plannedCost() {
441
//kdDebug()<<k_funcinfo<<endl;
443
if (type() == Node::Type_Summarytask) {
444
QPtrListIterator<Node> it(childNodeIterator());
445
for (; it.current(); ++it) {
446
c += it.current()->plannedCost();
448
} else if (m_currentSchedule) {
449
c = m_currentSchedule->plannedCost();
454
double Task::plannedCost(const QDate &date) {
455
//kdDebug()<<k_funcinfo<<endl;
457
if (type() == Node::Type_Summarytask) {
458
QPtrListIterator<Node> it(childNodeIterator());
459
for (; it.current(); ++it) {
460
c += it.current()->plannedCost(date);
462
} else if (m_currentSchedule) {
463
c = m_currentSchedule->plannedCost(date);
468
double Task::plannedCostTo(const QDate &date) {
469
//kdDebug()<<k_funcinfo<<endl;
471
if (type() == Node::Type_Summarytask) {
472
QPtrListIterator<Node> it(childNodeIterator());
473
for (; it.current(); ++it) {
474
c += it.current()->plannedCostTo(date);
476
} else if (m_currentSchedule) {
477
c = m_currentSchedule->plannedCostTo(date);
482
double Task::actualCost() {
483
//kdDebug()<<k_funcinfo<<endl;
485
if (type() == Node::Type_Summarytask) {
486
QPtrListIterator<Node> it(childNodeIterator());
487
for (; it.current(); ++it) {
488
c += it.current()->actualCost();
490
} else if (m_currentSchedule) {
491
c = m_currentSchedule->actualCost();
496
double Task::actualCost(const QDate &date) {
497
//kdDebug()<<k_funcinfo<<endl;
499
if (type() == Node::Type_Summarytask) {
500
QPtrListIterator<Node> it(childNodeIterator());
501
for (; it.current(); ++it) {
502
c += it.current()->actualCost(date);
504
} else if (m_currentSchedule) {
505
c = m_currentSchedule->actualCost(date);
510
double Task::actualCostTo(const QDate &date) {
511
//kdDebug()<<k_funcinfo<<endl;
513
if (type() == Node::Type_Summarytask) {
514
QPtrListIterator<Node> it(childNodeIterator());
515
for (; it.current(); ++it) {
516
c += it.current()->actualCostTo(date);
518
} else if (m_currentSchedule) {
519
c = m_currentSchedule->actualCostTo(date);
524
//FIXME Handle summarytasks
525
double Task::effortPerformanceIndex(const QDate &date, bool *error) {
527
Duration ae = actualEffortTo(date);
529
bool e = (ae == Duration::zeroDuration || m_progress.percentFinished == 0);
534
res = (plannedEffortTo(date).toDouble() * ((double)m_progress.percentFinished/100.0) / ae.toDouble());
539
//FIXME Handle summarytasks
540
double Task::costPerformanceIndex(const QDate &date, bool *error) {
542
Duration ac = Q_INT64(actualCostTo(date));
544
bool e = (ac == Duration::zeroDuration || m_progress.percentFinished == 0);
549
res = (plannedCostTo(date) * m_progress.percentFinished)/(100 * actualCostTo(date));
554
void Task::initiateCalculation(Schedule &sch) {
555
//kdDebug()<<k_funcinfo<<m_name<<" schedule: "<<(sch?sch->name():"None")<<" id="<<(sch?sch->id():-1)<<endl;
556
m_visitedForward = false;
557
m_visitedBackward = false;
558
m_currentSchedule = createSchedule(&sch);
559
m_currentSchedule->initiateCalculation();
560
clearProxyRelations();
561
Node::initiateCalculation(sch);
565
void Task::initiateCalculationLists(QPtrList<Node> &startnodes, QPtrList<Node> &endnodes, QPtrList<Node> &summarytasks/*, QPtrList<Node> &milestones*/) {
566
//kdDebug()<<k_funcinfo<<m_name<<endl;
567
if (type() == Node::Type_Summarytask) {
568
summarytasks.append(this);
569
// propagate my relations to my children and dependent nodes
571
QPtrListIterator<Node> nodes = m_nodes;
572
for (; nodes.current(); ++nodes) {
573
if (!dependParentNodes().isEmpty())
574
nodes.current()->addParentProxyRelations(dependParentNodes());
575
if (!dependChildNodes().isEmpty())
576
nodes.current()->addChildProxyRelations(dependChildNodes());
577
nodes.current()->initiateCalculationLists(startnodes, endnodes, summarytasks);
581
endnodes.append(this);
582
//kdDebug()<<k_funcinfo<<"endnodes append: "<<m_name<<endl;
585
startnodes.append(this);
586
//kdDebug()<<k_funcinfo<<"startnodes append: "<<m_name<<endl;
591
DateTime Task::calculatePredeccessors(const QPtrList<Relation> &list, int use) {
593
QPtrListIterator<Relation> it = list;
594
for (; it.current(); ++it) {
595
if (it.current()->parent()->type() == Type_Summarytask) {
596
//kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl;
597
continue; // skip summarytasks
599
DateTime t = it.current()->parent()->calculateForward(use); // early finish
600
switch (it.current()->type()) {
601
case Relation::StartStart:
602
// I can't start earlier than my predesseccor
603
t = it.current()->parent()->getEarliestStart() + it.current()->lag();
605
case Relation::FinishFinish:
606
// I can't finish earlier than my predeccessor, so
607
// I can't start earlier than it's (earlyfinish+lag)- my duration
608
t += it.current()->lag();
609
t -= duration(t, use, true);
612
t += it.current()->lag();
615
if (!time.isValid() || t > time)
618
//kdDebug()<<time.toString()<<" "<<m_name<<" calculatePredeccessors() ("<<list.count()<<")"<<endl;
621
DateTime Task::calculateForward(int use) {
622
//kdDebug()<<k_funcinfo<<m_name<<<<endl;
623
if (m_currentSchedule == 0) {
626
Schedule *cs = m_currentSchedule;
627
if (m_visitedForward) {
628
//kdDebug()<<earliestStart.toString()<<" + "<<m_durationBackward.toString()<<" "<<m_name<<" calculateForward() (visited)"<<endl;
629
return cs->earliestStart + m_durationForward;
631
// First, calculate all predecessors
632
if (!dependParentNodes().isEmpty()) {
633
DateTime time = calculatePredeccessors(dependParentNodes(), use);
634
if (time.isValid() && time > cs->earliestStart) {
635
cs->earliestStart = time;
638
if (!m_parentProxyRelations.isEmpty()) {
639
DateTime time = calculatePredeccessors(m_parentProxyRelations, use);
640
if (time.isValid() && time > cs->earliestStart) {
641
cs->earliestStart = time;
644
if (type() == Node::Type_Task) {
645
m_durationForward = m_effort->effort(use);
646
switch (constraint()) {
649
if (m_effort->type() == Effort::Type_Effort) {
650
DateTime t = workStartAfter(cs->earliestStart);
652
cs->earliestStart = t;
654
m_durationForward = duration(cs->earliestStart, use, false);
655
//kdDebug()<<k_funcinfo<<m_name<<": "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<endl;
657
case Node::MustFinishOn:
658
m_durationForward = duration(m_constraintEndTime, use, true);
659
cs->earliestStart = m_constraintEndTime - m_durationForward;
661
case Node::FinishNotLater:
662
m_durationForward = duration(cs->earliestStart, use, false);
663
if (cs->earliestStart + m_durationForward > m_constraintEndTime) {
664
m_durationForward = duration(m_constraintEndTime, use, true);
665
cs->earliestStart = m_constraintEndTime - m_durationForward;
668
case Node::MustStartOn:
669
cs->earliestStart = m_constraintStartTime;
670
m_durationForward = duration(cs->earliestStart, use, false);
672
case Node::StartNotEarlier:
673
if (cs->earliestStart < m_constraintStartTime) {
674
cs->earliestStart = m_constraintStartTime;
676
m_durationForward = duration(cs->earliestStart, use, false);
678
case Node::FixedInterval: {
679
cs->earliestStart = m_constraintStartTime;
680
m_durationForward = m_constraintEndTime - m_constraintStartTime;
684
} else if (type() == Node::Type_Milestone) {
685
m_durationForward = Duration::zeroDuration;
686
switch (constraint()) {
687
case Node::MustFinishOn:
688
cs->earliestStart = m_constraintEndTime;
690
case Node::FinishNotLater:
691
if (cs->earliestStart > m_constraintEndTime) {
692
cs->earliestStart = m_constraintEndTime;
695
case Node::MustStartOn:
696
cs->earliestStart = m_constraintStartTime;
698
case Node::StartNotEarlier:
699
if (cs->earliestStart < m_constraintStartTime) {
700
cs->earliestStart = m_constraintStartTime;
703
case Node::FixedInterval:
704
cs->earliestStart = m_constraintStartTime;
709
//kdDebug()<<k_funcinfo<<m_name<<" "<<earliestStart.toString()<<endl
710
} else if (type() == Node::Type_Summarytask) {
711
kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
713
m_durationForward = Duration::zeroDuration;
716
//kdDebug()<<"Earlyfinish: "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<" "<<m_name<<" calculateForward()"<<endl;
717
m_visitedForward = true;
718
return cs->earliestStart + m_durationForward;
721
DateTime Task::calculateSuccessors(const QPtrList<Relation> &list, int use) {
723
QPtrListIterator<Relation> it = list;
724
for (; it.current(); ++it) {
725
if (it.current()->child()->type() == Type_Summarytask) {
726
//kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl;
727
continue; // skip summarytasks
729
DateTime t = it.current()->child()->calculateBackward(use);
730
switch (it.current()->type()) {
731
case Relation::StartStart:
732
// I must start before my successor, so
733
// I can't finish later than it's (starttime-lag) + my duration
734
t -= it.current()->lag();
735
t += duration(t, use, false);
737
case Relation::FinishFinish:
738
// My successor cannot finish before me, so
739
// I can't finish later than it's latest finish - lag
740
t = it.current()->child()->getLatestFinish() - it.current()->lag();
743
t -= it.current()->lag();
746
if (!time.isValid() || t < time)
749
//kdDebug()<<time.toString()<<" "<<m_name<<" calculateSuccessors() ("<<list.count()<<")"<<endl;
752
DateTime Task::calculateBackward(int use) {
753
//kdDebug()<<k_funcinfo<<m_name<<endl;
754
if (m_currentSchedule == 0) {
757
Schedule *cs = m_currentSchedule;
758
if (m_visitedBackward) {
759
//kdDebug()<<latestFinish.toString()<<" - "<<m_durationBackward.toString()<<" "<<m_name<<" calculateBackward() (visited)"<<endl;
760
return cs->latestFinish - m_durationBackward;
762
// First, calculate all successors
763
if (!dependChildNodes().isEmpty()) {
764
DateTime time = calculateSuccessors(dependChildNodes(), use);
765
if (time.isValid() && time < cs->latestFinish) {
766
cs->latestFinish = time;
769
if (!m_childProxyRelations.isEmpty()) {
770
DateTime time = calculateSuccessors(m_childProxyRelations, use);
771
if (time.isValid() && time < cs->latestFinish) {
772
cs->latestFinish = time;
775
//kdDebug()<<k_funcinfo<<m_name<<": latestFinish="<<cs->latestFinish<<endl;
776
if (type() == Node::Type_Task) {
777
m_durationBackward = m_effort->effort(use);
778
switch (constraint()) {
781
if (m_effort->type() == Effort::Type_Effort) {
782
DateTime t = workFinishBefore(cs->latestFinish);
783
//kdDebug()<<k_funcinfo<<m_name<<": latestFinish="<<cs->latestFinish<<" t="<<t<<endl;
785
cs->latestFinish = t;
788
m_durationBackward = duration(cs->latestFinish, use, true);
790
case Node::MustStartOn:
791
m_durationBackward = duration(m_constraintStartTime, use, false);
792
cs->latestFinish = m_constraintStartTime + m_durationBackward;
794
case Node::StartNotEarlier:
795
m_durationBackward = duration(cs->latestFinish, use, true);
796
if (cs->latestFinish - m_durationBackward < m_constraintStartTime) {
797
m_durationBackward = duration(m_constraintStartTime, use, false);
798
cs->latestFinish = m_constraintStartTime + m_durationBackward;
801
case Node::MustFinishOn:
802
cs->latestFinish = m_constraintEndTime;
803
m_durationBackward = duration(cs->latestFinish, use, true);
805
case Node::FinishNotLater:
806
if (cs->latestFinish > m_constraintEndTime) {
807
cs->latestFinish = m_constraintEndTime;
809
m_durationBackward = duration(cs->latestFinish, use, true);
811
case Node::FixedInterval: {
812
cs->latestFinish = m_constraintEndTime;
813
m_durationBackward = m_constraintEndTime - m_constraintStartTime;
817
} else if (type() == Node::Type_Milestone) {
818
m_durationBackward = Duration::zeroDuration;
819
switch (constraint()) {
820
case Node::MustFinishOn:
821
cs->latestFinish = m_constraintEndTime;
823
case Node::FinishNotLater:
824
if (cs->latestFinish > m_constraintEndTime) {
825
cs->latestFinish = m_constraintEndTime;
828
case Node::MustStartOn:
829
cs->latestFinish = m_constraintStartTime;
831
case Node::StartNotEarlier:
832
if (cs->latestFinish < m_constraintStartTime) {
833
cs->latestFinish = m_constraintStartTime;
836
case Node::FixedInterval:
837
cs->latestFinish = m_constraintEndTime;
842
//kdDebug()<<k_funcinfo<<m_name<<" "<<cs->latestFinish<<endl;
843
} else if (type() == Node::Type_Summarytask) {
844
kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
846
m_durationBackward = Duration::zeroDuration;
848
//kdDebug()<<"Latestart: "<<cs->latestFinish<<"-"<<m_durationBackward.toString()<<"="<<(cs->latestFinish-m_durationBackward).toString()<<" "<<m_name<<" calculateBackward()"<<endl;
849
m_visitedBackward = true;
850
return cs->latestFinish - m_durationBackward;
853
DateTime Task::schedulePredeccessors(const QPtrList<Relation> &list, int use) {
855
QPtrListIterator<Relation> it = list;
856
for (; it.current(); ++it) {
857
if (it.current()->parent()->type() == Type_Summarytask) {
858
//kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl;
859
continue; // skip summarytasks
861
// schedule the predecessors
862
DateTime earliest = it.current()->parent()->getEarliestStart();
863
DateTime t = it.current()->parent()->scheduleForward(earliest, use);
864
switch (it.current()->type()) {
865
case Relation::StartStart:
866
// I can't start before my predesseccor
867
t = it.current()->parent()->startTime() + it.current()->lag();
869
case Relation::FinishFinish:
870
// I can't end before my predecessor, so
871
// I can't start before it's endtime - my duration
872
t -= duration(t + it.current()->lag(), use, true);
875
t += it.current()->lag();
878
if (!time.isValid() || t > time)
881
//kdDebug()<<time.toString()<<" "<<m_name<<" schedulePredeccessors()"<<endl;
885
DateTime Task::scheduleForward(const DateTime &earliest, int use) {
886
//kdDebug()<<k_funcinfo<<m_name<<" earliest="<<earliest<<endl;
887
if (m_currentSchedule == 0) {
890
Schedule *cs = m_currentSchedule;
891
if (m_visitedForward) {
894
cs->notScheduled = false;
895
cs->startTime = earliest > cs->earliestStart ? earliest : cs->earliestStart;
896
// First, calculate all my own predecessors
897
DateTime time = schedulePredeccessors(dependParentNodes(), use);
898
if (time.isValid() && time > cs->startTime) {
899
cs->startTime = time;
900
//kdDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl;
903
time = schedulePredeccessors(m_parentProxyRelations, use);
904
if (time.isValid() && time > cs->startTime) {
905
cs->startTime = time;
906
//kdDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl;
908
//kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
909
if(type() == Node::Type_Task) {
910
cs->duration = m_effort->effort(use);
911
switch (m_constraint) {
913
// cs->startTime calculated above
914
//kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
915
if (m_effort->type() == Effort::Type_Effort) {
916
DateTime t = workStartAfter(cs->startTime);
920
cs->duration = duration(cs->startTime, use, false);
921
cs->endTime = cs->startTime + cs->duration;
922
//kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl;
925
// cd->startTime calculated above
926
cs->duration = duration(cs->latestFinish, use, true);
927
cs->endTime = cs->latestFinish;
928
cs->startTime = cs->endTime - cs->duration;
929
//kdDebug()<<k_funcinfo<<m_name<<" endTime="<<cs->endTime<<" latest="<<cs->latestFinish<<endl;
931
case Node::StartNotEarlier:
932
// cs->startTime calculated above
933
//kdDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cd->startTime.toString()<<endl;
934
if (cs->startTime < m_constraintStartTime) {
935
cs->startTime = m_constraintStartTime;
937
if (m_effort->type() == Effort::Type_Effort) {
938
DateTime t = workStartAfter(cs->startTime);
942
cs->duration = duration(cs->startTime, use, false);
943
cs->endTime = cs->startTime + cs->duration;
944
if (cs->endTime > cs->latestFinish) {
945
cs->schedulingError = true;
948
case Node::FinishNotLater:
949
// cs->startTime calculated above
950
//kdDebug()<<"FinishNotLater="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
951
cs->duration = duration(cs->startTime, use, false);
952
cs->endTime = cs->startTime + cs->duration;
953
if (cs->endTime > m_constraintEndTime) {
954
cs->schedulingError = true;
955
cs->endTime = m_constraintEndTime;
956
cs->duration = duration(cs->endTime, use, true);
957
cs->startTime = cs->endTime - cs->duration;
960
case Node::MustStartOn:
961
// cs->startTime calculated above
962
//kdDebug()<<"MustStartOn="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
963
if (m_constraintStartTime < cs->startTime ||
964
m_constraintStartTime > cs->latestFinish - m_durationBackward) {
965
cs->schedulingError = true;
967
cs->startTime = m_constraintStartTime;
968
cs->duration = duration(cs->startTime, use, false);
969
cs->endTime = cs->startTime + cs->duration;
971
case Node::MustFinishOn:
972
// cs->startTime calculated above
973
//kdDebug()<<"MustFinishOn="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
974
if (m_constraintEndTime > cs->latestFinish ||
975
m_constraintEndTime < cs->earliestStart + m_durationForward) {
976
cs->schedulingError = true;
978
cs->endTime = m_constraintEndTime;
979
cs->duration = duration(cs->endTime, use, true);
980
cs->startTime = cs->endTime - cs->duration;
982
case Node::FixedInterval: {
983
// cs->startTime calculated above
984
//kdDebug()<<"FixedInterval="<<m_constraintStartTime<<" "<<cs->startTime<<endl;
985
if (cs->startTime < cs->earliestStart) {
986
cs->schedulingError = true;
988
cs->startTime = m_constraintStartTime;
989
cs->endTime = m_constraintEndTime;
990
cs->duration = cs->endTime - cs->startTime;
991
cs->workStartTime = m_constraintStartTime;
992
cs->workEndTime = m_constraintEndTime;
993
//kdDebug()<<"FixedInterval="<<cs->startTime<<", "<<cs->endTime<<endl;
1000
m_requests->reserve(cs->startTime, cs->duration);
1002
} else if (type() == Node::Type_Milestone) {
1003
switch (m_constraint) {
1005
cs->endTime = cs->startTime;
1009
cs->startTime = cs->latestFinish;
1010
cs->endTime = cs->latestFinish;
1013
case Node::MustStartOn:
1014
case Node::FixedInterval:
1015
//kdDebug()<<"Forw, MustStartOn: "<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
1016
if (m_constraintStartTime < cs->startTime ||
1017
m_constraintStartTime > cs->latestFinish) {
1018
cs->schedulingError = true;
1020
cs->startTime = m_constraintStartTime;
1021
cs->endTime = m_constraintStartTime;
1023
case Node::MustFinishOn:
1024
if (m_constraintEndTime < cs->startTime ||
1025
m_constraintEndTime > cs->latestFinish) {
1026
cs->schedulingError = true;
1028
cs->startTime = m_constraintEndTime;
1029
cs->endTime = m_constraintEndTime;
1031
case Node::StartNotEarlier:
1032
if (cs->startTime < m_constraintStartTime) {
1033
cs->schedulingError = true;
1035
cs->endTime = cs->startTime;
1037
case Node::FinishNotLater:
1038
if (cs->startTime > m_constraintEndTime) {
1039
cs->schedulingError = true;
1041
cs->endTime = cs->startTime;
1046
cs->duration = Duration::zeroDuration;
1047
//kdDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime<<", "<<cs->endTime<<endl;
1048
} else if (type() == Node::Type_Summarytask) {
1049
//shouldn't come here
1050
cs->endTime = cs->startTime;
1051
cs->duration = cs->endTime - cs->startTime;
1052
kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
1054
//kdDebug()<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<" "<<m_name<<" scheduleForward()"<<endl;
1055
m_visitedForward = true;
1059
DateTime Task::scheduleSuccessors(const QPtrList<Relation> &list, int use) {
1061
QPtrListIterator<Relation> it = list;
1062
for (; it.current(); ++it) {
1063
if (it.current()->child()->type() == Type_Summarytask) {
1064
//kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->child()->name()<<endl;
1067
// get the successors starttime
1068
DateTime latest = it.current()->child()->getLatestFinish();
1069
DateTime t = it.current()->child()->scheduleBackward(latest, use);
1070
switch (it.current()->type()) {
1071
case Relation::StartStart:
1072
// I can't start before my successor, so
1073
// I can't finish later than it's starttime + my duration
1074
t += duration(t - it.current()->lag(), use, false);
1076
case Relation::FinishFinish:
1077
t = it.current()->child()->endTime() - it.current()->lag();
1080
t -= it.current()->lag();
1083
if (!time.isValid() || t < time)
1088
DateTime Task::scheduleBackward(const DateTime &latest, int use) {
1089
//kdDebug()<<k_funcinfo<<m_name<<": latest="<<latest<<endl;
1090
if (m_currentSchedule == 0) {
1093
Schedule *cs = m_currentSchedule;
1094
if (m_visitedBackward) {
1095
return cs->startTime;
1097
cs->notScheduled = false;
1098
cs->endTime = latest < cs->latestFinish ? latest : cs->latestFinish;
1099
// First, calculate all my own successors
1100
DateTime time = scheduleSuccessors(dependChildNodes(), use);
1101
if (time.isValid() && time < cs->endTime) {
1105
time = scheduleSuccessors(m_childProxyRelations, use);
1106
if (time.isValid() && time < cs->endTime) {
1109
if (type() == Node::Type_Task) {
1110
cs->duration = m_effort->effort(use);
1111
switch (m_constraint) {
1113
// cs->endTime calculated above
1114
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" early="<<cs->earliestStart<<endl;
1115
if (m_effort->type() == Effort::Type_Effort) {
1116
DateTime t = workFinishBefore(cs->endTime);
1117
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" t="<<t<<endl;
1121
cs->duration = duration(cs->earliestStart, use, false);
1122
cs->startTime = cs->earliestStart;
1123
DateTime e = cs->startTime + cs->duration;
1124
if (e > cs->endTime) {
1125
cs->schedulingError = true;
1128
//kdDebug()<<k_funcinfo<<m_name<<": start="<<cs->startTime<<"+"<<cs->duration.toString()<<"="<<e<<" -> end="<<cs->endTime<<endl;
1132
// cs->endTime calculated above
1133
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" late="<<cs->latestFinish<<endl;
1134
if (m_effort->type() == Effort::Type_Effort) {
1135
DateTime t = workFinishBefore(cs->endTime);
1136
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" t="<<t<<endl;
1140
cs->duration = duration(cs->endTime, use, true);
1141
cs->startTime = cs->endTime - cs->duration;
1142
//kdDebug()<<k_funcinfo<<m_name<<": lateStart="<<cs->startTime<<endl;
1144
case Node::StartNotEarlier:
1145
// cs->endTime calculated above
1146
//kdDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cs->endTime.toString()<<endl;
1147
if (m_effort->type() == Effort::Type_Effort) {
1148
DateTime t = workFinishBefore(cs->endTime);
1149
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" t="<<t<<endl;
1153
cs->duration = duration(cs->endTime, use, true);
1154
cs->startTime = cs->endTime - cs->duration;
1155
if (cs->startTime < m_constraintStartTime) {
1156
cs->schedulingError = true;
1157
cs->startTime = m_constraintStartTime;
1158
cs->duration = duration(cs->startTime, use, false);
1159
cs->endTime = cs->startTime + cs->duration;
1162
case Node::FinishNotLater:
1163
// cs->endTime calculated above
1164
//kdDebug()<<"FinishNotLater="<<m_constraintEndTime.toString()<<" "<<cs->endTime.toString()<<endl;
1165
if (cs->endTime > m_constraintEndTime) {
1166
cs->schedulingError = true;
1167
cs->endTime = m_constraintEndTime;
1169
if (m_effort->type() == Effort::Type_Effort) {
1170
DateTime t = workFinishBefore(cs->endTime);
1171
//kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" t="<<t<<endl;
1175
cs->duration = duration(cs->endTime, use, true);
1176
cs->startTime = cs->endTime - cs->duration;
1178
case Node::MustStartOn:
1179
// cs->endTime calculated above
1180
//kdDebug()<<"MustStartOn="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl;
1181
if (m_constraintStartTime < cs->earliestStart ||
1182
m_constraintStartTime > cs->latestFinish - m_durationBackward) {
1183
cs->schedulingError = true;
1185
cs->startTime = m_constraintStartTime;
1186
cs->duration = duration(cs->startTime, use, false);
1187
cs->endTime = cs->startTime + cs->duration;
1189
case Node::MustFinishOn:
1190
// cs->endTime calculated above
1191
//kdDebug()<<"MustFinishOn="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl;
1192
if (m_constraintEndTime > cs->latestFinish ||
1193
m_constraintEndTime < cs->earliestStart + m_durationForward) {
1194
cs->schedulingError = true;
1196
cs->endTime = m_constraintEndTime;
1197
cs->duration = duration(cs->endTime, use, true);
1198
cs->startTime = cs->endTime - cs->duration;
1200
case Node::FixedInterval: {
1201
// cs->endTime calculated above
1202
//kdDebug()<<k_funcinfo<<"FixedInterval="<<m_constraintEndTime<<" "<<cs->endTime<<endl;
1203
if (m_constraintEndTime > cs->endTime) {
1204
cs->schedulingError = true;
1205
//kdDebug()<<k_funcinfo<<"FixedInterval error: "<<m_constraintEndTime<<" > "<<cs->endTime<<endl;
1207
cs->startTime = m_constraintStartTime;
1208
cs->endTime = m_constraintEndTime;
1209
cs->duration = cs->endTime - cs->startTime;
1210
cs->workStartTime = m_constraintStartTime;
1211
cs->workEndTime = m_constraintEndTime;
1218
m_requests->reserve(cs->startTime, cs->duration);
1220
} else if (type() == Node::Type_Milestone) {
1221
switch (m_constraint) {
1223
cs->startTime = cs->earliestStart;
1224
cs->endTime = cs->earliestStart;
1227
cs->startTime = cs->latestFinish;
1228
cs->endTime = cs->latestFinish;
1230
case Node::MustStartOn:
1231
case Node::FixedInterval:
1232
if (m_constraintStartTime < cs->earliestStart ||
1233
m_constraintStartTime > cs->endTime) {
1234
cs->schedulingError = true;
1236
cs->startTime = cs->earliestStart;
1237
cs->endTime = cs->earliestStart;
1239
case Node::MustFinishOn:
1240
if (m_constraintEndTime < cs->earliestStart ||
1241
m_constraintEndTime > cs->endTime) {
1242
cs->schedulingError = true;
1244
cs->startTime = cs->earliestStart;
1245
cs->endTime = cs->earliestStart;
1247
case Node::StartNotEarlier:
1248
if (m_constraintStartTime > cs->endTime) {
1249
cs->schedulingError = true;
1251
cs->startTime = cs->endTime;
1253
case Node::FinishNotLater:
1254
if (m_constraintEndTime < cs->endTime) {
1255
cs->schedulingError = true;
1257
cs->startTime = cs->endTime;
1262
cs->duration = Duration::zeroDuration;
1263
} else if (type() == Node::Type_Summarytask) {
1264
//shouldn't come here
1265
cs->startTime = cs->endTime;
1266
cs->duration = cs->endTime - cs->startTime;
1267
kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl;
1269
//kdDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<endl;
1270
m_visitedBackward = true;
1271
return cs->startTime;
1274
void Task::adjustSummarytask() {
1275
if (m_currentSchedule == 0)
1277
if (type() == Type_Summarytask) {
1278
DateTime start = m_currentSchedule->latestFinish;
1279
DateTime end = m_currentSchedule->earliestStart;
1280
QPtrListIterator<Node> it(m_nodes);
1281
for (; it.current(); ++it) {
1282
it.current()->adjustSummarytask();
1283
if (it.current()->startTime() < start)
1284
start = it.current()->startTime();
1285
if (it.current()->endTime() > end)
1286
end = it.current()->endTime();
1288
m_currentSchedule->startTime = start;
1289
m_currentSchedule->endTime = end;
1290
m_currentSchedule->duration = end - start;
1291
m_currentSchedule->notScheduled = false;
1292
//kdDebug()<<k_funcinfo<<cs->name<<": "<<m_currentSchedule->startTime.toString()<<" : "<<m_currentSchedule->endTime.toString()<<endl;
1296
Duration Task::calcDuration(const DateTime &time, const Duration &effort, bool backward) {
1297
//kdDebug()<<"--------> calcDuration "<<(backward?"(B) ":"(F) ")<<m_name<<" time="<<time<<" effort="<<effort.toString(Duration::Format_Day)<<endl;
1299
// Allready checked: m_effort, m_currentSchedule and time.
1300
Duration dur = effort; // use effort as default duration
1301
if (m_effort->type() == Effort::Type_Effort) {
1302
if (m_requests == 0 || m_requests->isEmpty()) {
1303
m_currentSchedule->resourceError = true;
1306
dur = m_requests->duration(time, effort, backward);
1307
if (dur == Duration::zeroDuration) {
1308
kdWarning()<<k_funcinfo<<"zero duration: Resource not available"<<endl;
1309
m_currentSchedule->resourceNotAvailable = true;
1314
if (m_effort->type() == Effort::Type_FixedDuration) {
1315
//TODO: Different types of fixed duration
1318
kdError()<<k_funcinfo<<"Unsupported effort type: "<<m_effort->type()<<endl;
1322
void Task::clearProxyRelations() {
1323
m_parentProxyRelations.clear();
1324
m_childProxyRelations.clear();
1327
void Task::addParentProxyRelations(QPtrList<Relation> &list) {
1328
//kdDebug()<<k_funcinfo<<m_name<<endl;
1329
if (type() == Type_Summarytask) {
1330
// propagate to my children
1331
//kdDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl;
1332
QPtrListIterator<Node> nodes = m_nodes;
1333
for (; nodes.current(); ++nodes) {
1334
nodes.current()->addParentProxyRelations(list);
1335
nodes.current()->addParentProxyRelations(dependParentNodes());
1338
// add 'this' as child relation to the relations parent
1339
//kdDebug()<<k_funcinfo<<m_name<<" is not summary task"<<endl;
1340
QPtrListIterator<Relation> it = list;
1341
for (; it.current(); ++it) {
1342
it.current()->parent()->addChildProxyRelation(this, it.current());
1343
// add a parent relation to myself
1344
addParentProxyRelation(it.current()->parent(), it.current());
1349
void Task::addChildProxyRelations(QPtrList<Relation> &list) {
1350
//kdDebug()<<k_funcinfo<<m_name<<endl;
1351
if (type() == Type_Summarytask) {
1352
// propagate to my children
1353
//kdDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl;
1354
QPtrListIterator<Node> nodes = m_nodes;
1355
for (; nodes.current(); ++nodes) {
1356
nodes.current()->addChildProxyRelations(list);
1357
nodes.current()->addChildProxyRelations(dependChildNodes());
1360
// add 'this' as parent relation to the relations child
1361
//kdDebug()<<k_funcinfo<<m_name<<" is not summary task"<<endl;
1362
QPtrListIterator<Relation> it = list;
1363
for (; it.current(); ++it) {
1364
it.current()->child()->addParentProxyRelation(this, it.current());
1365
// add a child relation to myself
1366
addChildProxyRelation(it.current()->child(), it.current());
1371
void Task::addParentProxyRelation(Node *node, const Relation *rel) {
1372
if (node->type() != Type_Summarytask) {
1373
if (type() == Type_Summarytask) {
1374
//kdDebug()<<"Add parent proxy from my children "<<m_name<<" to "<<node->name()<<endl;
1375
QPtrListIterator<Node> nodes = m_nodes;
1376
for (; nodes.current(); ++nodes) {
1377
nodes.current()->addParentProxyRelation(node, rel);
1380
//kdDebug()<<"Add parent proxy from "<<node->name()<<" to (me) "<<m_name<<endl;
1381
m_parentProxyRelations.append(new ProxyRelation(node, this, rel->type(), rel->lag()));
1386
void Task::addChildProxyRelation(Node *node, const Relation *rel) {
1387
if (node->type() != Type_Summarytask) {
1388
if (type() == Type_Summarytask) {
1389
//kdDebug()<<"Add child proxy from my children "<<m_name<<" to "<<node->name()<<endl;
1390
QPtrListIterator<Node> nodes = m_nodes;
1391
for (; nodes.current(); ++nodes) {
1392
nodes.current()->addChildProxyRelation(node, rel);
1395
//kdDebug()<<"Add child proxy from (me) "<<m_name<<" to "<<node->name()<<endl;
1396
m_childProxyRelations.append(new ProxyRelation(this, node, rel->type(), rel->lag()));
1401
bool Task::isEndNode() const {
1402
QPtrListIterator<Relation> it = m_dependChildNodes;
1403
for (; it.current(); ++it) {
1404
if (it.current()->type() == Relation::FinishStart)
1407
QPtrListIterator<Relation> pit = m_childProxyRelations;
1408
for (; pit.current(); ++pit) {
1409
if (pit.current()->type() == Relation::FinishStart)
1414
bool Task::isStartNode() const {
1415
QPtrListIterator<Relation> it = m_dependParentNodes;
1416
for (; it.current(); ++it) {
1417
if (it.current()->type() == Relation::FinishStart ||
1418
it.current()->type() == Relation::StartStart)
1421
QPtrListIterator<Relation> pit = m_parentProxyRelations;
1422
for (; pit.current(); ++pit) {
1423
if (pit.current()->type() == Relation::FinishStart ||
1424
pit.current()->type() == Relation::StartStart)
1430
DateTime Task::workStartTime() const {
1431
if (m_currentSchedule == 0)
1434
return m_currentSchedule->workStartTime;
1435
return m_currentSchedule->startTime;
1438
DateTime Task::workEndTime() const {
1439
if (m_currentSchedule == 0)
1441
return m_currentSchedule->endTime;
1444
DateTime Task::workStartAfter(const DateTime &dt) {
1446
DateTime t = m_requests->availableAfter(dt);
1447
return t.isValid() ? t : dt;
1452
DateTime Task::workFinishBefore(const DateTime &dt) {
1454
return m_requests->availableBefore(dt);
1459
Duration Task::positiveFloat() {
1460
if (m_currentSchedule == 0)
1461
return Duration::zeroDuration;
1463
if (type() == Node::Type_Milestone) {
1464
if (m_currentSchedule->startTime < m_currentSchedule->latestFinish) {
1465
f = m_currentSchedule->latestFinish - m_currentSchedule->startTime;
1468
if (m_currentSchedule->workEndTime.isValid())
1469
if (m_currentSchedule->workEndTime < m_currentSchedule->latestFinish) {
1470
f = m_currentSchedule->latestFinish - m_currentSchedule->workEndTime;
1471
} else if (m_currentSchedule->endTime.isValid()) {
1472
if (m_currentSchedule->endTime < m_currentSchedule->latestFinish) {
1473
f = m_currentSchedule->latestFinish - m_currentSchedule->endTime;
1477
//kdDebug()<<k_funcinfo<<f.toString()<<endl;
1481
bool Task::isCritical() {
1482
Schedule *cs = m_currentSchedule;
1486
return cs->earliestStart >= cs->startTime && cs->latestFinish <= cs->endTime;
1489
bool Task::calcCriticalPath(bool fromEnd) {
1490
if (m_currentSchedule == 0)
1492
//kdDebug()<<k_funcinfo<<m_name<<" fromEnd="<<fromEnd<<" cp="<<m_currentSchedule->inCriticalPath<<endl;
1493
if (m_currentSchedule->inCriticalPath) {
1494
return true; // path allready calculated
1496
if (!isCritical()) {
1501
m_currentSchedule->inCriticalPath = true;
1502
//kdDebug()<<k_funcinfo<<m_name<<" end node"<<endl;
1505
QPtrListIterator<Relation> it(m_childProxyRelations);
1506
for (; it.current(); ++it) {
1507
if (it.current()->child()->calcCriticalPath(fromEnd)) {
1508
m_currentSchedule->inCriticalPath = true;
1511
QPtrListIterator<Relation> pit(m_dependChildNodes);
1512
for (; pit.current(); ++pit) {
1513
if (pit.current()->child()->calcCriticalPath(fromEnd)) {
1514
m_currentSchedule->inCriticalPath = true;
1518
if (isStartNode()) {
1519
m_currentSchedule->inCriticalPath = true;
1520
//kdDebug()<<k_funcinfo<<m_name<<" start node"<<endl;
1523
QPtrListIterator<Relation> it(m_parentProxyRelations);
1524
for (; it.current(); ++it) {
1525
if (it.current()->parent()->calcCriticalPath(fromEnd)) {
1526
m_currentSchedule->inCriticalPath = true;
1529
QPtrListIterator<Relation> pit(m_dependParentNodes);
1530
for (; pit.current(); ++pit) {
1531
if (pit.current()->parent()->calcCriticalPath(fromEnd)) {
1532
m_currentSchedule->inCriticalPath = true;
1536
//kdDebug()<<k_funcinfo<<m_name<<" return cp="<<m_currentSchedule->inCriticalPath<<endl;
1537
return m_currentSchedule->inCriticalPath;
1540
void Task::setCurrentSchedule(long id) {
1541
setCurrentSchedulePtr(findSchedule(id));
1542
Node::setCurrentSchedule(id);
1547
void Task::printDebug(bool children, QCString indent) {
1548
kdDebug()<<indent<<"+ Task node: "<<name()<<" type="<<type()<<endl;
1550
kdDebug()<<indent<<"Requested resources (total): "<<units()<<"%"<<endl;
1551
kdDebug()<<indent<<"Requested resources (work): "<<workUnits()<<"%"<<endl;
1553
m_requests->printDebug(indent);
1555
Node::printDebug(children, indent);
1561
} //KPlato namespace