~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to kplato/kpttask.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-04-20 21:38:53 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060420213853-j5lxluqvymxt2zny
Tags: 1:1.5.0-0ubuntu2
UbuntuĀ uploadĀ 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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.
 
19
*/
 
20
 
 
21
#include "kpttask.h"
 
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"
 
30
 
 
31
#include <qdom.h>
 
32
#include <qbrush.h>
 
33
#include <kdebug.h>
 
34
 
 
35
namespace KPlato
 
36
{
 
37
 
 
38
Task::Task(Node *parent) : Node(parent), m_resource() {
 
39
    //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
 
40
    m_resource.setAutoDelete(true);
 
41
    Duration d(1, 0, 0);
 
42
    m_effort = new Effort(d);
 
43
    m_effort->setOptimisticRatio(-10);
 
44
    m_effort->setPessimisticRatio(20);
 
45
    m_requests = 0;
 
46
 
 
47
    if (m_parent)
 
48
        m_leader = m_parent->leader();
 
49
    
 
50
    m_schedules.setAutoDelete(true);
 
51
    m_parentProxyRelations.setAutoDelete(true);
 
52
    m_childProxyRelations.setAutoDelete(true);
 
53
}
 
54
 
 
55
Task::Task(Task &task, Node *parent) 
 
56
    : Node(task, parent), 
 
57
      m_resource() {
 
58
    //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
 
59
    m_resource.setAutoDelete(true);
 
60
    
 
61
    m_parentProxyRelations.setAutoDelete(true);
 
62
    m_childProxyRelations.setAutoDelete(true);
 
63
    m_requests = 0;
 
64
    
 
65
    m_effort = task.effort() ? new Effort(*(task.effort())) 
 
66
                             : new Effort(); // Avoid crash, (shouldn't be zero)
 
67
}
 
68
 
 
69
 
 
70
Task::~Task() {
 
71
    delete m_effort;
 
72
}
 
73
 
 
74
int Task::type() const {
 
75
        if ( numChildren() > 0) {
 
76
          return Node::Type_Summarytask;
 
77
        }
 
78
        else if ( 0 == effort()->expected().seconds() ) {
 
79
                return Node::Type_Milestone;
 
80
        }
 
81
        else {
 
82
                return Node::Type_Task;
 
83
        }
 
84
}
 
85
 
 
86
 
 
87
 
 
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();
 
92
}
 
93
 
 
94
Duration *Task::getRandomDuration() {
 
95
    return 0L;
 
96
}
 
97
 
 
98
ResourceGroupRequest *Task::resourceGroupRequest(ResourceGroup *group) const {
 
99
    if (m_requests)
 
100
        return m_requests->find(group);
 
101
    return 0;
 
102
}
 
103
 
 
104
void Task::clearResourceRequests() {
 
105
    if (m_requests)
 
106
        m_requests->clear();
 
107
}
 
108
 
 
109
void Task::addRequest(ResourceGroup *group, int numResources) {
 
110
    addRequest(new ResourceGroupRequest(group, numResources));
 
111
}
 
112
 
 
113
void Task::addRequest(ResourceGroupRequest *request) {
 
114
    if (!m_requests)
 
115
        m_requests = new ResourceRequestCollection(*this);
 
116
    m_requests->addRequest(request);
 
117
}
 
118
 
 
119
void Task::takeRequest(ResourceGroupRequest *request) {
 
120
    if (m_requests) {
 
121
        m_requests->takeRequest(request);
 
122
        if (m_requests->isEmpty()) {
 
123
            delete m_requests;
 
124
            m_requests = 0;
 
125
        }
 
126
    }
 
127
}
 
128
 
 
129
int Task::units() const {
 
130
    if (!m_requests)
 
131
        return 0;
 
132
    return m_requests->units();
 
133
}
 
134
 
 
135
int Task::workUnits() const {
 
136
    if (!m_requests)
 
137
        return 0;
 
138
    return m_requests->workUnits();
 
139
}
 
140
 
 
141
void Task::makeAppointments() {
 
142
    if (m_currentSchedule == 0)
 
143
        return;
 
144
    if (type() == Node::Type_Task) {
 
145
        if (m_requests) {
 
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;
 
149
        }
 
150
    } else if (type() == Node::Type_Summarytask) {
 
151
        QPtrListIterator<Node> nit(m_nodes);
 
152
        for ( ; nit.current(); ++nit ) {
 
153
            nit.current()->makeAppointments();
 
154
        }
 
155
    } else if (type() == Node::Type_Milestone) {
 
156
        //kdDebug()<<k_funcinfo<<"Milestone not implemented"<<endl;
 
157
        // Well, shouldn't have resources anyway...
 
158
    }
 
159
}
 
160
 
 
161
void Task::calcResourceOverbooked() {
 
162
    if (m_currentSchedule)
 
163
        m_currentSchedule->calcResourceOverbooked();
 
164
}
 
165
 
 
166
// A new constraint means start/end times and duration must be recalculated
 
167
void Task::setConstraint(Node::ConstraintType type) {
 
168
    m_constraint = type;
 
169
}
 
170
 
 
171
 
 
172
bool Task::load(QDomElement &element, Project &project) {
 
173
    // Load attributes (TODO: Handle different types of tasks, milestone, summary...)
 
174
    QString s;
 
175
    bool ok = false;
 
176
    m_id = element.attribute("id");
 
177
    
 
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;
 
182
 
 
183
    // Allow for both numeric and text
 
184
    QString constraint = element.attribute("scheduling","0");
 
185
    m_constraint = (Node::ConstraintType)constraint.toInt(&ok);
 
186
    if (!ok)
 
187
        Node::setConstraint(constraint); // hmmm, why do I need Node::?
 
188
 
 
189
    s = element.attribute("constraint-starttime");
 
190
    if (s != "")
 
191
        m_constraintStartTime = DateTime::fromString(s);
 
192
    s = element.attribute("constraint-endtime");
 
193
    if ( s != "")
 
194
        m_constraintEndTime = DateTime::fromString(s);
 
195
    
 
196
    m_startupCost = element.attribute("startup-cost", "0.0").toDouble();
 
197
    m_shutdownCost = element.attribute("shutdown-cost", "0.0").toDouble();
 
198
    
 
199
    m_wbs = element.attribute("wbs", "");
 
200
    
 
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();
 
206
 
 
207
            if (e.tagName() == "project") {
 
208
                // Load the subproject
 
209
                Project *child = new Project(this);
 
210
                if (child->load(e)) {
 
211
                    addChildNode(child);
 
212
                } else {
 
213
                    // TODO: Complain about this
 
214
                    delete child;
 
215
                }
 
216
            } else if (e.tagName() == "task") {
 
217
                // Load the task
 
218
                Task *child = new Task(this);
 
219
                if (child->load(e, project)) {
 
220
                    addChildNode(child);
 
221
                } else {
 
222
                    // TODO: Complain about this
 
223
                    delete child;
 
224
                }
 
225
            } else if (e.tagName() == "resource") {
 
226
                // TODO: Load the resource (projects don't have resources yet)
 
227
            } else if (e.tagName() == "effort") {
 
228
                //  Load the effort
 
229
                m_effort->load(e);
 
230
            } else if (e.tagName() == "resourcegroup-request") {
 
231
                // Load the resource request
 
232
                ResourceGroupRequest *r = new ResourceGroupRequest();
 
233
                if (r->load(e, project)) {
 
234
                    addRequest(r);
 
235
                } else {
 
236
                    kdError()<<k_funcinfo<<"Failed to load resource request"<<endl;
 
237
                    delete r;
 
238
                }
 
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();
 
242
                
 
243
                s = e.attribute("startTime");
 
244
                if (s != "")
 
245
                    m_progress.startTime = DateTime::fromString(s);
 
246
                s = e.attribute("finishTime");
 
247
                if (s != "")
 
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)) {
 
260
                                sch->setNode(this);
 
261
                                addSchedule(sch);
 
262
                            } else {
 
263
                                kdError()<<k_funcinfo<<"Failed to load schedule"<<endl;
 
264
                                delete sch;
 
265
                            }
 
266
                        }
 
267
                    }
 
268
                }
 
269
            }
 
270
        }
 
271
    }
 
272
    //kdDebug()<<k_funcinfo<<m_name<<" loaded"<<endl;
 
273
    return true;
 
274
}
 
275
 
 
276
 
 
277
void Task::save(QDomElement &element)  const {
 
278
    QDomElement me = element.ownerDocument().createElement("task");
 
279
    element.appendChild(me);
 
280
 
 
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);
 
286
 
 
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));    
 
290
 
 
291
    me.setAttribute("startup-cost", m_startupCost);
 
292
    me.setAttribute("shutdown-cost", m_shutdownCost);
 
293
    
 
294
    me.setAttribute("wbs", m_wbs);
 
295
    
 
296
    m_effort->save(me);
 
297
 
 
298
    QDomElement el = me.ownerDocument().createElement("progress");
 
299
    me.appendChild(el);
 
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());
 
307
    
 
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);
 
315
            }
 
316
        }
 
317
    }
 
318
    if (m_requests) {
 
319
        m_requests->save(me);
 
320
    }
 
321
    for (int i=0; i<numChildren(); i++) {
 
322
        getChildNode(i)->save(me);
 
323
    }
 
324
}
 
325
 
 
326
void Task::saveAppointments(QDomElement &element, long id) const {
 
327
    //kdDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl;
 
328
    Schedule *sch = findSchedule(id);
 
329
    if (sch) {
 
330
        sch->saveAppointments(element);
 
331
    }
 
332
    QPtrListIterator<Node> it(m_nodes);
 
333
    for (; it.current(); ++it ) {
 
334
        it.current()->saveAppointments(element, id);
 
335
    }
 
336
}
 
337
 
 
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);
 
342
    }
 
343
    return EffortCostMap();
 
344
}
 
345
 
 
346
// Returns the total planned effort for this task (or subtasks) 
 
347
Duration Task::plannedEffort() {
 
348
   //kdDebug()<<k_funcinfo<<endl;
 
349
    Duration eff;
 
350
    if (type() == Node::Type_Summarytask) {
 
351
        QPtrListIterator<Node> it(childNodeIterator());
 
352
        for (; it.current(); ++it) {
 
353
            eff += it.current()->plannedEffort();
 
354
        }
 
355
    } else if (m_currentSchedule) {
 
356
        eff = m_currentSchedule->plannedEffort();
 
357
    }
 
358
    return eff;
 
359
}
 
360
 
 
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;
 
364
    Duration eff;
 
365
    if (type() == Node::Type_Summarytask) {
 
366
        QPtrListIterator<Node> it(childNodeIterator());
 
367
        for (; it.current(); ++it) {
 
368
            eff += it.current()->plannedEffort(date);
 
369
        }
 
370
    } else if (m_currentSchedule) {
 
371
        eff = m_currentSchedule->plannedEffort(date);
 
372
    }
 
373
    return eff;
 
374
}
 
375
 
 
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;
 
379
    Duration eff;
 
380
    if (type() == Node::Type_Summarytask) {
 
381
        QPtrListIterator<Node> it(childNodeIterator());
 
382
        for (; it.current(); ++it) {
 
383
            eff += it.current()->plannedEffortTo(date);
 
384
        }
 
385
    } else if (m_currentSchedule) {
 
386
        eff = m_currentSchedule->plannedEffortTo(date);
 
387
    }
 
388
    return eff;
 
389
}
 
390
 
 
391
// Returns the total planned effort for this task (or subtasks) 
 
392
Duration Task::actualEffort() {
 
393
   //kdDebug()<<k_funcinfo<<endl;
 
394
    Duration eff;
 
395
    if (type() == Node::Type_Summarytask) {
 
396
        QPtrListIterator<Node> it(childNodeIterator());
 
397
        for (; it.current(); ++it) {
 
398
            eff += it.current()->actualEffort();
 
399
        }
 
400
    } else {
 
401
        eff = m_progress.totalPerformed;
 
402
    }
 
403
    /* If we want to register pr resource...
 
404
    } else if (m_currentSchedule) {
 
405
        eff = m_currentSchedule->actualEffort();
 
406
    }*/
 
407
    return eff;
 
408
}
 
409
 
 
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;
 
413
    Duration eff;
 
414
    if (type() == Node::Type_Summarytask) {
 
415
        QPtrListIterator<Node> it(childNodeIterator());
 
416
        for (; it.current(); ++it) {
 
417
            eff += it.current()->actualEffort(date);
 
418
        }
 
419
    } else if (m_currentSchedule) {
 
420
        eff = m_currentSchedule->actualEffort(date);
 
421
    }
 
422
    return eff;
 
423
}
 
424
 
 
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;
 
428
    Duration eff;
 
429
    if (type() == Node::Type_Summarytask) {
 
430
        QPtrListIterator<Node> it(childNodeIterator());
 
431
        for (; it.current(); ++it) {
 
432
            eff += it.current()->actualEffortTo(date);
 
433
        }
 
434
    } else if (m_currentSchedule) {
 
435
        eff = m_currentSchedule->actualEffortTo(date);
 
436
    }
 
437
    return eff;
 
438
}
 
439
 
 
440
double Task::plannedCost() {
 
441
    //kdDebug()<<k_funcinfo<<endl;
 
442
    double c = 0;
 
443
    if (type() == Node::Type_Summarytask) {
 
444
        QPtrListIterator<Node> it(childNodeIterator());
 
445
        for (; it.current(); ++it) {
 
446
            c += it.current()->plannedCost();
 
447
        }
 
448
    } else if (m_currentSchedule) {
 
449
        c = m_currentSchedule->plannedCost();
 
450
    }
 
451
    return c;
 
452
}
 
453
 
 
454
double Task::plannedCost(const QDate &date) {
 
455
    //kdDebug()<<k_funcinfo<<endl;
 
456
    double c = 0;
 
457
    if (type() == Node::Type_Summarytask) {
 
458
        QPtrListIterator<Node> it(childNodeIterator());
 
459
        for (; it.current(); ++it) {
 
460
            c += it.current()->plannedCost(date);
 
461
        }
 
462
    } else if (m_currentSchedule) {
 
463
        c = m_currentSchedule->plannedCost(date);
 
464
    }
 
465
    return c;
 
466
}
 
467
 
 
468
double Task::plannedCostTo(const QDate &date) {
 
469
    //kdDebug()<<k_funcinfo<<endl;
 
470
    double c = 0;
 
471
    if (type() == Node::Type_Summarytask) {
 
472
        QPtrListIterator<Node> it(childNodeIterator());
 
473
        for (; it.current(); ++it) {
 
474
            c += it.current()->plannedCostTo(date);
 
475
        }
 
476
    } else if (m_currentSchedule) {
 
477
        c = m_currentSchedule->plannedCostTo(date);
 
478
    }
 
479
    return c;
 
480
}
 
481
 
 
482
double Task::actualCost() {
 
483
    //kdDebug()<<k_funcinfo<<endl;
 
484
    double c = 0;
 
485
    if (type() == Node::Type_Summarytask) {
 
486
        QPtrListIterator<Node> it(childNodeIterator());
 
487
        for (; it.current(); ++it) {
 
488
            c += it.current()->actualCost();
 
489
        }
 
490
    } else if (m_currentSchedule) {
 
491
        c = m_currentSchedule->actualCost();
 
492
    }
 
493
    return c;
 
494
}
 
495
 
 
496
double Task::actualCost(const QDate &date) {
 
497
    //kdDebug()<<k_funcinfo<<endl;
 
498
    double c = 0;
 
499
    if (type() == Node::Type_Summarytask) {
 
500
        QPtrListIterator<Node> it(childNodeIterator());
 
501
        for (; it.current(); ++it) {
 
502
            c += it.current()->actualCost(date);
 
503
        }
 
504
    } else if (m_currentSchedule) {
 
505
        c = m_currentSchedule->actualCost(date);
 
506
    }
 
507
    return c;
 
508
}
 
509
 
 
510
double Task::actualCostTo(const QDate &date) {
 
511
    //kdDebug()<<k_funcinfo<<endl;
 
512
    double c = 0;
 
513
    if (type() == Node::Type_Summarytask) {
 
514
        QPtrListIterator<Node> it(childNodeIterator());
 
515
        for (; it.current(); ++it) {
 
516
            c += it.current()->actualCostTo(date);
 
517
        }
 
518
    } else if (m_currentSchedule) {
 
519
        c = m_currentSchedule->actualCostTo(date);
 
520
    }
 
521
    return c;
 
522
}
 
523
 
 
524
//FIXME Handle summarytasks
 
525
double Task::effortPerformanceIndex(const QDate &date, bool *error) {
 
526
    double res = 0.0;
 
527
    Duration ae = actualEffortTo(date);
 
528
    
 
529
    bool e = (ae == Duration::zeroDuration || m_progress.percentFinished == 0);
 
530
    if (error) {
 
531
        *error = e;
 
532
    }
 
533
    if (!e) {
 
534
        res = (plannedEffortTo(date).toDouble() * ((double)m_progress.percentFinished/100.0) / ae.toDouble());
 
535
    }
 
536
    return res;
 
537
}
 
538
 
 
539
//FIXME Handle summarytasks
 
540
double Task::costPerformanceIndex(const QDate &date, bool *error) {
 
541
    double res = 0.0;
 
542
    Duration ac = Q_INT64(actualCostTo(date));
 
543
    
 
544
    bool e = (ac == Duration::zeroDuration || m_progress.percentFinished == 0);
 
545
    if (error) {
 
546
        *error = e;
 
547
    }
 
548
    if (!e) {
 
549
        res = (plannedCostTo(date) * m_progress.percentFinished)/(100 * actualCostTo(date));
 
550
    }
 
551
    return res;
 
552
}
 
553
 
 
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);
 
562
}
 
563
 
 
564
 
 
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
 
570
        
 
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);
 
578
        }        
 
579
    } else {
 
580
        if (isEndNode()) {
 
581
            endnodes.append(this);
 
582
            //kdDebug()<<k_funcinfo<<"endnodes append: "<<m_name<<endl;
 
583
        }
 
584
        if (isStartNode()) {
 
585
            startnodes.append(this);
 
586
            //kdDebug()<<k_funcinfo<<"startnodes append: "<<m_name<<endl;
 
587
        }
 
588
    }
 
589
}
 
590
 
 
591
DateTime Task::calculatePredeccessors(const QPtrList<Relation> &list, int use) {
 
592
    DateTime time;
 
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
 
598
        }
 
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();
 
604
                break;
 
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);
 
610
                break;
 
611
            default:
 
612
                t += it.current()->lag();
 
613
                break;
 
614
        }
 
615
        if (!time.isValid() || t > time)
 
616
            time = t;
 
617
    }
 
618
    //kdDebug()<<time.toString()<<"                  "<<m_name<<" calculatePredeccessors() ("<<list.count()<<")"<<endl;
 
619
    return time;
 
620
}
 
621
DateTime Task::calculateForward(int use) {
 
622
    //kdDebug()<<k_funcinfo<<m_name<<<<endl;
 
623
    if (m_currentSchedule == 0) {
 
624
        return DateTime();
 
625
    }
 
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;
 
630
    }
 
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;
 
636
        }
 
637
    }
 
638
    if (!m_parentProxyRelations.isEmpty()) {
 
639
        DateTime time = calculatePredeccessors(m_parentProxyRelations, use);
 
640
        if (time.isValid() && time > cs->earliestStart) {
 
641
            cs->earliestStart = time;
 
642
        }
 
643
    }
 
644
    if (type() == Node::Type_Task) {
 
645
        m_durationForward = m_effort->effort(use);
 
646
        switch (constraint()) {
 
647
            case Node::ASAP:
 
648
            case Node::ALAP:
 
649
                if (m_effort->type() == Effort::Type_Effort) {
 
650
                    DateTime t = workStartAfter(cs->earliestStart);
 
651
                    if (t.isValid())
 
652
                         cs->earliestStart = t;
 
653
                }
 
654
                m_durationForward = duration(cs->earliestStart, use, false);
 
655
                //kdDebug()<<k_funcinfo<<m_name<<": "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<endl;
 
656
                break;
 
657
            case Node::MustFinishOn:
 
658
                m_durationForward = duration(m_constraintEndTime, use, true);
 
659
                cs->earliestStart = m_constraintEndTime - m_durationForward;
 
660
                break;
 
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;
 
666
                }
 
667
                break;
 
668
            case Node::MustStartOn:
 
669
                cs->earliestStart = m_constraintStartTime;
 
670
                m_durationForward = duration(cs->earliestStart, use, false);
 
671
                break;
 
672
            case Node::StartNotEarlier:
 
673
                if (cs->earliestStart < m_constraintStartTime) {
 
674
                    cs->earliestStart = m_constraintStartTime;
 
675
                }
 
676
                m_durationForward = duration(cs->earliestStart, use, false);
 
677
                break;
 
678
            case Node::FixedInterval: {
 
679
                cs->earliestStart = m_constraintStartTime;
 
680
                m_durationForward = m_constraintEndTime - m_constraintStartTime;
 
681
                break;
 
682
            }
 
683
        }
 
684
    } else if (type() == Node::Type_Milestone) {
 
685
        m_durationForward = Duration::zeroDuration;
 
686
        switch (constraint()) {
 
687
            case Node::MustFinishOn:
 
688
                cs->earliestStart = m_constraintEndTime;
 
689
                break;
 
690
            case Node::FinishNotLater:
 
691
                if (cs->earliestStart > m_constraintEndTime) {
 
692
                    cs->earliestStart = m_constraintEndTime;
 
693
                }
 
694
                break;
 
695
            case Node::MustStartOn:
 
696
                cs->earliestStart = m_constraintStartTime;
 
697
                break;
 
698
            case Node::StartNotEarlier:
 
699
                if (cs->earliestStart < m_constraintStartTime) {
 
700
                    cs->earliestStart = m_constraintStartTime;
 
701
                }
 
702
                break;
 
703
            case Node::FixedInterval:
 
704
                cs->earliestStart = m_constraintStartTime;
 
705
                break;
 
706
            default:
 
707
                break;
 
708
        }
 
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;
 
712
    } else { // ???
 
713
        m_durationForward = Duration::zeroDuration;
 
714
    }
 
715
    
 
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;
 
719
}
 
720
 
 
721
DateTime Task::calculateSuccessors(const QPtrList<Relation> &list, int use) {
 
722
    DateTime time;
 
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
 
728
        }
 
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);
 
736
                break;
 
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();
 
741
                break;
 
742
            default:
 
743
                t -= it.current()->lag();
 
744
                break;
 
745
        }
 
746
        if (!time.isValid() || t < time)
 
747
            time = t;
 
748
    }
 
749
    //kdDebug()<<time.toString()<<"                  "<<m_name<<" calculateSuccessors() ("<<list.count()<<")"<<endl;
 
750
    return time;
 
751
}
 
752
DateTime Task::calculateBackward(int use) {
 
753
    //kdDebug()<<k_funcinfo<<m_name<<endl;
 
754
    if (m_currentSchedule == 0) {
 
755
        return DateTime();
 
756
    }
 
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;
 
761
    }
 
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;
 
767
        }
 
768
    }
 
769
    if (!m_childProxyRelations.isEmpty()) {
 
770
        DateTime time = calculateSuccessors(m_childProxyRelations, use);
 
771
        if (time.isValid() && time < cs->latestFinish) {
 
772
            cs->latestFinish = time;
 
773
        }
 
774
    }
 
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()) {
 
779
            case Node::ASAP:
 
780
            case Node::ALAP:
 
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;
 
784
                    if (t.isValid()) {
 
785
                        cs->latestFinish = t;
 
786
                    }
 
787
                }
 
788
                m_durationBackward = duration(cs->latestFinish, use, true);
 
789
                break;
 
790
            case Node::MustStartOn:
 
791
                m_durationBackward = duration(m_constraintStartTime, use, false);
 
792
                cs->latestFinish = m_constraintStartTime + m_durationBackward;
 
793
                break;
 
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;
 
799
                }
 
800
                break;
 
801
            case Node::MustFinishOn:
 
802
                cs->latestFinish = m_constraintEndTime;
 
803
                m_durationBackward = duration(cs->latestFinish, use, true);
 
804
                break;
 
805
            case Node::FinishNotLater:
 
806
                if (cs->latestFinish > m_constraintEndTime) {
 
807
                    cs->latestFinish = m_constraintEndTime;
 
808
                }
 
809
                m_durationBackward = duration(cs->latestFinish, use, true);
 
810
                break;
 
811
            case Node::FixedInterval: {
 
812
                cs->latestFinish = m_constraintEndTime;
 
813
                m_durationBackward = m_constraintEndTime - m_constraintStartTime;
 
814
                break;
 
815
            }
 
816
        }
 
817
    } else if (type() == Node::Type_Milestone) {
 
818
        m_durationBackward = Duration::zeroDuration;
 
819
        switch (constraint()) {
 
820
            case Node::MustFinishOn:
 
821
                cs->latestFinish = m_constraintEndTime;
 
822
                break;
 
823
            case Node::FinishNotLater:
 
824
                if (cs->latestFinish > m_constraintEndTime) {
 
825
                    cs->latestFinish = m_constraintEndTime;
 
826
                }
 
827
                break;
 
828
            case Node::MustStartOn:
 
829
                cs->latestFinish = m_constraintStartTime;
 
830
                break;
 
831
            case Node::StartNotEarlier:
 
832
                if (cs->latestFinish < m_constraintStartTime) {
 
833
                    cs->latestFinish = m_constraintStartTime;
 
834
                }
 
835
                break;
 
836
            case Node::FixedInterval:
 
837
                cs->latestFinish = m_constraintEndTime;
 
838
                break;
 
839
            default:
 
840
                break;
 
841
        }
 
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;
 
845
    } else { // ???
 
846
        m_durationBackward = Duration::zeroDuration;
 
847
    }
 
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;
 
851
}
 
852
 
 
853
DateTime Task::schedulePredeccessors(const QPtrList<Relation> &list, int use) {
 
854
    DateTime time;
 
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
 
860
        }
 
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();
 
868
                break;
 
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);
 
873
                break;
 
874
            default:
 
875
                t += it.current()->lag();
 
876
                break;
 
877
        }
 
878
        if (!time.isValid() || t > time)
 
879
            time = t;
 
880
    }
 
881
    //kdDebug()<<time.toString()<<" "<<m_name<<" schedulePredeccessors()"<<endl;
 
882
    return time;
 
883
}
 
884
 
 
885
DateTime Task::scheduleForward(const DateTime &earliest, int use) {
 
886
    //kdDebug()<<k_funcinfo<<m_name<<" earliest="<<earliest<<endl;
 
887
    if (m_currentSchedule == 0) {
 
888
        return DateTime();
 
889
    }
 
890
    Schedule *cs = m_currentSchedule;
 
891
    if (m_visitedForward) {
 
892
        return cs->endTime;
 
893
    }
 
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;
 
901
    }
 
902
    // Then my parents
 
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;
 
907
    }
 
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) {
 
912
        case Node::ASAP:
 
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);
 
917
                if (t.isValid())
 
918
                    cs->startTime = t;
 
919
            }
 
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;
 
923
            break;
 
924
        case Node::ALAP:
 
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;
 
930
            break;
 
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;
 
936
            }
 
937
            if (m_effort->type() == Effort::Type_Effort) {
 
938
                DateTime t = workStartAfter(cs->startTime);
 
939
                if (t.isValid())
 
940
                    cs->startTime = t;
 
941
            }
 
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;
 
946
            }
 
947
            break;
 
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;
 
958
            }
 
959
            break;
 
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;
 
966
            }
 
967
            cs->startTime = m_constraintStartTime;
 
968
            cs->duration = duration(cs->startTime, use, false);
 
969
            cs->endTime = cs->startTime + cs->duration;
 
970
            break;
 
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;
 
977
            }
 
978
            cs->endTime = m_constraintEndTime;
 
979
            cs->duration = duration(cs->endTime, use, true);
 
980
            cs->startTime = cs->endTime - cs->duration;
 
981
            break;
 
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;
 
987
            }
 
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;
 
994
            break;
 
995
        }
 
996
        default:
 
997
            break;
 
998
        }
 
999
        if (m_requests) {
 
1000
            m_requests->reserve(cs->startTime, cs->duration);
 
1001
        }
 
1002
    } else if (type() == Node::Type_Milestone) {
 
1003
        switch (m_constraint) {
 
1004
        case Node::ASAP: {
 
1005
            cs->endTime = cs->startTime;
 
1006
            break;
 
1007
        }
 
1008
        case Node::ALAP: {
 
1009
            cs->startTime = cs->latestFinish;
 
1010
            cs->endTime = cs->latestFinish;
 
1011
            break;
 
1012
        }
 
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;
 
1019
            }
 
1020
            cs->startTime = m_constraintStartTime;
 
1021
            cs->endTime = m_constraintStartTime;
 
1022
            break;
 
1023
        case Node::MustFinishOn:
 
1024
            if (m_constraintEndTime < cs->startTime ||
 
1025
                m_constraintEndTime > cs->latestFinish) {
 
1026
                cs->schedulingError = true;
 
1027
            }
 
1028
            cs->startTime = m_constraintEndTime;
 
1029
            cs->endTime = m_constraintEndTime;
 
1030
            break;
 
1031
        case Node::StartNotEarlier:
 
1032
            if (cs->startTime < m_constraintStartTime) {
 
1033
                cs->schedulingError = true;
 
1034
            }
 
1035
            cs->endTime = cs->startTime;
 
1036
            break;
 
1037
        case Node::FinishNotLater:
 
1038
            if (cs->startTime > m_constraintEndTime) {
 
1039
                cs->schedulingError = true;
 
1040
            }
 
1041
            cs->endTime = cs->startTime;
 
1042
            break;
 
1043
        default:
 
1044
            break;
 
1045
        }
 
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;
 
1053
    }
 
1054
    //kdDebug()<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<" "<<m_name<<" scheduleForward()"<<endl;
 
1055
    m_visitedForward = true;
 
1056
    return cs->endTime;
 
1057
}
 
1058
 
 
1059
DateTime Task::scheduleSuccessors(const QPtrList<Relation> &list, int use) {
 
1060
    DateTime time;
 
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;
 
1065
            continue;
 
1066
        }
 
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);
 
1075
                break;
 
1076
            case Relation::FinishFinish:
 
1077
                t = it.current()->child()->endTime() - it.current()->lag();
 
1078
                break;
 
1079
            default:
 
1080
                t -= it.current()->lag();
 
1081
                break;
 
1082
        }
 
1083
        if (!time.isValid() || t < time)
 
1084
            time = t;
 
1085
   }
 
1086
   return time;
 
1087
}
 
1088
DateTime Task::scheduleBackward(const DateTime &latest, int use) {
 
1089
    //kdDebug()<<k_funcinfo<<m_name<<": latest="<<latest<<endl;
 
1090
    if (m_currentSchedule == 0) {
 
1091
        return DateTime();
 
1092
    }
 
1093
    Schedule *cs = m_currentSchedule;
 
1094
    if (m_visitedBackward) {
 
1095
        return cs->startTime;
 
1096
    }
 
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) {
 
1102
        cs->endTime = time;
 
1103
    }
 
1104
    // Then my parents
 
1105
    time = scheduleSuccessors(m_childProxyRelations, use);
 
1106
    if (time.isValid() && time < cs->endTime) {
 
1107
        cs->endTime = time;
 
1108
    }
 
1109
    if (type() == Node::Type_Task) {
 
1110
        cs->duration = m_effort->effort(use);
 
1111
        switch (m_constraint) {
 
1112
        case Node::ASAP: {
 
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;
 
1118
                if (t.isValid())
 
1119
                    cs->endTime = t;
 
1120
            }
 
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;
 
1126
            }
 
1127
            cs->endTime = e;
 
1128
            //kdDebug()<<k_funcinfo<<m_name<<": start="<<cs->startTime<<"+"<<cs->duration.toString()<<"="<<e<<" -> end="<<cs->endTime<<endl;
 
1129
            break;
 
1130
        }
 
1131
        case Node::ALAP:
 
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;
 
1137
                if (t.isValid())
 
1138
                    cs->endTime = t;
 
1139
            }
 
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;
 
1143
            break;
 
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;
 
1150
                if (t.isValid())
 
1151
                    cs->endTime = t;
 
1152
            }
 
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;
 
1160
            }
 
1161
            break;
 
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;
 
1168
            }
 
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;
 
1172
                if (t.isValid())
 
1173
                    cs->endTime = t;
 
1174
            }
 
1175
            cs->duration = duration(cs->endTime, use, true);
 
1176
            cs->startTime = cs->endTime - cs->duration;
 
1177
            break;
 
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;
 
1184
            }
 
1185
            cs->startTime = m_constraintStartTime;
 
1186
            cs->duration = duration(cs->startTime, use, false);
 
1187
            cs->endTime = cs->startTime + cs->duration;
 
1188
            break;
 
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;
 
1195
            }
 
1196
            cs->endTime = m_constraintEndTime;
 
1197
            cs->duration = duration(cs->endTime, use, true);
 
1198
            cs->startTime = cs->endTime - cs->duration;
 
1199
            break;
 
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;
 
1206
            }
 
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;
 
1212
            break;
 
1213
        }
 
1214
        default:
 
1215
            break;
 
1216
        }
 
1217
        if (m_requests) {
 
1218
            m_requests->reserve(cs->startTime, cs->duration);
 
1219
        }
 
1220
    } else if (type() == Node::Type_Milestone) {
 
1221
        switch (m_constraint) {
 
1222
        case Node::ASAP:
 
1223
            cs->startTime = cs->earliestStart;
 
1224
            cs->endTime = cs->earliestStart;
 
1225
            break;
 
1226
        case Node::ALAP:
 
1227
            cs->startTime = cs->latestFinish;
 
1228
            cs->endTime = cs->latestFinish;
 
1229
            break;
 
1230
        case Node::MustStartOn:
 
1231
        case Node::FixedInterval:
 
1232
            if (m_constraintStartTime < cs->earliestStart ||
 
1233
                m_constraintStartTime > cs->endTime) {
 
1234
                cs->schedulingError = true;
 
1235
            }
 
1236
            cs->startTime = cs->earliestStart;
 
1237
            cs->endTime = cs->earliestStart;
 
1238
            break;
 
1239
        case Node::MustFinishOn:
 
1240
            if (m_constraintEndTime < cs->earliestStart ||
 
1241
                m_constraintEndTime > cs->endTime) {
 
1242
                cs->schedulingError = true;
 
1243
            }
 
1244
            cs->startTime = cs->earliestStart;
 
1245
            cs->endTime = cs->earliestStart;
 
1246
            break;
 
1247
        case Node::StartNotEarlier:
 
1248
            if (m_constraintStartTime > cs->endTime) {
 
1249
                cs->schedulingError = true;
 
1250
            }
 
1251
            cs->startTime = cs->endTime;
 
1252
            break;
 
1253
        case Node::FinishNotLater:
 
1254
            if (m_constraintEndTime < cs->endTime) {
 
1255
                cs->schedulingError = true;
 
1256
            }
 
1257
            cs->startTime = cs->endTime;
 
1258
            break;
 
1259
        default:
 
1260
            break;
 
1261
        }
 
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;
 
1268
    }
 
1269
    //kdDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<endl;
 
1270
    m_visitedBackward = true;
 
1271
    return cs->startTime;
 
1272
}
 
1273
 
 
1274
void Task::adjustSummarytask() {
 
1275
    if (m_currentSchedule == 0)
 
1276
        return;
 
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();
 
1287
        }
 
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;
 
1293
    }
 
1294
}
 
1295
 
 
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;
 
1298
    
 
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;
 
1304
            return effort;
 
1305
        }
 
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;
 
1310
            dur = effort; //???
 
1311
        }
 
1312
        return dur;
 
1313
    }
 
1314
    if (m_effort->type() == Effort::Type_FixedDuration) {
 
1315
        //TODO: Different types of fixed duration
 
1316
        return dur; //
 
1317
    }
 
1318
    kdError()<<k_funcinfo<<"Unsupported effort type: "<<m_effort->type()<<endl;
 
1319
    return dur;
 
1320
}
 
1321
 
 
1322
void Task::clearProxyRelations() {
 
1323
    m_parentProxyRelations.clear();
 
1324
    m_childProxyRelations.clear();
 
1325
}
 
1326
 
 
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());
 
1336
        }        
 
1337
    } else {
 
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());
 
1345
        }
 
1346
    }
 
1347
}
 
1348
 
 
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());
 
1358
        }        
 
1359
    } else {
 
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());
 
1367
        }
 
1368
    }
 
1369
}
 
1370
 
 
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);
 
1378
            }
 
1379
        } else {
 
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()));
 
1382
        }
 
1383
    }
 
1384
}
 
1385
 
 
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);
 
1393
            }
 
1394
        } else {
 
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()));
 
1397
        }
 
1398
    }
 
1399
}
 
1400
 
 
1401
bool Task::isEndNode() const {
 
1402
    QPtrListIterator<Relation> it = m_dependChildNodes;
 
1403
    for (; it.current(); ++it) {
 
1404
        if (it.current()->type() == Relation::FinishStart)
 
1405
            return false;
 
1406
    }
 
1407
    QPtrListIterator<Relation> pit = m_childProxyRelations;
 
1408
    for (; pit.current(); ++pit) {
 
1409
        if (pit.current()->type() == Relation::FinishStart)
 
1410
            return false;
 
1411
    }
 
1412
    return true;
 
1413
}
 
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)
 
1419
            return false;
 
1420
    }
 
1421
    QPtrListIterator<Relation> pit = m_parentProxyRelations;
 
1422
    for (; pit.current(); ++pit) {
 
1423
        if (pit.current()->type() == Relation::FinishStart ||
 
1424
            pit.current()->type() == Relation::StartStart)
 
1425
            return false;
 
1426
    }
 
1427
    return true;
 
1428
}
 
1429
 
 
1430
DateTime Task::workStartTime() const {
 
1431
    if (m_currentSchedule == 0)
 
1432
         return DateTime();
 
1433
    if (m_requests)
 
1434
        return m_currentSchedule->workStartTime;
 
1435
    return m_currentSchedule->startTime;
 
1436
}
 
1437
 
 
1438
DateTime Task::workEndTime() const {
 
1439
    if (m_currentSchedule == 0)
 
1440
         return DateTime();
 
1441
    return m_currentSchedule->endTime;
 
1442
}
 
1443
 
 
1444
DateTime Task::workStartAfter(const DateTime &dt) {
 
1445
    if (m_requests) {
 
1446
        DateTime t = m_requests->availableAfter(dt);
 
1447
        return t.isValid() ? t : dt;
 
1448
    }
 
1449
    return dt;
 
1450
}
 
1451
 
 
1452
DateTime Task::workFinishBefore(const DateTime &dt) {
 
1453
    if (m_requests) {
 
1454
        return m_requests->availableBefore(dt);
 
1455
    }
 
1456
    return dt;
 
1457
}
 
1458
 
 
1459
Duration Task::positiveFloat() {
 
1460
    if (m_currentSchedule == 0)
 
1461
        return Duration::zeroDuration;
 
1462
    Duration f;
 
1463
    if (type() == Node::Type_Milestone) {
 
1464
        if (m_currentSchedule->startTime < m_currentSchedule->latestFinish) {
 
1465
            f = m_currentSchedule->latestFinish - m_currentSchedule->startTime;
 
1466
        }
 
1467
    } else {
 
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;
 
1474
            }
 
1475
        }
 
1476
    }
 
1477
    //kdDebug()<<k_funcinfo<<f.toString()<<endl;
 
1478
    return f;
 
1479
}
 
1480
 
 
1481
bool Task::isCritical() {
 
1482
    Schedule *cs = m_currentSchedule;
 
1483
    if (cs == 0) {
 
1484
        return false;
 
1485
    }
 
1486
    return cs->earliestStart >= cs->startTime && cs->latestFinish <= cs->endTime;
 
1487
}
 
1488
 
 
1489
bool Task::calcCriticalPath(bool fromEnd) {
 
1490
    if (m_currentSchedule == 0)
 
1491
        return false;
 
1492
    //kdDebug()<<k_funcinfo<<m_name<<" fromEnd="<<fromEnd<<" cp="<<m_currentSchedule->inCriticalPath<<endl;
 
1493
    if (m_currentSchedule->inCriticalPath) {
 
1494
        return true; // path allready calculated
 
1495
    }
 
1496
    if (!isCritical()) {
 
1497
        return false;
 
1498
    }
 
1499
    if (fromEnd) {
 
1500
        if (isEndNode()) {
 
1501
            m_currentSchedule->inCriticalPath = true;
 
1502
            //kdDebug()<<k_funcinfo<<m_name<<" end node"<<endl;
 
1503
            return true;
 
1504
        }
 
1505
        QPtrListIterator<Relation> it(m_childProxyRelations);
 
1506
        for (; it.current(); ++it) {
 
1507
            if (it.current()->child()->calcCriticalPath(fromEnd)) {
 
1508
                m_currentSchedule->inCriticalPath = true;
 
1509
            }
 
1510
        }
 
1511
        QPtrListIterator<Relation> pit(m_dependChildNodes);
 
1512
        for (; pit.current(); ++pit) {
 
1513
            if (pit.current()->child()->calcCriticalPath(fromEnd)) {
 
1514
                m_currentSchedule->inCriticalPath = true;
 
1515
            }
 
1516
        }
 
1517
    } else {
 
1518
        if (isStartNode()) {
 
1519
            m_currentSchedule->inCriticalPath = true;
 
1520
            //kdDebug()<<k_funcinfo<<m_name<<" start node"<<endl;
 
1521
            return true;
 
1522
        }
 
1523
        QPtrListIterator<Relation> it(m_parentProxyRelations);
 
1524
        for (; it.current(); ++it) {
 
1525
            if (it.current()->parent()->calcCriticalPath(fromEnd)) {
 
1526
                m_currentSchedule->inCriticalPath = true;
 
1527
            }
 
1528
        }
 
1529
        QPtrListIterator<Relation> pit(m_dependParentNodes);
 
1530
        for (; pit.current(); ++pit) {
 
1531
            if (pit.current()->parent()->calcCriticalPath(fromEnd)) {
 
1532
                m_currentSchedule->inCriticalPath = true;
 
1533
            }
 
1534
        }
 
1535
    }
 
1536
    //kdDebug()<<k_funcinfo<<m_name<<" return cp="<<m_currentSchedule->inCriticalPath<<endl;
 
1537
    return m_currentSchedule->inCriticalPath;
 
1538
}
 
1539
 
 
1540
void Task::setCurrentSchedule(long id) {
 
1541
    setCurrentSchedulePtr(findSchedule(id));
 
1542
    Node::setCurrentSchedule(id);
 
1543
}
 
1544
 
 
1545
 
 
1546
#ifndef NDEBUG
 
1547
void Task::printDebug(bool children, QCString indent) {
 
1548
    kdDebug()<<indent<<"+ Task node: "<<name()<<" type="<<type()<<endl;
 
1549
    indent += "!  ";
 
1550
    kdDebug()<<indent<<"Requested resources (total): "<<units()<<"%"<<endl;
 
1551
    kdDebug()<<indent<<"Requested resources (work): "<<workUnits()<<"%"<<endl;
 
1552
    if (m_requests)
 
1553
        m_requests->printDebug(indent);
 
1554
    
 
1555
    Node::printDebug(children, indent);
 
1556
 
 
1557
}
 
1558
 
 
1559
#endif
 
1560
 
 
1561
}  //KPlato namespace