/* This file is part of the KDE project Copyright (C) 2001 Thomas zander Copyright (C) 2004 Dag Andersen This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kpttask.h" #include "kptproject.h" #include "kpttaskdialog.h" #include "kptduration.h" #include "kptrelation.h" #include "kptdatetime.h" #include "kptcalendar.h" #include "kpteffortcostmap.h" #include "kptschedule.h" #include #include #include namespace KPlato { Task::Task(Node *parent) : Node(parent), m_resource() { //kdDebug()<setOptimisticRatio(-10); m_effort->setPessimisticRatio(20); m_requests = 0; if (m_parent) m_leader = m_parent->leader(); m_schedules.setAutoDelete(true); m_parentProxyRelations.setAutoDelete(true); m_childProxyRelations.setAutoDelete(true); } Task::Task(Task &task, Node *parent) : Node(task, parent), m_resource() { //kdDebug()< 0) { return Node::Type_Summarytask; } else if ( 0 == effort()->expected().seconds() ) { return Node::Type_Milestone; } else { return Node::Type_Task; } } Duration *Task::getExpectedDuration() { //kdDebug()<duration) : new Duration(); } Duration *Task::getRandomDuration() { return 0L; } ResourceGroupRequest *Task::resourceGroupRequest(ResourceGroup *group) const { if (m_requests) return m_requests->find(group); return 0; } void Task::clearResourceRequests() { if (m_requests) m_requests->clear(); } void Task::addRequest(ResourceGroup *group, int numResources) { addRequest(new ResourceGroupRequest(group, numResources)); } void Task::addRequest(ResourceGroupRequest *request) { if (!m_requests) m_requests = new ResourceRequestCollection(*this); m_requests->addRequest(request); } void Task::takeRequest(ResourceGroupRequest *request) { if (m_requests) { m_requests->takeRequest(request); if (m_requests->isEmpty()) { delete m_requests; m_requests = 0; } } } int Task::units() const { if (!m_requests) return 0; return m_requests->units(); } int Task::workUnits() const { if (!m_requests) return 0; return m_requests->workUnits(); } void Task::makeAppointments() { if (m_currentSchedule == 0) return; if (type() == Node::Type_Task) { if (m_requests) { //kdDebug()<startTime<<", "<endTime<<"; "<duration.toString()<makeAppointments(m_currentSchedule); //kdDebug()<startTime<<", "<endTime<<"; "<duration.toString()< nit(m_nodes); for ( ; nit.current(); ++nit ) { nit.current()->makeAppointments(); } } else if (type() == Node::Type_Milestone) { //kdDebug()<calcResourceOverbooked(); } // A new constraint means start/end times and duration must be recalculated void Task::setConstraint(Node::ConstraintType type) { m_constraint = type; } bool Task::load(QDomElement &element, Project &project) { // Load attributes (TODO: Handle different types of tasks, milestone, summary...) QString s; bool ok = false; m_id = element.attribute("id"); m_name = element.attribute("name"); m_leader = element.attribute("leader"); m_description = element.attribute("description"); //kdDebug()<load(e)) { if (!project.addSubTask(child, this)) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; } } else if (e.tagName() == "task") { // Load the task Task *child = new Task(this); if (child->load(e, project)) { if (!project.addSubTask(child, this)) { delete child; // TODO: Complain about this } } else { // TODO: Complain about this delete child; } } else if (e.tagName() == "resource") { // TODO: Load the resource (projects don't have resources yet) } else if (e.tagName() == "effort") { // Load the effort m_effort->load(e); } else if (e.tagName() == "resourcegroup-request") { // Load the resource request ResourceGroupRequest *r = new ResourceGroupRequest(); if (r->load(e, project)) { addRequest(r); } else { kdError()<loadXML(el)) { sch->setNode(this); addSchedule(sch); } else { kdError()<save(me); QDomElement el = me.ownerDocument().createElement("progress"); me.appendChild(el); el.setAttribute("started", m_progress.started); el.setAttribute("finished", m_progress.finished); el.setAttribute("startTime", m_progress.startTime.toString(Qt::ISODate)); el.setAttribute("finishTime", m_progress.finishTime.toString(Qt::ISODate)); el.setAttribute("percent-finished", m_progress.percentFinished); el.setAttribute("remaining-effort", m_progress.remainingEffort.toString()); el.setAttribute("performed-effort", m_progress.totalPerformed.toString()); if (!m_schedules.isEmpty()) { QDomElement schs = me.ownerDocument().createElement("schedules"); me.appendChild(schs); QIntDictIterator it = m_schedules; for (; it.current(); ++it) { if (!it.current()->isDeleted()) { it.current()->saveXML(schs); } } } if (m_requests) { m_requests->save(me); } for (int i=0; isave(me); } } void Task::saveAppointments(QDomElement &element, long id) const { //kdDebug()<name():"None")<<" id="<<(sch?sch->id():-1)<initiateCalculation(); clearProxyRelations(); Node::initiateCalculation(sch); } void Task::initiateCalculationLists(QPtrList &startnodes, QPtrList &endnodes, QPtrList &summarytasks/*, QPtrList &milestones*/) { //kdDebug()< nodes = m_nodes; for (; nodes.current(); ++nodes) { if (!dependParentNodes().isEmpty()) nodes.current()->addParentProxyRelations(dependParentNodes()); if (!dependChildNodes().isEmpty()) nodes.current()->addChildProxyRelations(dependChildNodes()); nodes.current()->initiateCalculationLists(startnodes, endnodes, summarytasks); } } else { if (isEndNode()) { endnodes.append(this); //kdDebug()< &list, int use) { DateTime time; QPtrListIterator it = list; for (; it.current(); ++it) { if (it.current()->parent()->type() == Type_Summarytask) { //kdDebug()<parent()->name()<parent()->calculateForward(use); // early finish switch (it.current()->type()) { case Relation::StartStart: // I can't start earlier than my predesseccor t = it.current()->parent()->getEarliestStart() + it.current()->lag(); break; case Relation::FinishFinish: // I can't finish earlier than my predeccessor, so // I can't start earlier than it's (earlyfinish+lag)- my duration t += it.current()->lag(); t -= duration(t, use, true); break; default: t += it.current()->lag(); break; } if (!time.isValid() || t > time) time = t; } //kdDebug()<earliestStart + m_durationForward; } // First, calculate all predecessors if (!dependParentNodes().isEmpty()) { DateTime time = calculatePredeccessors(dependParentNodes(), use); if (time.isValid() && time > cs->earliestStart) { cs->earliestStart = time; } } if (!m_parentProxyRelations.isEmpty()) { DateTime time = calculatePredeccessors(m_parentProxyRelations, use); if (time.isValid() && time > cs->earliestStart) { cs->earliestStart = time; } } if (type() == Node::Type_Task) { m_durationForward = m_effort->effort(use); switch (constraint()) { case Node::ASAP: case Node::ALAP: cs->earliestStart = workStartAfter(cs->earliestStart); m_durationForward = duration(cs->earliestStart, use, false); //kdDebug()<earliestStart<<"+"<earliestStart+m_durationForward)<earliestStart = m_constraintEndTime - m_durationForward; break; case Node::FinishNotLater: m_durationForward = duration(cs->earliestStart, use, false); if (cs->earliestStart + m_durationForward > m_constraintEndTime) { m_durationForward = duration(m_constraintEndTime, use, true); cs->earliestStart = m_constraintEndTime - m_durationForward; } break; case Node::MustStartOn: cs->earliestStart = m_constraintStartTime; m_durationForward = duration(cs->earliestStart, use, false); break; case Node::StartNotEarlier: if (cs->earliestStart < m_constraintStartTime) { cs->earliestStart = m_constraintStartTime; } m_durationForward = duration(cs->earliestStart, use, false); break; case Node::FixedInterval: { cs->earliestStart = m_constraintStartTime; m_durationForward = m_constraintEndTime - m_constraintStartTime; break; } } } else if (type() == Node::Type_Milestone) { m_durationForward = Duration::zeroDuration; switch (constraint()) { case Node::MustFinishOn: cs->earliestStart = m_constraintEndTime; break; case Node::FinishNotLater: if (cs->earliestStart > m_constraintEndTime) { cs->earliestStart = m_constraintEndTime; } break; case Node::MustStartOn: cs->earliestStart = m_constraintStartTime; break; case Node::StartNotEarlier: if (cs->earliestStart < m_constraintStartTime) { cs->earliestStart = m_constraintStartTime; } break; case Node::FixedInterval: cs->earliestStart = m_constraintStartTime; break; default: break; } //kdDebug()<earliestStart<<"+"<earliestStart+m_durationForward)<<" "<earliestStart + m_durationForward; } DateTime Task::calculateSuccessors(const QPtrList &list, int use) { DateTime time; QPtrListIterator it = list; for (; it.current(); ++it) { if (it.current()->child()->type() == Type_Summarytask) { //kdDebug()<parent()->name()<child()->calculateBackward(use); switch (it.current()->type()) { case Relation::StartStart: // I must start before my successor, so // I can't finish later than it's (starttime-lag) + my duration t -= it.current()->lag(); t += duration(t, use, false); break; case Relation::FinishFinish: // My successor cannot finish before me, so // I can't finish later than it's latest finish - lag t = it.current()->child()->getLatestFinish() - it.current()->lag(); break; default: t -= it.current()->lag(); break; } if (!time.isValid() || t < time) time = t; } //kdDebug()<latestFinish - m_durationBackward; } // First, calculate all successors if (!dependChildNodes().isEmpty()) { DateTime time = calculateSuccessors(dependChildNodes(), use); if (time.isValid() && time < cs->latestFinish) { cs->latestFinish = time; } } if (!m_childProxyRelations.isEmpty()) { DateTime time = calculateSuccessors(m_childProxyRelations, use); if (time.isValid() && time < cs->latestFinish) { cs->latestFinish = time; } } //kdDebug()<latestFinish<latestFinish<<"-"<latestFinish-m_durationBackward).toString()<<" "<latestFinish - m_durationBackward; } DateTime Task::schedulePredeccessors(const QPtrList &list, int use) { DateTime time; QPtrListIterator it = list; for (; it.current(); ++it) { if (it.current()->parent()->type() == Type_Summarytask) { //kdDebug()<parent()->name()<parent()->getEarliestStart(); DateTime t = it.current()->parent()->scheduleForward(earliest, use); switch (it.current()->type()) { case Relation::StartStart: // I can't start before my predesseccor t = it.current()->parent()->startTime() + it.current()->lag(); break; case Relation::FinishFinish: // I can't end before my predecessor, so // I can't start before it's endtime - my duration t -= duration(t + it.current()->lag(), use, true); break; default: t += it.current()->lag(); break; } if (!time.isValid() || t > time) time = t; } //kdDebug()<startTime.toString()<startTime < m_constraintStartTime) { cs->startTime = m_constraintStartTime; } cs->startTime = workStartAfter(cs->startTime); cs->duration = duration(cs->startTime, use, false); cs->endTime = cs->startTime + cs->duration; if (cs->endTime > cs->latestFinish) { cs->schedulingError = true; } break; case Node::FinishNotLater: // cs->startTime calculated above //kdDebug()<<"FinishNotLater="<startTime.toString()<duration = duration(cs->startTime, use, false); cs->endTime = cs->startTime + cs->duration; if (cs->endTime > m_constraintEndTime) { cs->schedulingError = true; cs->endTime = m_constraintEndTime; cs->duration = duration(cs->endTime, use, true); cs->startTime = cs->endTime - cs->duration; } break; case Node::MustStartOn: // cs->startTime calculated above //kdDebug()<<"MustStartOn="<startTime.toString()<startTime || m_constraintStartTime > cs->latestFinish - m_durationBackward) { cs->schedulingError = true; } cs->startTime = m_constraintStartTime; cs->duration = duration(cs->startTime, use, false); cs->endTime = cs->startTime + cs->duration; break; case Node::MustFinishOn: // cs->startTime calculated above //kdDebug()<<"MustFinishOn="<startTime.toString()< cs->latestFinish || m_constraintEndTime < cs->earliestStart + m_durationForward) { cs->schedulingError = true; } cs->endTime = m_constraintEndTime; cs->duration = duration(cs->endTime, use, true); cs->startTime = cs->endTime - cs->duration; break; case Node::FixedInterval: { // cs->startTime calculated above //kdDebug()<<"FixedInterval="<startTime<startTime < cs->earliestStart) { cs->schedulingError = true; } cs->startTime = m_constraintStartTime; cs->endTime = m_constraintEndTime; cs->duration = cs->endTime - cs->startTime; cs->workStartTime = m_constraintStartTime; cs->workEndTime = m_constraintEndTime; //kdDebug()<<"FixedInterval="<startTime<<", "<endTime<reserve(cs->startTime, cs->duration); } } else if (type() == Node::Type_Milestone) { switch (m_constraint) { case Node::ASAP: { cs->endTime = cs->startTime; break; } case Node::ALAP: { cs->startTime = cs->latestFinish; cs->endTime = cs->latestFinish; break; } case Node::MustStartOn: case Node::FixedInterval: //kdDebug()<<"Forw, MustStartOn: "<startTime.toString()<startTime || m_constraintStartTime > cs->latestFinish) { cs->schedulingError = true; } cs->startTime = m_constraintStartTime; cs->endTime = m_constraintStartTime; break; case Node::MustFinishOn: if (m_constraintEndTime < cs->startTime || m_constraintEndTime > cs->latestFinish) { cs->schedulingError = true; } cs->startTime = m_constraintEndTime; cs->endTime = m_constraintEndTime; break; case Node::StartNotEarlier: if (cs->startTime < m_constraintStartTime) { cs->schedulingError = true; } cs->endTime = cs->startTime; break; case Node::FinishNotLater: if (cs->startTime > m_constraintEndTime) { cs->schedulingError = true; } cs->endTime = cs->startTime; break; default: break; } cs->duration = Duration::zeroDuration; //kdDebug()<startTime<<", "<endTime<endTime = cs->startTime; cs->duration = cs->endTime - cs->startTime; kdWarning()<startTime.toString()<<" : "<endTime.toString()<<" "<endTime; } DateTime Task::scheduleSuccessors(const QPtrList &list, int use) { DateTime time; QPtrListIterator it = list; for (; it.current(); ++it) { if (it.current()->child()->type() == Type_Summarytask) { //kdDebug()<child()->name()<child()->getLatestFinish(); DateTime t = it.current()->child()->scheduleBackward(latest, use); switch (it.current()->type()) { case Relation::StartStart: // I can't start before my successor, so // I can't finish later than it's starttime + my duration t += duration(t - it.current()->lag(), use, false); break; case Relation::FinishFinish: t = it.current()->child()->endTime() - it.current()->lag(); break; default: t -= it.current()->lag(); break; } if (!time.isValid() || t < time) time = t; } return time; } DateTime Task::scheduleBackward(const DateTime &latest, int use) { //kdDebug()<duration.toString()<<"="< end="<endTime<endTime calculated above //kdDebug()<endTime.toString()<endTime = workFinishBefore(cs->endTime); cs->duration = duration(cs->endTime, use, true); cs->startTime = cs->endTime - cs->duration; if (cs->startTime < m_constraintStartTime) { cs->schedulingError = true; cs->startTime = m_constraintStartTime; cs->duration = duration(cs->startTime, use, false); cs->endTime = cs->startTime + cs->duration; } break; case Node::FinishNotLater: // cs->endTime calculated above //kdDebug()<<"FinishNotLater="<endTime.toString()<endTime > m_constraintEndTime) { cs->schedulingError = true; cs->endTime = m_constraintEndTime; } cs->endTime = workFinishBefore(cs->endTime); cs->duration = duration(cs->endTime, use, true); cs->startTime = cs->endTime - cs->duration; break; case Node::MustStartOn: // cs->endTime calculated above //kdDebug()<<"MustStartOn="<startTime.toString()<earliestStart || m_constraintStartTime > cs->latestFinish - m_durationBackward) { cs->schedulingError = true; } cs->startTime = m_constraintStartTime; cs->duration = duration(cs->startTime, use, false); cs->endTime = cs->startTime + cs->duration; break; case Node::MustFinishOn: // cs->endTime calculated above //kdDebug()<<"MustFinishOn="<startTime.toString()< cs->latestFinish || m_constraintEndTime < cs->earliestStart + m_durationForward) { cs->schedulingError = true; } cs->endTime = m_constraintEndTime; cs->duration = duration(cs->endTime, use, true); cs->startTime = cs->endTime - cs->duration; break; case Node::FixedInterval: { // cs->endTime calculated above //kdDebug()<endTime< cs->endTime) { cs->schedulingError = true; //kdDebug()< "<endTime<startTime = m_constraintStartTime; cs->endTime = m_constraintEndTime; cs->duration = cs->endTime - cs->startTime; cs->workStartTime = m_constraintStartTime; cs->workEndTime = m_constraintEndTime; break; } default: break; } if (m_requests) { m_requests->reserve(cs->startTime, cs->duration); } } else if (type() == Node::Type_Milestone) { switch (m_constraint) { case Node::ASAP: cs->startTime = cs->earliestStart; cs->endTime = cs->earliestStart; break; case Node::ALAP: cs->startTime = cs->latestFinish; cs->endTime = cs->latestFinish; break; case Node::MustStartOn: case Node::FixedInterval: if (m_constraintStartTime < cs->earliestStart || m_constraintStartTime > cs->endTime) { cs->schedulingError = true; } cs->startTime = cs->earliestStart; cs->endTime = cs->earliestStart; break; case Node::MustFinishOn: if (m_constraintEndTime < cs->earliestStart || m_constraintEndTime > cs->endTime) { cs->schedulingError = true; } cs->startTime = cs->earliestStart; cs->endTime = cs->earliestStart; break; case Node::StartNotEarlier: if (m_constraintStartTime > cs->endTime) { cs->schedulingError = true; } cs->startTime = cs->endTime; break; case Node::FinishNotLater: if (m_constraintEndTime < cs->endTime) { cs->schedulingError = true; } cs->startTime = cs->endTime; break; default: break; } cs->duration = Duration::zeroDuration; } else if (type() == Node::Type_Summarytask) { //shouldn't come here cs->startTime = cs->endTime; cs->duration = cs->endTime - cs->startTime; kdWarning()<startTime.toString()<<" : "<endTime.toString()<startTime; } void Task::adjustSummarytask() { if (m_currentSchedule == 0) return; if (type() == Type_Summarytask) { DateTime start = m_currentSchedule->latestFinish; DateTime end = m_currentSchedule->earliestStart; QPtrListIterator it(m_nodes); for (; it.current(); ++it) { it.current()->adjustSummarytask(); if (it.current()->startTime() < start) start = it.current()->startTime(); if (it.current()->endTime() > end) end = it.current()->endTime(); } m_currentSchedule->startTime = start; m_currentSchedule->endTime = end; m_currentSchedule->duration = end - start; m_currentSchedule->notScheduled = false; //kdDebug()<name<<": "<startTime.toString()<<" : "<endTime.toString()< calcDuration "<<(backward?"(B) ":"(F) ")<resourceNotAvailable = true; dur = effort; //??? } return dur; } if (m_effort->type() == Effort::Type_FixedDuration) { //TODO: Different types of fixed duration return dur; // } kdError()<type()< &list) { //kdDebug()< nodes = m_nodes; for (; nodes.current(); ++nodes) { nodes.current()->addParentProxyRelations(list); nodes.current()->addParentProxyRelations(dependParentNodes()); } } else { // add 'this' as child relation to the relations parent //kdDebug()< it = list; for (; it.current(); ++it) { it.current()->parent()->addChildProxyRelation(this, it.current()); // add a parent relation to myself addParentProxyRelation(it.current()->parent(), it.current()); } } } void Task::addChildProxyRelations(QPtrList &list) { //kdDebug()< nodes = m_nodes; for (; nodes.current(); ++nodes) { nodes.current()->addChildProxyRelations(list); nodes.current()->addChildProxyRelations(dependChildNodes()); } } else { // add 'this' as parent relation to the relations child //kdDebug()< it = list; for (; it.current(); ++it) { it.current()->child()->addParentProxyRelation(this, it.current()); // add a child relation to myself addChildProxyRelation(it.current()->child(), it.current()); } } } void Task::addParentProxyRelation(Node *node, const Relation *rel) { if (node->type() != Type_Summarytask) { if (type() == Type_Summarytask) { //kdDebug()<<"Add parent proxy from my children "<name()< nodes = m_nodes; for (; nodes.current(); ++nodes) { nodes.current()->addParentProxyRelation(node, rel); } } else { //kdDebug()<<"Add parent proxy from "<name()<<" to (me) "<type(), rel->lag())); } } } void Task::addChildProxyRelation(Node *node, const Relation *rel) { if (node->type() != Type_Summarytask) { if (type() == Type_Summarytask) { //kdDebug()<<"Add child proxy from my children "<name()< nodes = m_nodes; for (; nodes.current(); ++nodes) { nodes.current()->addChildProxyRelation(node, rel); } } else { //kdDebug()<<"Add child proxy from (me) "<name()<type(), rel->lag())); } } } bool Task::isEndNode() const { QPtrListIterator it = m_dependChildNodes; for (; it.current(); ++it) { if (it.current()->type() == Relation::FinishStart) return false; } QPtrListIterator pit = m_childProxyRelations; for (; pit.current(); ++pit) { if (pit.current()->type() == Relation::FinishStart) return false; } return true; } bool Task::isStartNode() const { QPtrListIterator it = m_dependParentNodes; for (; it.current(); ++it) { if (it.current()->type() == Relation::FinishStart || it.current()->type() == Relation::StartStart) return false; } QPtrListIterator pit = m_parentProxyRelations; for (; pit.current(); ++pit) { if (pit.current()->type() == Relation::FinishStart || pit.current()->type() == Relation::StartStart) return false; } return true; } DateTime Task::workStartTime() const { if (m_currentSchedule == 0) return DateTime(); if (m_requests) return m_currentSchedule->workStartTime; return m_currentSchedule->startTime; } DateTime Task::workEndTime() const { if (m_currentSchedule == 0) return DateTime(); return m_currentSchedule->endTime; } DateTime Task::workStartAfter(const DateTime &dt) { if (m_requests) { DateTime t = m_requests->availableAfter(dt); return t.isValid() ? t : dt; } return dt; } DateTime Task::workFinishBefore(const DateTime &dt) { if (m_requests) { return m_requests->availableBefore(dt); } return dt; } Duration Task::positiveFloat() { if (m_currentSchedule == 0 || m_currentSchedule->schedulingError || effortMetError()) { return Duration::zeroDuration; } Duration f; if (type() == Node::Type_Milestone) { if (m_currentSchedule->startTime < m_currentSchedule->latestFinish) { f = m_currentSchedule->latestFinish - m_currentSchedule->startTime; } } else if (m_effort->type() == Effort::Type_FixedDuration) { if (m_currentSchedule->endTime.isValid()) { if (m_currentSchedule->endTime < m_currentSchedule->latestFinish) { f = m_currentSchedule->latestFinish - m_currentSchedule->endTime; } } } else { if (m_currentSchedule->workEndTime.isValid()) if (m_currentSchedule->workEndTime < m_currentSchedule->latestFinish) { f = m_currentSchedule->latestFinish - m_currentSchedule->workEndTime; } else if (m_currentSchedule->endTime.isValid()) { if (m_currentSchedule->endTime < m_currentSchedule->latestFinish) { f = m_currentSchedule->latestFinish - m_currentSchedule->endTime; } } } //kdDebug()<earliestStart >= cs->startTime && cs->latestFinish <= cs->endTime; } bool Task::calcCriticalPath(bool fromEnd) { if (m_currentSchedule == 0) return false; //kdDebug()< it(m_childProxyRelations); for (; it.current(); ++it) { if (it.current()->child()->calcCriticalPath(fromEnd)) { m_currentSchedule->inCriticalPath = true; } } QPtrListIterator pit(m_dependChildNodes); for (; pit.current(); ++pit) { if (pit.current()->child()->calcCriticalPath(fromEnd)) { m_currentSchedule->inCriticalPath = true; } } } else { if (isStartNode()) { m_currentSchedule->inCriticalPath = true; //kdDebug()< it(m_parentProxyRelations); for (; it.current(); ++it) { if (it.current()->parent()->calcCriticalPath(fromEnd)) { m_currentSchedule->inCriticalPath = true; } } QPtrListIterator pit(m_dependParentNodes); for (; pit.current(); ++pit) { if (pit.current()->parent()->calcCriticalPath(fromEnd)) { m_currentSchedule->inCriticalPath = true; } } } //kdDebug()<printDebug(indent); Node::printDebug(children, indent); } #endif } //KPlato namespace