kplato

kptnode.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Thomas zander <zander@kde.org>
00003    Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 #include "kptnode.h"
00021 
00022 #include "kptappointment.h"
00023 #include "kptaccount.h"
00024 #include "kptwbsdefinition.h"
00025 #include "kptresource.h"
00026 #include "kptschedule.h"
00027 
00028 #include <qptrlist.h>
00029 #include <qdom.h>
00030 
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033 
00034 namespace KPlato
00035 {
00036 
00037 Node::Node(Node *parent) : m_nodes(), m_dependChildNodes(), m_dependParentNodes() {
00038     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00039     m_parent = parent;
00040     init();
00041     m_id = QString(); // Not mapped
00042 }
00043 
00044 Node::Node(Node &node, Node *parent) 
00045     : m_nodes(), 
00046       m_dependChildNodes(), 
00047       m_dependParentNodes() {
00048     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00049     m_parent = parent;
00050     init();
00051     m_name = node.name();
00052     m_leader = node.leader();
00053     m_description = node.description();
00054     m_constraint = (ConstraintType) node.constraint();
00055     m_constraintStartTime = node.constraintStartTime();
00056     m_constraintEndTime = node.constraintEndTime();
00057     
00058     m_dateOnlyStartDate = node.startDate();
00059     m_dateOnlyEndDate = node.endDate();
00060     
00061     m_runningAccount = node.runningAccount();
00062     m_startupAccount = node.startupAccount();
00063     m_shutdownAccount = node.shutdownAccount();
00064 
00065     m_startupCost = node.startupCost();
00066     m_shutdownCost = node.shutdownCost();
00067     
00068     m_schedules.setAutoDelete(node.m_schedules.autoDelete());
00069 }
00070 
00071 Node::~Node() {
00072     if (findNode() == this) {
00073         removeId(); // only remove myself (I may be just a working copy)
00074     }
00075     Relation *rel = 0;
00076     while ((rel = m_dependParentNodes.getFirst())) {
00077         delete rel;
00078     }
00079     while ((rel = m_dependChildNodes.getFirst())) {
00080         delete rel;
00081     }
00082     if (m_runningAccount)
00083         m_runningAccount->removeRunning(*this);
00084     if (m_startupAccount)
00085         m_startupAccount->removeStartup(*this);
00086     if (m_shutdownAccount)
00087         m_shutdownAccount->removeShutdown(*this);
00088 }
00089 
00090 void Node::init() {
00091     m_currentSchedule = 0;
00092     m_nodes.setAutoDelete(true);
00093     m_name="";
00094     m_constraint = Node::ASAP;
00095     m_effort = 0;
00096     m_visitedForward = false;
00097     m_visitedBackward = false;
00098     
00099     m_dateOnlyStartDate = m_dateOnlyEndDate = QDate::currentDate();
00100     m_dateOnlyDuration.addDays(1);
00101     
00102     m_runningAccount = 0;
00103     m_startupAccount = 0;
00104     m_shutdownAccount = 0;
00105     m_startupCost = 0.0;
00106     m_shutdownCost = 0.0;
00107 }
00108 
00109 Node *Node::projectNode() {
00110     if ((type() == Type_Project) || (type() == Type_Subproject)) {
00111         return this;
00112     }
00113     if (m_parent)
00114         return m_parent->projectNode();
00115 
00116     kdError()<<k_funcinfo<<"Ooops, no parent and no project found"<<endl;
00117     return 0;
00118 }
00119 
00120 void Node::delChildNode( Node *node, bool remove) {
00121     //kdDebug()<<k_funcinfo<<"find="<<m_nodes.findRef(node)<<endl;
00122     if ( m_nodes.findRef(node) != -1 ) {
00123         if(remove)
00124             m_nodes.remove();
00125         else
00126             m_nodes.take();
00127     }
00128     node->setParent(0);
00129 }
00130 
00131 void Node::delChildNode( int number, bool remove) {
00132     Node *n = m_nodes.at(number);
00133     //kdDebug()<<k_funcinfo<<(n?n->id():"null")<<" : "<<(n?n->name():"")<<endl;
00134     if(remove)
00135         m_nodes.remove(number);
00136     else
00137         m_nodes.take(number);
00138     
00139     if (n) {
00140         n->setParent(0);
00141     }
00142 }
00143 
00144 void Node::insertChildNode( unsigned int index, Node *node) {
00145     //kdDebug()<<k_funcinfo<<"insert id="<<node->id()<<": "<<node->name()<<endl;
00146     m_nodes.insert(index,node);
00147     node->setParent(this);
00148 }
00149 
00150 void Node::addChildNode( Node *node, Node *after) {
00151     //kdDebug()<<k_funcinfo<<endl;
00152     int index = m_nodes.findRef(after);
00153     if (index == -1) {
00154         //kdDebug()<<k_funcinfo<<"append id="<<node->id()<<": "<<node->name()<<endl;
00155         m_nodes.append(node);
00156         node->setParent(this);
00157         return;
00158     }
00159     //kdDebug()<<k_funcinfo<<"insert id="<<node->id()<<": "<<node->name()<<endl;
00160     m_nodes.insert(index+1, node);
00161     node->setParent(this);
00162 }
00163 
00164 int Node::findChildNode( Node* node )
00165 {
00166     return m_nodes.findRef( node );
00167 }
00168 
00169 
00170 const Node* Node::getChildNode(int number) const {
00171     // Work around missing const at() method in QPtrList
00172     const QPtrList<Node> &nodes = m_nodes;
00173     return (const_cast<QPtrList<Node> &>(nodes)).at(number);
00174 }
00175 
00176 Duration *Node::getDelay() {
00177     /* TODO
00178        Calculate the delay of this node. Use the calculated startTime and the setted startTime.
00179     */
00180     return 0L;
00181 }
00182 
00183 void Node::addDependChildNode( Node *node, Relation::Type p) {
00184     addDependChildNode(node,p,Duration());
00185 }
00186 
00187 void Node::addDependChildNode( Node *node, Relation::Type p, Duration lag) {
00188     Relation *relation = new Relation(this, node, p, lag);
00189     if (node->addDependParentNode(relation))
00190         m_dependChildNodes.append(relation);
00191     else
00192         delete relation;
00193 }
00194 
00195 void Node::insertDependChildNode( unsigned int index, Node *node, Relation::Type p) {
00196     Relation *relation = new Relation(this, node, p, Duration());
00197     if (node->addDependParentNode(relation))
00198         m_dependChildNodes.insert(index, relation);
00199     else
00200         delete relation;
00201 }
00202 
00203 bool Node::addDependChildNode( Relation *relation) {
00204     if(m_dependChildNodes.findRef(relation) != -1)
00205         return false;
00206     m_dependChildNodes.append(relation);
00207     return true;
00208 }
00209 
00210 // These delDepend... methods look suspicious to me, can someone review?
00211 void Node::delDependChildNode( Node *node, bool remove) {
00212     if ( m_nodes.findRef(node) != -1 ) {
00213         if(remove)
00214             m_dependChildNodes.remove();
00215         else
00216             m_dependChildNodes.take();
00217     }
00218 }
00219 
00220 void Node::delDependChildNode( Relation *rel, bool remove) {
00221     if ( m_dependChildNodes.findRef(rel) != -1 ) {
00222         if(remove)
00223             m_dependChildNodes.remove();
00224         else
00225             m_dependChildNodes.take();
00226     }
00227 }
00228 
00229 void Node::delDependChildNode( int number, bool remove) {
00230     if(remove)
00231         m_dependChildNodes.remove(number);
00232     else
00233         m_dependChildNodes.take(number);
00234 }
00235 
00236 void Node::takeDependChildNode(Relation *rel) {
00237     if (m_dependChildNodes.findRef(rel) != -1) {
00238         m_dependChildNodes.take();
00239     }
00240 }
00241 
00242 void Node::addDependParentNode( Node *node, Relation::Type p) {
00243     addDependParentNode(node,p,Duration());
00244 }
00245 
00246 void Node::addDependParentNode( Node *node, Relation::Type p, Duration lag) {
00247     Relation *relation = new Relation(node, this, p, lag);
00248     if (node->addDependChildNode(relation))
00249         m_dependParentNodes.append(relation);
00250     else
00251         delete relation;
00252 }
00253 
00254 void Node::insertDependParentNode( unsigned int index, Node *node, Relation::Type p) {
00255     Relation *relation = new Relation(this, node, p, Duration());
00256     if (node->addDependChildNode(relation))
00257         m_dependParentNodes.insert(index,relation);
00258     else
00259         delete relation;
00260 }
00261 
00262 bool Node::addDependParentNode( Relation *relation) {
00263     if(m_dependParentNodes.findRef(relation) != -1)
00264         return false;
00265     m_dependParentNodes.append(relation);
00266     return true;
00267 }
00268 
00269 // These delDepend... methods look suspicious to me, can someone review?
00270 void Node::delDependParentNode( Node *node, bool remove) {
00271     if ( m_nodes.findRef(node) != -1 ) {
00272         if(remove)
00273             m_dependParentNodes.remove();
00274         else
00275             m_dependParentNodes.take();
00276     }
00277 }
00278 
00279 void Node::delDependParentNode( Relation *rel, bool remove) {
00280     if ( m_dependParentNodes.findRef(rel) != -1 ) {
00281         if(remove)
00282             m_dependParentNodes.remove();
00283         else
00284             m_dependParentNodes.take();
00285     }
00286 }
00287 
00288 void Node::delDependParentNode( int number, bool remove) {
00289     if(remove)
00290         m_dependParentNodes.remove(number);
00291     else
00292         m_dependParentNodes.take(number);
00293 }
00294 
00295 void Node::takeDependParentNode(Relation *rel) {
00296     if (m_dependParentNodes.findRef(rel) != -1) {
00297         rel = m_dependParentNodes.take();
00298     }      
00299 }
00300 
00301 bool Node::isParentOf(Node *node) {
00302     if (m_nodes.findRef(node) != -1)
00303         return true;
00304 
00305     QPtrListIterator<Node> nit(childNodeIterator());
00306     for ( ; nit.current(); ++nit ) {
00307         if (nit.current()->isParentOf(node))
00308             return true;
00309     }
00310     return false;
00311 }
00312 
00313 Relation *Node::findParentRelation(Node *node) {
00314     for (int i=0; i<numDependParentNodes(); i++) {
00315         Relation *rel = getDependParentNode(i);
00316         if (rel->parent() == node)
00317             return rel;
00318     }
00319     return (Relation *)0;
00320 }
00321 
00322 Relation *Node::findChildRelation(Node *node) {
00323     for (int i=0; i<numDependChildNodes(); i++) {
00324         Relation *rel = getDependChildNode(i);
00325         if (rel->child() == node)
00326             return rel;
00327     }
00328     return (Relation *)0;
00329 }
00330 
00331 Relation *Node::findRelation(Node *node) {
00332     Relation *rel = findParentRelation(node);
00333     if (!rel)
00334         rel = findChildRelation(node);
00335     return rel;
00336 }
00337 
00338 bool Node::isDependChildOf(Node *node) {
00339     //kdDebug()<<k_funcinfo<<" '"<<m_name<<"' checking against '"<<node->name()<<"'"<<endl;
00340     for (int i=0; i<numDependParentNodes(); i++) {
00341         Relation *rel = getDependParentNode(i);
00342         if (rel->parent() == node)
00343             return true;
00344         if (rel->parent()->isDependChildOf(node))
00345             return true;
00346     }
00347     return false;
00348 }
00349 
00350 Duration Node::duration(const DateTime &time, int use, bool backward) {
00351     //kdDebug()<<k_funcinfo<<endl;
00352     // TODO: handle risc
00353     if (!time.isValid()) {
00354         kdError()<<k_funcinfo<<"Time is invalid"<<endl;
00355         return Duration::zeroDuration;
00356     }
00357     if (m_effort == 0) {
00358         kdError()<<k_funcinfo<<"m_effort == 0"<<endl;
00359         return Duration::zeroDuration;
00360     }
00361     if (m_currentSchedule == 0) {
00362         return Duration::zeroDuration;
00363         kdError()<<k_funcinfo<<"No current schedule"<<endl;
00364     }
00365     kdDebug()<<k_funcinfo<<m_name<<": Use="<<use<<endl;
00366     return calcDuration(time, m_effort->effort(use), backward);
00367 }
00368 
00369 void Node::makeAppointments() {
00370     QPtrListIterator<Node> nit(m_nodes);
00371     for ( ; nit.current(); ++nit ) {
00372         nit.current()->makeAppointments();
00373     }
00374 }
00375 
00376 void Node::calcResourceOverbooked() {
00377     QPtrListIterator<Node> nit(m_nodes);
00378     for ( ; nit.current(); ++nit ) {
00379         nit.current()->calcResourceOverbooked();
00380     }
00381 }
00382 
00383 QStringList Node::overbookedResources() const {
00384     return m_currentSchedule ? m_currentSchedule->overbookedResources() : QStringList();
00385 }
00386 
00387 void Node::saveRelations(QDomElement &element) const {
00388     QPtrListIterator<Relation> it(m_dependChildNodes);
00389     for (; it.current(); ++it) {
00390         it.current()->save(element);
00391     }
00392     QPtrListIterator<Node> nodes(m_nodes);
00393     for ( ; nodes.current(); ++nodes ) {
00394         nodes.current()->saveRelations(element);
00395     }
00396 }
00397 
00398 void Node::setConstraint(QString &type) {
00399     // Do not i18n these, they are used in load()
00400     if (type == "ASAP")
00401         setConstraint(ASAP);
00402     else if (type == "ALAP")
00403         setConstraint(ALAP);
00404     else if (type == "StartNotEarlier")
00405         setConstraint(StartNotEarlier);
00406     else if (type == "FinishNotLater")
00407         setConstraint(FinishNotLater);
00408     else if (type == "MustStartOn")
00409         setConstraint(MustStartOn);
00410     else if (type == "MustFinishOn")
00411         setConstraint(MustFinishOn);
00412     else if (type == "FixedInterval")
00413         setConstraint(FixedInterval);
00414     else
00415         setConstraint(ASAP);  // default
00416 }
00417 
00418 QString Node::constraintToString() const {
00419     // Do not i18n these, they are used in save()
00420     if (m_constraint == ASAP)
00421         return QString("ASAP");
00422     else if (m_constraint == ALAP)
00423         return QString("ALAP");
00424     else if (m_constraint == StartNotEarlier)
00425         return QString("StartNotEarlier");
00426     else if (m_constraint == FinishNotLater)
00427         return QString("FinishNotLater");
00428     else if (m_constraint == MustStartOn)
00429         return QString("MustStartOn");
00430     else if (m_constraint == MustFinishOn)
00431         return QString("MustFinishOn");
00432     else if (m_constraint == FixedInterval)
00433         return QString("FixedInterval");
00434 
00435     return QString();
00436 }
00437 
00438 void Node::propagateEarliestStart(DateTime &time) {
00439     if (m_currentSchedule == 0)
00440         return;
00441     m_currentSchedule->earliestStart = time;
00442     //kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->earliestStart.toString()<<endl;
00443     QPtrListIterator<Node> it = m_nodes;
00444     for (; it.current(); ++it) {
00445         it.current()->propagateEarliestStart(time);
00446     }
00447 }
00448 
00449 void Node::propagateLatestFinish(DateTime &time) {
00450     if (m_currentSchedule == 0)
00451         return;
00452     m_currentSchedule->latestFinish = time;
00453     //kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->latestFinish<<endl;
00454     QPtrListIterator<Node> it = m_nodes;
00455     for (; it.current(); ++it) {
00456         it.current()->propagateLatestFinish(time);
00457     }
00458 }
00459 
00460 void Node::moveEarliestStart(DateTime &time) {
00461     if (m_currentSchedule == 0)
00462         return;
00463     if (m_currentSchedule->earliestStart < time)
00464         m_currentSchedule->earliestStart = time;
00465     QPtrListIterator<Node> it = m_nodes;
00466     for (; it.current(); ++it) {
00467         it.current()->moveEarliestStart(time);
00468     }
00469 }
00470 
00471 void Node::moveLatestFinish(DateTime &time) {
00472     if (m_currentSchedule == 0)
00473         return;
00474     if (m_currentSchedule->latestFinish > time)
00475         m_currentSchedule->latestFinish = time;
00476     QPtrListIterator<Node> it = m_nodes;
00477     for (; it.current(); ++it) {
00478         it.current()->moveLatestFinish(time);
00479     }
00480 }
00481 
00482 void Node::initiateCalculation(Schedule &sch) {
00483     QPtrListIterator<Node> it = m_nodes;
00484     for (; it.current(); ++it) {
00485         it.current()->initiateCalculation(sch);
00486     }
00487 }
00488 
00489 void Node::resetVisited() {
00490     m_visitedForward = false;
00491     m_visitedBackward = false;
00492     QPtrListIterator<Node> it = m_nodes;
00493     for (; it.current(); ++it) {
00494         it.current()->resetVisited();
00495     }
00496 }
00497 
00498 Node *Node::siblingBefore() {
00499     //kdDebug()<<k_funcinfo<<endl;
00500     if (getParent())
00501         return getParent()->childBefore(this);
00502     return 0;
00503 }
00504 
00505 Node *Node::childBefore(Node *node) {
00506     //kdDebug()<<k_funcinfo<<endl;
00507     int index = m_nodes.findRef(node);
00508     if (index > 0){
00509         return m_nodes.at(index-1);
00510     }
00511     return 0;
00512 }
00513 
00514 Node *Node::siblingAfter() {
00515     //kdDebug()<<k_funcinfo<<endl;
00516     if (getParent())
00517         return getParent()->childAfter(this);
00518     return 0;
00519 }
00520 
00521 Node *Node::childAfter(Node *node)
00522 {
00523     //kdDebug()<<k_funcinfo<<endl;
00524     uint index = m_nodes.findRef(node);
00525     if (index < m_nodes.count()-1) {
00526         return m_nodes.at(index+1);    }
00527     return 0;
00528 }
00529 
00530 bool Node::moveChildUp(Node* node)
00531 {
00532     if (findChildNode(node) == -1)
00533         return false; // not my node!
00534     Node *sib = node->siblingBefore();
00535     if (!sib)
00536         return false;
00537     sib = sib->siblingBefore();
00538     delChildNode(node, false);
00539     if (sib) {
00540         addChildNode(node, sib);
00541     } else {
00542         insertChildNode(0, node);
00543     }        
00544     return true;
00545 }
00546 
00547 bool Node::moveChildDown(Node* node)
00548 {
00549     if (findChildNode(node) == -1)
00550         return false; // not my node!
00551     Node *sib = node->siblingAfter();
00552     if (!sib)
00553         return false;
00554     delChildNode(node, false);
00555     addChildNode(node, sib);
00556     return true;
00557 }
00558 
00559 bool Node::legalToLink(Node *node) {
00560     Node *p = projectNode();
00561     if (p)
00562         return p->legalToLink(this, node);
00563     return false;
00564 }
00565 
00566 bool Node::isEndNode() const {
00567     return m_dependChildNodes.isEmpty();
00568 }
00569 bool Node::isStartNode() const {
00570     return m_dependParentNodes.isEmpty();
00571 }
00572 
00573 bool Node::setId(QString id) {
00574     //kdDebug()<<k_funcinfo<<id<<endl;
00575     if (id.isEmpty()) {
00576         kdError()<<k_funcinfo<<"id is empty"<<endl;
00577         m_id = id;
00578         return false;
00579     }
00580     if (!m_id.isEmpty()) {
00581         Node *n = findNode();
00582         if (n == this) {
00583             //kdDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
00584             removeId();
00585         } else if (n) {
00586             //Hmmm, shouldn't happen
00587             kdError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different node: "<<n->name()<<endl;
00588         }
00589     }
00590     if (findNode(id)) {
00591         kdError()<<k_funcinfo<<"id '"<<id<<"' is already used for different node: "<<findNode(id)->name()<<endl;
00592         m_id = QString(); // hmmm
00593         return false;
00594     }
00595     m_id = id;
00596     insertId(id);
00597     //kdDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
00598     return true;
00599 }
00600 
00601 void Node::setStartTime(DateTime startTime) { 
00602     if (m_currentSchedule)
00603         m_currentSchedule->startTime = startTime;
00604     m_dateOnlyStartDate = startTime.date();
00605 }
00606 
00607 void Node::setEndTime(DateTime endTime) { 
00608     if (m_currentSchedule)
00609         m_currentSchedule->endTime = endTime;
00610     
00611     m_dateOnlyEndDate = endTime.date();
00612     if (endTime.time().isNull() && m_dateOnlyEndDate > m_dateOnlyStartDate)
00613         m_dateOnlyEndDate = m_dateOnlyEndDate.addDays(-1);
00614 }
00615 
00616 void Node::saveAppointments(QDomElement &element, long id) const {
00617     //kdDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl;
00618     QPtrListIterator<Node> it(m_nodes);
00619     for (; it.current(); ++it ) {
00620         it.current()->saveAppointments(element, id);
00621     }
00622 }
00623 
00624 QPtrList<Appointment> Node::appointments() {
00625     QPtrList<Appointment> lst;
00626     if (m_currentSchedule)
00627         lst = m_currentSchedule->appointments();
00628     return lst;
00629 }
00630 
00631 // Appointment *Node::findAppointment(Resource *resource) {
00632 //     if (m_currentSchedule)
00633 //         return m_currentSchedule->findAppointment(resource);
00634 //     return 0;
00635 // }
00636 bool Node::addAppointment(Appointment *appointment) {
00637     if (m_currentSchedule)
00638         return m_currentSchedule->add(appointment);
00639     return false;
00640 }
00641 
00642 bool Node::addAppointment(Appointment *appointment, Schedule &main) {
00643     //kdDebug()<<k_funcinfo<<this<<endl;
00644     Schedule *s = findSchedule(main.id());
00645     if (s == 0) {
00646         s = createSchedule(&main);
00647     }
00648     appointment->setNode(s);
00649     return s->add(appointment);
00650 }
00651 
00652 void Node::addAppointment(ResourceSchedule *resource, DateTime &start, DateTime &end, double load) {
00653     Schedule *node = findSchedule(resource->id());
00654     if (node == 0) {
00655         node = createSchedule(resource->parent());
00656     }
00657     node->addAppointment(resource, start, end, load);
00658 }
00659 
00660 void Node::takeSchedule(const Schedule *schedule) {
00661     if (schedule == 0)
00662         return;
00663     if (m_currentSchedule == schedule)
00664         m_currentSchedule = 0;
00665     m_schedules.take(schedule->id());
00666 }
00667 
00668 void Node::addSchedule(Schedule *schedule) {
00669     if (schedule == 0)
00670         return;
00671     m_schedules.replace(schedule->id(), schedule);
00672 }
00673 
00674 Schedule *Node::createSchedule(QString name, Schedule::Type type, long id) {
00675     //kdDebug()<<k_funcinfo<<name<<" type="<<type<<" id="<<(int)id<<endl;
00676     NodeSchedule *sch = new NodeSchedule(this, name, type, id);
00677     addSchedule(sch);
00678     return sch;
00679 }
00680 
00681 Schedule *Node::createSchedule(Schedule *parent) {
00682     //kdDebug()<<k_funcinfo<<name<<" type="<<type<<" id="<<(int)id<<endl;
00683     NodeSchedule *sch = new NodeSchedule(parent, this);
00684     addSchedule(sch);
00685     return sch;
00686 }
00687 
00688 Schedule *Node::findSchedule(const QString name, const Schedule::Type type) const {
00689     QIntDictIterator<Schedule> it = m_schedules;
00690     for (; it.current(); ++it) {
00691         if (!it.current()->isDeleted() && 
00692             it.current()->name() == name && it.current()->type() == type)
00693             return it.current();
00694     }
00695     return 0;
00696 }
00697 
00698 Schedule *Node::findSchedule(const Schedule::Type type) const {
00699     //kdDebug()<<k_funcinfo<<m_name<<" find type="<<type<<" nr="<<m_schedules.count()<<endl;
00700     QIntDictIterator<Schedule> it = m_schedules;
00701     for (; it.current(); ++it) {
00702         if (!it.current()->isDeleted() && it.current()->type() == type) {
00703             return it.current();
00704         }
00705     }
00706     return 0;
00707 }
00708 
00709 void Node::setScheduleDeleted(long id, bool on) {
00710     Schedule *ns = findSchedule(id);
00711     if (ns == 0) {
00712         kdError()<<k_funcinfo<<m_name<<" Could not find schedule with id="<<id<<endl;
00713     } else {
00714         ns->setDeleted(on);
00715     }
00716 }
00717 
00718 void Node::setParentSchedule(Schedule *sch) {
00719     Schedule *s = findSchedule(sch->id());
00720     if (s) {
00721         s->setParent(sch);
00722     }
00723     QPtrListIterator<Node> it = m_nodes;
00724     for (; it.current(); ++it) {
00725         it.current()->setParentSchedule(sch);
00726     }
00727 }
00728 
00729 bool Node::calcCriticalPath(bool fromEnd) {
00730     if (m_currentSchedule == 0)
00731         return false;
00732     //kdDebug()<<k_funcinfo<<m_name<<endl;
00733     if (!isCritical()) {
00734         return false;
00735     }
00736     if (!fromEnd && isStartNode()) {
00737         m_currentSchedule->inCriticalPath = true;
00738         return true;
00739     }
00740     if (fromEnd && isEndNode()) {
00741         m_currentSchedule->inCriticalPath = true;
00742         return true;
00743     }
00744     QPtrListIterator<Relation> pit(m_dependParentNodes);
00745     for (; pit.current(); ++pit) {
00746         if (pit.current()->parent()->calcCriticalPath(fromEnd)) {
00747             m_currentSchedule->inCriticalPath = true;
00748         }
00749     }
00750     return m_currentSchedule->inCriticalPath;
00751 }
00752 
00753 int Node::level() {
00754     Node *n = getParent();
00755     return n ? n->level() + 1 : 0;
00756 }
00757 
00758 void Node::generateWBS(int count, WBSDefinition &def, QString wbs) {
00759     m_wbs = wbs + def.code(count, level());
00760     //kdDebug()<<k_funcinfo<<m_name<<" wbs: "<<m_wbs<<endl;
00761     QString w = wbs + def.wbs(count, level());
00762     QPtrListIterator<Node> it = m_nodes;
00763     for (int i=0; it.current(); ++it) {
00764         it.current()->generateWBS(++i, def, w);
00765     }
00766 
00767 }
00768 
00769 void Node::setCurrentSchedule(long id) {
00770     QPtrListIterator<Node> it = m_nodes;
00771     for (; it.current(); ++it) {
00772         it.current()->setCurrentSchedule(id);
00773     }
00774     //kdDebug()<<k_funcinfo<<m_name<<" id: "<<id<<"="<<m_currentSchedule<<endl;
00775 }
00777 
00778 Effort::Effort( Duration e, Duration p, Duration o) {
00779   m_expectedEffort = e;
00780   m_pessimisticEffort = p;
00781   m_optimisticEffort = o;
00782   m_type = Type_Effort;
00783   m_risktype = Risk_None;
00784 }
00785 
00786 Effort::Effort(const Effort &effort) {
00787     set(effort.expected(), effort.pessimistic(), effort.optimistic());
00788     setType(effort.type());
00789     setRisktype(effort.risktype());
00790 }
00791 
00792 Effort::~Effort() {
00793 }
00794 
00795 const Effort Effort::zeroEffort( Duration::zeroDuration,
00796                        Duration::zeroDuration,
00797                        Duration::zeroDuration );
00798 
00799 void Effort::set( Duration e, Duration p, Duration o ) {
00800     m_expectedEffort = e;
00801     m_pessimisticEffort = (p == Duration::zeroDuration) ? e :  p;
00802     m_optimisticEffort = (o == Duration::zeroDuration) ? e :  o;
00803     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.toString()<<endl;
00804 }
00805 
00806 void Effort::set( int e, int p, int o ) {
00807     m_expectedEffort = Duration(e);
00808     m_pessimisticEffort = (p < 0) ? Duration(e) :  Duration(p);
00809     m_optimisticEffort = (o < 0) ? Duration(e) :  Duration(o);
00810     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.toString()<<endl;
00811     //kdDebug()<<k_funcinfo<<"   Optimistic: "<<m_optimisticEffort.toString()<<endl;
00812     //kdDebug()<<k_funcinfo<<"   Pessimistic: "<<m_pessimisticEffort.toString()<<endl;
00813 
00814     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.duration()<<" manseconds"<<endl;
00815 }
00816 
00817 //TODO (?): effort is not really a duration, should maybe not use Duration for storage
00818 void Effort::set(unsigned days, unsigned hours, unsigned minutes) {
00819     Duration dur(days, hours, minutes);
00820     set(dur);
00821     //kdDebug()<<k_funcinfo<<"effort="<<dur.toString()<<endl;
00822 }
00823 
00824 void Effort::expectedEffort(unsigned *days, unsigned *hours, unsigned *minutes) {
00825     m_expectedEffort.get(days, hours, minutes);
00826 }
00827 
00828 Duration Effort::variance() const {
00829     return (m_pessimisticEffort - m_optimisticEffort)/6;
00830 }
00831 Duration Effort::pertExpected() const {
00832     if (m_risktype == Risk_Low) {
00833         return (m_optimisticEffort + m_pessimisticEffort + (m_expectedEffort*4))/6;
00834     } else if (m_risktype == Risk_High) {
00835         return (m_optimisticEffort + (m_pessimisticEffort*2) + (m_expectedEffort*4))/7;
00836     }
00837     return m_expectedEffort; // risk==none
00838 }
00839 Duration Effort::pertOptimistic() const {
00840     if (m_risktype != Risk_None) {
00841         return pertExpected() - variance();
00842     }
00843     return m_optimisticEffort;
00844 }
00845 Duration Effort::pertPessimistic() const {
00846     if (m_risktype != Risk_None) {
00847         return pertExpected() + variance();
00848     }
00849     return m_pessimisticEffort;
00850 }
00851 
00852 Duration Effort::effort(int use) const {
00853     if (use == Effort::Use_Expected) {
00854         return pertExpected();
00855     } else if (use == Effort::Use_Optimistic) {
00856         return pertOptimistic();
00857     } else if (use == Effort::Use_Pessimistic)
00858         return pertPessimistic();
00859     
00860     return m_expectedEffort; // default
00861 }
00862 
00863 bool Effort::load(QDomElement &element) {
00864     m_expectedEffort = Duration::fromString(element.attribute("expected"));
00865     m_optimisticEffort = Duration::fromString(element.attribute("optimistic"));
00866     m_pessimisticEffort = Duration::fromString(element.attribute("pessimistic"));
00867     setType(element.attribute("type", "WorkBased"));
00868     setRisktype(element.attribute("risk"));
00869     return true;
00870 }
00871 
00872 void Effort::save(QDomElement &element) const {
00873     QDomElement me = element.ownerDocument().createElement("effort");
00874     element.appendChild(me);
00875     me.setAttribute("expected", m_expectedEffort.toString());
00876     me.setAttribute("optimistic", m_optimisticEffort.toString());
00877     me.setAttribute("pessimistic", m_pessimisticEffort.toString());
00878     me.setAttribute("type", typeToString());
00879     me.setAttribute("risk", risktypeToString());
00880 }
00881 
00882 QString Effort::typeToString() const {
00883     if (m_type == Type_Effort)
00884         return QString("Effort");
00885     if (m_type == Type_FixedDuration)
00886         return QString("Type_FixedDuration");
00887 
00888     return QString();
00889 }
00890 
00891 void Effort::setType(QString type) {
00892     if (type == "Effort")
00893         setType(Type_Effort);
00894     else if (type == "Type_FixedDuration")
00895         setType(Type_FixedDuration);
00896     else
00897         setType(Type_Effort); // default
00898 }
00899 
00900 QString Effort::risktypeToString() const {
00901     if (m_risktype == Risk_None)
00902         return QString("None");
00903     if (m_risktype == Risk_Low)
00904         return QString("Low");
00905     if (m_risktype == Risk_High)
00906         return QString("High");
00907 
00908     return QString();
00909 }
00910 
00911 void Effort::setRisktype(QString type) {
00912     if (type == "High")
00913         setRisktype(Risk_High);
00914     else if (type == "Low")
00915         setRisktype(Risk_Low);
00916     else
00917         setRisktype(Risk_None); // default
00918 }
00919 
00920 void Effort::setOptimisticRatio(int percent)
00921 {
00922     int p = percent>0 ? -percent : percent;
00923     m_optimisticEffort = m_expectedEffort*(100+p)/100;
00924 }
00925 
00926 int Effort::optimisticRatio() const {
00927     if (m_expectedEffort == Duration::zeroDuration)
00928         return 0;
00929     return (m_optimisticEffort.milliseconds()*100/m_expectedEffort.milliseconds())-100;
00930 }
00931 
00932 void Effort::setPessimisticRatio(int percent) 
00933 {
00934     int p = percent<0 ? -percent : percent;
00935     m_pessimisticEffort = m_expectedEffort*(100+p)/100;
00936 }
00937 int Effort::pessimisticRatio() const {
00938     if (m_expectedEffort == Duration::zeroDuration)
00939         return 0;
00940     return m_pessimisticEffort.milliseconds()*100/m_expectedEffort.milliseconds()-100;
00941 }
00942 
00943 // Debugging
00944 #ifndef NDEBUG
00945 void Node::printDebug(bool children, QCString indent) {
00946     kdDebug()<<indent<<"  Unique node identity="<<m_id<<endl;
00947     if (m_effort) m_effort->printDebug(indent);
00948     QString s = "  Constraint: " + constraintToString();
00949     if (m_constraint == MustStartOn || m_constraint == StartNotEarlier || m_constraint == FixedInterval)
00950         kdDebug()<<indent<<s<<" ("<<constraintStartTime().toString()<<")"<<endl;
00951     if (m_constraint == MustFinishOn || m_constraint == FinishNotLater || m_constraint == FixedInterval)
00952         kdDebug()<<indent<<s<<" ("<<constraintEndTime().toString()<<")"<<endl;
00953     Schedule *cs = m_currentSchedule; 
00954     if (cs) {
00955         kdDebug()<<indent<<"  Current schedule: "<<"id="<<cs->id()<<" '"<<cs->name()<<"' type: "<<cs->type()<<endl;
00956     } else {
00957         kdDebug()<<indent<<"  Current schedule: None"<<endl;
00958     }
00959     QIntDictIterator<Schedule> it = m_schedules;
00960     for (; it.current(); ++it) {
00961         it.current()->printDebug(indent+"  ");
00962     }
00963     kdDebug()<<indent<<"  Parent: "<<(m_parent ? m_parent->name() : QString("None"))<<endl;
00964     kdDebug()<<indent<<"  Level: "<<level()<<endl;
00965     kdDebug()<<indent<<"  No of predecessors: "<<m_dependParentNodes.count()<<endl;
00966     QPtrListIterator<Relation> pit(m_dependParentNodes);
00967     //kdDebug()<<indent<<"  Dependant parents="<<pit.count()<<endl;
00968     if (pit.count() > 0) {
00969         for ( ; pit.current(); ++pit ) {
00970             pit.current()->printDebug(indent);
00971         }
00972     }
00973     kdDebug()<<indent<<"  No of successors: "<<m_dependChildNodes.count()<<endl;
00974     QPtrListIterator<Relation> cit(m_dependChildNodes);
00975     //kdDebug()<<indent<<"  Dependant children="<<cit.count()<<endl;
00976     if (cit.count() > 0) {
00977         for ( ; cit.current(); ++cit ) {
00978             cit.current()->printDebug(indent);
00979         }
00980     }
00981 
00982     //kdDebug()<<indent<<endl;
00983     indent += "  ";
00984     if (children) {
00985         QPtrListIterator<Node> it(m_nodes);
00986         for ( ; it.current(); ++it ) {
00987             it.current()->printDebug(true,indent);
00988         }
00989     }
00990 
00991 }
00992 #endif
00993 
00994 
00995 #ifndef NDEBUG
00996 void Effort::printDebug(QCString indent) {
00997     kdDebug()<<indent<<"  Effort:"<<endl;
00998     indent += "  ";
00999     kdDebug()<<indent<<"  Expected:    "<<m_expectedEffort.toString()<<endl;
01000     kdDebug()<<indent<<"  Optimistic:  "<<m_optimisticEffort.toString()<<endl;
01001     kdDebug()<<indent<<"  Pessimistic: "<<m_pessimisticEffort.toString()<<endl;
01002     
01003     kdDebug()<<indent<<"  Risk: "<<risktypeToString()<<endl;
01004     kdDebug()<<indent<<"  Pert expected:    "<<pertExpected().toString()<<endl;
01005     kdDebug()<<indent<<"  Pert optimistic:  "<<pertOptimistic().toString()<<endl;
01006     kdDebug()<<indent<<"  Pert pessimistic: "<<pertPessimistic().toString()<<endl;
01007     kdDebug()<<indent<<"  Pert variance:    "<<variance().toString()<<endl;
01008 }
01009 #endif
01010 
01011 }  //KPlato namespace
KDE Home | KDE Accessibility Home | Description of Access Keys