diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kplato/kpttask.cc | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kplato/kpttask.cc')
-rw-r--r-- | kplato/kpttask.cc | 1542 |
1 files changed, 1542 insertions, 0 deletions
diff --git a/kplato/kpttask.cc b/kplato/kpttask.cc new file mode 100644 index 00000000..255bf948 --- /dev/null +++ b/kplato/kpttask.cc @@ -0,0 +1,1542 @@ +/* This file is part of the KDE project + Copyright (C) 2001 Thomas zander <zander@kde.org> + Copyright (C) 2004 Dag Andersen <danders@get2net.dk> + + 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 <qdom.h> +#include <qbrush.h> +#include <kdebug.h> + +namespace KPlato +{ + +Task::Task(Node *parent) : Node(parent), m_resource() { + //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl; + m_resource.setAutoDelete(true); + Duration d(1, 0, 0); + m_effort = new Effort(d); + m_effort->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()<<k_funcinfo<<"("<<this<<")"<<endl; + m_resource.setAutoDelete(true); + + m_parentProxyRelations.setAutoDelete(true); + m_childProxyRelations.setAutoDelete(true); + m_requests = 0; + + m_effort = task.effort() ? new Effort(*(task.effort())) + : new Effort(); // Avoid crash, (shouldn't be zero) +} + + +Task::~Task() { + delete m_effort; +} + +int Task::type() const { + if ( numChildren() > 0) { + return Node::Type_Summarytask; + } + else if ( 0 == effort()->expected().seconds() ) { + return Node::Type_Milestone; + } + else { + return Node::Type_Task; + } +} + + + +Duration *Task::getExpectedDuration() { + //kdDebug()<<k_funcinfo<<endl; + // Duration should already be calculated + return m_currentSchedule ? new Duration(m_currentSchedule->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()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl; + m_requests->makeAppointments(m_currentSchedule); + //kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->startTime<<", "<<m_currentSchedule->endTime<<"; "<<m_currentSchedule->duration.toString()<<endl; + } + } else if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> nit(m_nodes); + for ( ; nit.current(); ++nit ) { + nit.current()->makeAppointments(); + } + } else if (type() == Node::Type_Milestone) { + //kdDebug()<<k_funcinfo<<"Milestone not implemented"<<endl; + // Well, shouldn't have resources anyway... + } +} + +void Task::calcResourceOverbooked() { + if (m_currentSchedule) + m_currentSchedule->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()<<k_funcinfo<<m_name<<": id="<<m_id<<endl; + + // Allow for both numeric and text + QString constraint = element.attribute("scheduling","0"); + m_constraint = (Node::ConstraintType)constraint.toInt(&ok); + if (!ok) + Node::setConstraint(constraint); // hmmm, why do I need Node::? + + s = element.attribute("constraint-starttime"); + if (s != "") + m_constraintStartTime = DateTime::fromString(s); + s = element.attribute("constraint-endtime"); + if ( s != "") + m_constraintEndTime = DateTime::fromString(s); + + m_startupCost = element.attribute("startup-cost", "0.0").toDouble(); + m_shutdownCost = element.attribute("shutdown-cost", "0.0").toDouble(); + + m_wbs = element.attribute("wbs", ""); + + // Load the project children + QDomNodeList list = element.childNodes(); + for (unsigned int i=0; i<list.count(); ++i) { + if (list.item(i).isElement()) { + QDomElement e = list.item(i).toElement(); + + if (e.tagName() == "project") { + // Load the subproject + Project *child = new Project(this); + if (child->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()<<k_funcinfo<<"Failed to load resource request"<<endl; + delete r; + } + } else if (e.tagName() == "progress") { + m_progress.started = (bool)e.attribute("started", "0").toInt(); + m_progress.finished = (bool)e.attribute("finished", "0").toInt(); + + s = e.attribute("startTime"); + if (s != "") + m_progress.startTime = DateTime::fromString(s); + s = e.attribute("finishTime"); + if (s != "") + m_progress.finishTime = DateTime::fromString(s); + m_progress.percentFinished = e.attribute("percent-finished", "0").toInt(); + m_progress.remainingEffort = Duration::fromString(e.attribute("remaining-effort")); + m_progress.totalPerformed = Duration::fromString(e.attribute("performed-effort")); + } else if (e.tagName() == "schedules") { + QDomNodeList lst = e.childNodes(); + for (unsigned int i=0; i<lst.count(); ++i) { + if (lst.item(i).isElement()) { + QDomElement el = lst.item(i).toElement(); + if (el.tagName() == "schedule") { + NodeSchedule *sch = new NodeSchedule(); + if (sch->loadXML(el)) { + sch->setNode(this); + addSchedule(sch); + } else { + kdError()<<k_funcinfo<<"Failed to load schedule"<<endl; + delete sch; + } + } + } + } + } + } + } + //kdDebug()<<k_funcinfo<<m_name<<" loaded"<<endl; + return true; +} + + +void Task::save(QDomElement &element) const { + QDomElement me = element.ownerDocument().createElement("task"); + element.appendChild(me); + + //TODO: Handle different types of tasks, milestone, summary... + me.setAttribute("id", m_id); + me.setAttribute("name", m_name); + me.setAttribute("leader", m_leader); + me.setAttribute("description", m_description); + + me.setAttribute("scheduling",constraintToString()); + me.setAttribute("constraint-starttime",m_constraintStartTime.toString(Qt::ISODate)); + me.setAttribute("constraint-endtime",m_constraintEndTime.toString(Qt::ISODate)); + + me.setAttribute("startup-cost", m_startupCost); + me.setAttribute("shutdown-cost", m_shutdownCost); + + me.setAttribute("wbs", m_wbs); + + m_effort->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<Schedule> 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; i<numChildren(); i++) { + getChildNode(i)->save(me); + } +} + +void Task::saveAppointments(QDomElement &element, long id) const { + //kdDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl; + Schedule *sch = findSchedule(id); + if (sch) { + sch->saveAppointments(element); + } + QPtrListIterator<Node> it(m_nodes); + for (; it.current(); ++it ) { + it.current()->saveAppointments(element, id); + } +} + +EffortCostMap Task::plannedEffortCostPrDay(const QDate &start, const QDate &end) const { + //kdDebug()<<k_funcinfo<<m_name<<endl; + if (m_currentSchedule) { + return m_currentSchedule->plannedEffortCostPrDay(start, end); + } + return EffortCostMap(); +} + +// Returns the total planned effort for this task (or subtasks) +Duration Task::plannedEffort() { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->plannedEffort(); + } + } else if (m_currentSchedule) { + eff = m_currentSchedule->plannedEffort(); + } + return eff; +} + +// Returns the total planned effort for this task (or subtasks) on date +Duration Task::plannedEffort(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->plannedEffort(date); + } + } else if (m_currentSchedule) { + eff = m_currentSchedule->plannedEffort(date); + } + return eff; +} + +// Returns the total planned effort for this task (or subtasks) upto and including date +Duration Task::plannedEffortTo(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->plannedEffortTo(date); + } + } else if (m_currentSchedule) { + eff = m_currentSchedule->plannedEffortTo(date); + } + return eff; +} + +// Returns the total planned effort for this task (or subtasks) +Duration Task::actualEffort() { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->actualEffort(); + } + } else { + eff = m_progress.totalPerformed; + } + /* If we want to register pr resource... + } else if (m_currentSchedule) { + eff = m_currentSchedule->actualEffort(); + }*/ + return eff; +} + +// Returns the total planned effort for this task (or subtasks) on date +Duration Task::actualEffort(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->actualEffort(date); + } + } else if (m_currentSchedule) { + eff = m_currentSchedule->actualEffort(date); + } + return eff; +} + +// Returns the total planned effort for this task (or subtasks) on date +Duration Task::actualEffortTo(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + Duration eff; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + eff += it.current()->actualEffortTo(date); + } + } else if (m_currentSchedule) { + eff = m_currentSchedule->actualEffortTo(date); + } + return eff; +} + +double Task::plannedCost() { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->plannedCost(); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->plannedCost(); + } + return c; +} + +double Task::plannedCost(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->plannedCost(date); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->plannedCost(date); + } + return c; +} + +double Task::plannedCostTo(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->plannedCostTo(date); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->plannedCostTo(date); + } + return c; +} + +double Task::actualCost() { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->actualCost(); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->actualCost(); + } + return c; +} + +double Task::actualCost(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->actualCost(date); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->actualCost(date); + } + return c; +} + +double Task::actualCostTo(const QDate &date) { + //kdDebug()<<k_funcinfo<<endl; + double c = 0; + if (type() == Node::Type_Summarytask) { + QPtrListIterator<Node> it(childNodeIterator()); + for (; it.current(); ++it) { + c += it.current()->actualCostTo(date); + } + } else if (m_currentSchedule) { + c = m_currentSchedule->actualCostTo(date); + } + return c; +} + +//FIXME Handle summarytasks +double Task::effortPerformanceIndex(const QDate &date, bool *error) { + double res = 0.0; + Duration ae = actualEffortTo(date); + + bool e = (ae == Duration::zeroDuration || m_progress.percentFinished == 0); + if (error) { + *error = e; + } + if (!e) { + res = (plannedEffortTo(date).toDouble() * ((double)m_progress.percentFinished/100.0) / ae.toDouble()); + } + return res; +} + +//FIXME Handle summarytasks +double Task::costPerformanceIndex(const QDate &date, bool *error) { + double res = 0.0; + Duration ac = Q_INT64(actualCostTo(date)); + + bool e = (ac == Duration::zeroDuration || m_progress.percentFinished == 0); + if (error) { + *error = e; + } + if (!e) { + res = (plannedCostTo(date) * m_progress.percentFinished)/(100 * actualCostTo(date)); + } + return res; +} + +void Task::initiateCalculation(Schedule &sch) { + //kdDebug()<<k_funcinfo<<m_name<<" schedule: "<<(sch?sch->name():"None")<<" id="<<(sch?sch->id():-1)<<endl; + m_visitedForward = false; + m_visitedBackward = false; + m_currentSchedule = createSchedule(&sch); + m_currentSchedule->initiateCalculation(); + clearProxyRelations(); + Node::initiateCalculation(sch); +} + + +void Task::initiateCalculationLists(QPtrList<Node> &startnodes, QPtrList<Node> &endnodes, QPtrList<Node> &summarytasks/*, QPtrList<Node> &milestones*/) { + //kdDebug()<<k_funcinfo<<m_name<<endl; + if (type() == Node::Type_Summarytask) { + summarytasks.append(this); + // propagate my relations to my children and dependent nodes + + QPtrListIterator<Node> 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()<<k_funcinfo<<"endnodes append: "<<m_name<<endl; + } + if (isStartNode()) { + startnodes.append(this); + //kdDebug()<<k_funcinfo<<"startnodes append: "<<m_name<<endl; + } + } +} + +DateTime Task::calculatePredeccessors(const QPtrList<Relation> &list, int use) { + DateTime time; + QPtrListIterator<Relation> it = list; + for (; it.current(); ++it) { + if (it.current()->parent()->type() == Type_Summarytask) { + //kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl; + continue; // skip summarytasks + } + DateTime t = it.current()->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()<<time.toString()<<" "<<m_name<<" calculatePredeccessors() ("<<list.count()<<")"<<endl; + return time; +} +DateTime Task::calculateForward(int use) { + //kdDebug()<<k_funcinfo<<m_name<<<<endl; + if (m_currentSchedule == 0) { + return DateTime(); + } + Schedule *cs = m_currentSchedule; + if (m_visitedForward) { + //kdDebug()<<earliestStart.toString()<<" + "<<m_durationBackward.toString()<<" "<<m_name<<" calculateForward() (visited)"<<endl; + return cs->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()<<k_funcinfo<<m_name<<": "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<endl; + break; + case Node::MustFinishOn: + m_durationForward = duration(m_constraintEndTime, use, true); + cs->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()<<k_funcinfo<<m_name<<" "<<earliestStart.toString()<<endl + } else if (type() == Node::Type_Summarytask) { + kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl; + } else { // ??? + m_durationForward = Duration::zeroDuration; + } + + //kdDebug()<<"Earlyfinish: "<<cs->earliestStart<<"+"<<m_durationForward.toString()<<"="<<(cs->earliestStart+m_durationForward)<<" "<<m_name<<" calculateForward()"<<endl; + m_visitedForward = true; + return cs->earliestStart + m_durationForward; +} + +DateTime Task::calculateSuccessors(const QPtrList<Relation> &list, int use) { + DateTime time; + QPtrListIterator<Relation> it = list; + for (; it.current(); ++it) { + if (it.current()->child()->type() == Type_Summarytask) { + //kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl; + continue; // skip summarytasks + } + DateTime t = it.current()->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()<<time.toString()<<" "<<m_name<<" calculateSuccessors() ("<<list.count()<<")"<<endl; + return time; +} +DateTime Task::calculateBackward(int use) { + //kdDebug()<<k_funcinfo<<m_name<<endl; + if (m_currentSchedule == 0) { + return DateTime(); + } + Schedule *cs = m_currentSchedule; + if (m_visitedBackward) { + //kdDebug()<<latestFinish.toString()<<" - "<<m_durationBackward.toString()<<" "<<m_name<<" calculateBackward() (visited)"<<endl; + return cs->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()<<k_funcinfo<<m_name<<": latestFinish="<<cs->latestFinish<<endl; + if (type() == Node::Type_Task) { + m_durationBackward = m_effort->effort(use); + switch (constraint()) { + case Node::ASAP: + case Node::ALAP: + cs->latestFinish = workFinishBefore(cs->latestFinish); + m_durationBackward = duration(cs->latestFinish, use, true); + break; + case Node::MustStartOn: + m_durationBackward = duration(m_constraintStartTime, use, false); + cs->latestFinish = m_constraintStartTime + m_durationBackward; + break; + case Node::StartNotEarlier: + m_durationBackward = duration(cs->latestFinish, use, true); + if (cs->latestFinish - m_durationBackward < m_constraintStartTime) { + m_durationBackward = duration(m_constraintStartTime, use, false); + cs->latestFinish = m_constraintStartTime + m_durationBackward; + } + break; + case Node::MustFinishOn: + cs->latestFinish = m_constraintEndTime; + m_durationBackward = duration(cs->latestFinish, use, true); + break; + case Node::FinishNotLater: + if (cs->latestFinish > m_constraintEndTime) { + cs->latestFinish = m_constraintEndTime; + } + m_durationBackward = duration(cs->latestFinish, use, true); + break; + case Node::FixedInterval: { + cs->latestFinish = m_constraintEndTime; + m_durationBackward = m_constraintEndTime - m_constraintStartTime; + break; + } + } + } else if (type() == Node::Type_Milestone) { + m_durationBackward = Duration::zeroDuration; + switch (constraint()) { + case Node::MustFinishOn: + cs->latestFinish = m_constraintEndTime; + break; + case Node::FinishNotLater: + if (cs->latestFinish > m_constraintEndTime) { + cs->latestFinish = m_constraintEndTime; + } + break; + case Node::MustStartOn: + cs->latestFinish = m_constraintStartTime; + break; + case Node::StartNotEarlier: + if (cs->latestFinish < m_constraintStartTime) { + cs->latestFinish = m_constraintStartTime; + } + break; + case Node::FixedInterval: + cs->latestFinish = m_constraintEndTime; + break; + default: + break; + } + //kdDebug()<<k_funcinfo<<m_name<<" "<<cs->latestFinish<<endl; + } else if (type() == Node::Type_Summarytask) { + kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl; + } else { // ??? + m_durationBackward = Duration::zeroDuration; + } + //kdDebug()<<"Latestart: "<<cs->latestFinish<<"-"<<m_durationBackward.toString()<<"="<<(cs->latestFinish-m_durationBackward).toString()<<" "<<m_name<<" calculateBackward()"<<endl; + m_visitedBackward = true; + return cs->latestFinish - m_durationBackward; +} + +DateTime Task::schedulePredeccessors(const QPtrList<Relation> &list, int use) { + DateTime time; + QPtrListIterator<Relation> it = list; + for (; it.current(); ++it) { + if (it.current()->parent()->type() == Type_Summarytask) { + //kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->parent()->name()<<endl; + continue; // skip summarytasks + } + // schedule the predecessors + DateTime earliest = it.current()->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()<<time.toString()<<" "<<m_name<<" schedulePredeccessors()"<<endl; + return time; +} + +DateTime Task::scheduleForward(const DateTime &earliest, int use) { + //kdDebug()<<k_funcinfo<<m_name<<" earliest="<<earliest<<endl; + if (m_currentSchedule == 0) { + return DateTime(); + } + Schedule *cs = m_currentSchedule; + if (m_visitedForward) { + return cs->endTime; + } + cs->notScheduled = false; + cs->startTime = earliest > cs->earliestStart ? earliest : cs->earliestStart; + // First, calculate all my own predecessors + DateTime time = schedulePredeccessors(dependParentNodes(), use); + if (time.isValid() && time > cs->startTime) { + cs->startTime = time; + //kdDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl; + } + // Then my parents + time = schedulePredeccessors(m_parentProxyRelations, use); + if (time.isValid() && time > cs->startTime) { + cs->startTime = time; + //kdDebug()<<k_funcinfo<<m_name<<" new startime="<<cs->startTime<<endl; + } + //kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl; + if(type() == Node::Type_Task) { + cs->duration = m_effort->effort(use); + switch (m_constraint) { + case Node::ASAP: + // cs->startTime calculated above + //kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl; + cs->startTime = workStartAfter(cs->startTime); + cs->duration = duration(cs->startTime, use, false); + cs->endTime = cs->startTime + cs->duration; + //kdDebug()<<k_funcinfo<<m_name<<" startTime="<<cs->startTime<<endl; + break; + case Node::ALAP: + // cd->startTime calculated above + cs->duration = duration(cs->latestFinish, use, true); + cs->endTime = cs->latestFinish; + cs->startTime = cs->endTime - cs->duration; + //kdDebug()<<k_funcinfo<<m_name<<" endTime="<<cs->endTime<<" latest="<<cs->latestFinish<<endl; + break; + case Node::StartNotEarlier: + // cs->startTime calculated above + //kdDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cd->startTime.toString()<<endl; + if (cs->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="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl; + cs->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="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl; + if (m_constraintStartTime < cs->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="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl; + if (m_constraintEndTime > 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="<<m_constraintStartTime<<" "<<cs->startTime<<endl; + if (cs->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="<<cs->startTime<<", "<<cs->endTime<<endl; + 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->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: "<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl; + if (m_constraintStartTime < cs->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()<<k_funcinfo<<m_name<<": "<<cs->startTime<<", "<<cs->endTime<<endl; + } else if (type() == Node::Type_Summarytask) { + //shouldn't come here + cs->endTime = cs->startTime; + cs->duration = cs->endTime - cs->startTime; + kdWarning()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl; + } + //kdDebug()<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<" "<<m_name<<" scheduleForward()"<<endl; + m_visitedForward = true; + return cs->endTime; +} + +DateTime Task::scheduleSuccessors(const QPtrList<Relation> &list, int use) { + DateTime time; + QPtrListIterator<Relation> it = list; + for (; it.current(); ++it) { + if (it.current()->child()->type() == Type_Summarytask) { + //kdDebug()<<k_funcinfo<<"Skip summarytask: "<<it.current()->child()->name()<<endl; + continue; + } + // get the successors starttime + DateTime latest = it.current()->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()<<k_funcinfo<<m_name<<": latest="<<latest<<endl; + if (m_currentSchedule == 0) { + return DateTime(); + } + Schedule *cs = m_currentSchedule; + if (m_visitedBackward) { + return cs->startTime; + } + cs->notScheduled = false; + cs->endTime = latest < cs->latestFinish ? latest : cs->latestFinish; + // First, calculate all my own successors + DateTime time = scheduleSuccessors(dependChildNodes(), use); + if (time.isValid() && time < cs->endTime) { + cs->endTime = time; + } + // Then my parents + time = scheduleSuccessors(m_childProxyRelations, use); + if (time.isValid() && time < cs->endTime) { + cs->endTime = time; + } + if (type() == Node::Type_Task) { + cs->duration = m_effort->effort(use); + switch (m_constraint) { + case Node::ASAP: { + // cs->endTime calculated above + //kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" early="<<cs->earliestStart<<endl; + cs->endTime = workFinishBefore(cs->endTime); + cs->duration = duration(cs->earliestStart, use, false); + cs->startTime = cs->earliestStart; + DateTime e = cs->startTime + cs->duration; + if (e > cs->endTime) { + cs->schedulingError = true; + } + cs->endTime = e; + //kdDebug()<<k_funcinfo<<m_name<<": start="<<cs->startTime<<"+"<<cs->duration.toString()<<"="<<e<<" -> end="<<cs->endTime<<endl; + break; + } + case Node::ALAP: + // cs->endTime calculated above + //kdDebug()<<k_funcinfo<<m_name<<": end="<<cs->endTime<<" late="<<cs->latestFinish<<endl; + cs->endTime = workFinishBefore(cs->endTime); + cs->duration = duration(cs->endTime, use, true); + cs->startTime = cs->endTime - cs->duration; + //kdDebug()<<k_funcinfo<<m_name<<": lateStart="<<cs->startTime<<endl; + break; + case Node::StartNotEarlier: + // cs->endTime calculated above + //kdDebug()<<"StartNotEarlier="<<m_constraintStartTime.toString()<<" "<<cs->endTime.toString()<<endl; + cs->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="<<m_constraintEndTime.toString()<<" "<<cs->endTime.toString()<<endl; + if (cs->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="<<m_constraintStartTime.toString()<<" "<<cs->startTime.toString()<<endl; + if (m_constraintStartTime < cs->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="<<m_constraintEndTime.toString()<<" "<<cs->startTime.toString()<<endl; + if (m_constraintEndTime > 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()<<k_funcinfo<<"FixedInterval="<<m_constraintEndTime<<" "<<cs->endTime<<endl; + if (m_constraintEndTime > cs->endTime) { + cs->schedulingError = true; + //kdDebug()<<k_funcinfo<<"FixedInterval error: "<<m_constraintEndTime<<" > "<<cs->endTime<<endl; + } + cs->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()<<k_funcinfo<<"Summarytasks should not be calculated here: "<<m_name<<endl; + } + //kdDebug()<<k_funcinfo<<m_name<<": "<<cs->startTime.toString()<<" : "<<cs->endTime.toString()<<endl; + m_visitedBackward = true; + return cs->startTime; +} + +void Task::adjustSummarytask() { + if (m_currentSchedule == 0) + return; + if (type() == Type_Summarytask) { + DateTime start = m_currentSchedule->latestFinish; + DateTime end = m_currentSchedule->earliestStart; + QPtrListIterator<Node> 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()<<k_funcinfo<<cs->name<<": "<<m_currentSchedule->startTime.toString()<<" : "<<m_currentSchedule->endTime.toString()<<endl; + } +} + +Duration Task::calcDuration(const DateTime &time, const Duration &effort, bool backward) { + //kdDebug()<<"--------> calcDuration "<<(backward?"(B) ":"(F) ")<<m_name<<" time="<<time<<" effort="<<effort.toString(Duration::Format_Day)<<endl; + + // Allready checked: m_effort, m_currentSchedule and time. + Duration dur = effort; // use effort as default duration + if (m_effort->type() == Effort::Type_Effort) { + if (m_requests == 0 || m_requests->isEmpty()) { + m_currentSchedule->resourceError = true; + return effort; + } + dur = m_requests->duration(time, effort, backward); + if (dur == Duration::zeroDuration) { + kdWarning()<<k_funcinfo<<"zero duration: Resource not available"<<endl; + m_currentSchedule->resourceNotAvailable = true; + dur = effort; //??? + } + return dur; + } + if (m_effort->type() == Effort::Type_FixedDuration) { + //TODO: Different types of fixed duration + return dur; // + } + kdError()<<k_funcinfo<<"Unsupported effort type: "<<m_effort->type()<<endl; + return dur; +} + +void Task::clearProxyRelations() { + m_parentProxyRelations.clear(); + m_childProxyRelations.clear(); +} + +void Task::addParentProxyRelations(QPtrList<Relation> &list) { + //kdDebug()<<k_funcinfo<<m_name<<endl; + if (type() == Type_Summarytask) { + // propagate to my children + //kdDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl; + QPtrListIterator<Node> 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()<<k_funcinfo<<m_name<<" is not summary task"<<endl; + QPtrListIterator<Relation> 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<Relation> &list) { + //kdDebug()<<k_funcinfo<<m_name<<endl; + if (type() == Type_Summarytask) { + // propagate to my children + //kdDebug()<<k_funcinfo<<m_name<<" is summary task"<<endl; + QPtrListIterator<Node> 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()<<k_funcinfo<<m_name<<" is not summary task"<<endl; + QPtrListIterator<Relation> 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 "<<m_name<<" to "<<node->name()<<endl; + QPtrListIterator<Node> nodes = m_nodes; + for (; nodes.current(); ++nodes) { + nodes.current()->addParentProxyRelation(node, rel); + } + } else { + //kdDebug()<<"Add parent proxy from "<<node->name()<<" to (me) "<<m_name<<endl; + m_parentProxyRelations.append(new ProxyRelation(node, this, rel->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 "<<m_name<<" to "<<node->name()<<endl; + QPtrListIterator<Node> nodes = m_nodes; + for (; nodes.current(); ++nodes) { + nodes.current()->addChildProxyRelation(node, rel); + } + } else { + //kdDebug()<<"Add child proxy from (me) "<<m_name<<" to "<<node->name()<<endl; + m_childProxyRelations.append(new ProxyRelation(this, node, rel->type(), rel->lag())); + } + } +} + +bool Task::isEndNode() const { + QPtrListIterator<Relation> it = m_dependChildNodes; + for (; it.current(); ++it) { + if (it.current()->type() == Relation::FinishStart) + return false; + } + QPtrListIterator<Relation> pit = m_childProxyRelations; + for (; pit.current(); ++pit) { + if (pit.current()->type() == Relation::FinishStart) + return false; + } + return true; +} +bool Task::isStartNode() const { + QPtrListIterator<Relation> it = m_dependParentNodes; + for (; it.current(); ++it) { + if (it.current()->type() == Relation::FinishStart || + it.current()->type() == Relation::StartStart) + return false; + } + QPtrListIterator<Relation> 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()<<k_funcinfo<<f.toString()<<endl; + return f; +} + +bool Task::isCritical() { + Schedule *cs = m_currentSchedule; + if (cs == 0) { + return false; + } + return cs->earliestStart >= cs->startTime && cs->latestFinish <= cs->endTime; +} + +bool Task::calcCriticalPath(bool fromEnd) { + if (m_currentSchedule == 0) + return false; + //kdDebug()<<k_funcinfo<<m_name<<" fromEnd="<<fromEnd<<" cp="<<m_currentSchedule->inCriticalPath<<endl; + if (m_currentSchedule->inCriticalPath) { + return true; // path allready calculated + } + if (!isCritical()) { + return false; + } + if (fromEnd) { + if (isEndNode()) { + m_currentSchedule->inCriticalPath = true; + //kdDebug()<<k_funcinfo<<m_name<<" end node"<<endl; + return true; + } + QPtrListIterator<Relation> it(m_childProxyRelations); + for (; it.current(); ++it) { + if (it.current()->child()->calcCriticalPath(fromEnd)) { + m_currentSchedule->inCriticalPath = true; + } + } + QPtrListIterator<Relation> 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()<<k_funcinfo<<m_name<<" start node"<<endl; + return true; + } + QPtrListIterator<Relation> it(m_parentProxyRelations); + for (; it.current(); ++it) { + if (it.current()->parent()->calcCriticalPath(fromEnd)) { + m_currentSchedule->inCriticalPath = true; + } + } + QPtrListIterator<Relation> pit(m_dependParentNodes); + for (; pit.current(); ++pit) { + if (pit.current()->parent()->calcCriticalPath(fromEnd)) { + m_currentSchedule->inCriticalPath = true; + } + } + } + //kdDebug()<<k_funcinfo<<m_name<<" return cp="<<m_currentSchedule->inCriticalPath<<endl; + return m_currentSchedule->inCriticalPath; +} + +void Task::setCurrentSchedule(long id) { + setCurrentSchedulePtr(findSchedule(id)); + Node::setCurrentSchedule(id); +} + +bool Task::effortMetError() const { + if (m_currentSchedule->notScheduled) { + return false; + } + return m_currentSchedule->plannedEffort() < effort()->effort(static_cast<Effort::Use>(static_cast<int>(m_currentSchedule->type()))); +} + +#ifndef NDEBUG +void Task::printDebug(bool children, QCString indent) { + kdDebug()<<indent<<"+ Task node: "<<name()<<" type="<<type()<<endl; + indent += "! "; + kdDebug()<<indent<<"Requested resources (total): "<<units()<<"%"<<endl; + kdDebug()<<indent<<"Requested resources (work): "<<workUnits()<<"%"<<endl; + if (m_requests) + m_requests->printDebug(indent); + + Node::printDebug(children, indent); + +} + +#endif + +} //KPlato namespace |