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         removeId(node->id());
00124         if(remove)
00125             m_nodes.remove();
00126         else
00127             m_nodes.take();
00128     }
00129 }
00130 
00131 void Node::delChildNode( int number, bool remove) {
00132     Node *n = m_nodes.at(number);
00133     if (n)
00134         removeId(n->id());
00135     if(remove)
00136         m_nodes.remove(number);
00137     else
00138         m_nodes.take(number);
00139 }
00140 
00141 void Node::insertChildNode( unsigned int index, Node *node) {
00142     if (!node->setId(node->id())) {
00143         kdError()<<k_funcinfo<<node->name()<<" Not unique id: "<<m_id<<endl;
00144     }
00145     m_nodes.insert(index,node);
00146     node->setParent(this);
00147 }
00148 
00149 void Node::addChildNode( Node *node, Node *after) {
00150     int index = m_nodes.findRef(after);
00151     if (index == -1) {
00152         if (!node->setId(node->id())) {
00153             kdError()<<k_funcinfo<<node->name()<<" Not unique id: "<<m_id<<endl;
00154         }
00155         m_nodes.append(node);
00156         node->setParent(this);
00157         return;
00158     }
00159     m_nodes.insert(index+1, node);
00160     node->setParent(this);
00161 }
00162 
00163 int Node::findChildNode( Node* node )
00164 {
00165     return m_nodes.findRef( node );
00166 }
00167 
00168 
00169 const Node* Node::getChildNode(int number) const {
00170     // Work around missing const at() method in QPtrList
00171     const QPtrList<Node> &nodes = m_nodes;
00172     return (const_cast<QPtrList<Node> &>(nodes)).at(number);
00173 }
00174 
00175 Duration *Node::getDelay() {
00176     /* TODO
00177        Calculate the delay of this node. Use the calculated startTime and the setted startTime.
00178     */
00179     return 0L;
00180 }
00181 
00182 void Node::addDependChildNode( Node *node, Relation::Type p) {
00183     addDependChildNode(node,p,Duration());
00184 }
00185 
00186 void Node::addDependChildNode( Node *node, Relation::Type p, Duration lag) {
00187     Relation *relation = new Relation(this, node, p, lag);
00188     if (node->addDependParentNode(relation))
00189         m_dependChildNodes.append(relation);
00190     else
00191         delete relation;
00192 }
00193 
00194 void Node::insertDependChildNode( unsigned int index, Node *node, Relation::Type p) {
00195     Relation *relation = new Relation(this, node, p, Duration());
00196     if (node->addDependParentNode(relation))
00197         m_dependChildNodes.insert(index, relation);
00198     else
00199         delete relation;
00200 }
00201 
00202 bool Node::addDependChildNode( Relation *relation) {
00203     if(m_dependChildNodes.findRef(relation) != -1)
00204         return false;
00205     m_dependChildNodes.append(relation);
00206     return true;
00207 }
00208 
00209 // These delDepend... methods look suspicious to me, can someone review?
00210 void Node::delDependChildNode( Node *node, bool remove) {
00211     if ( m_nodes.findRef(node) != -1 ) {
00212         if(remove)
00213             m_dependChildNodes.remove();
00214         else
00215             m_dependChildNodes.take();
00216     }
00217 }
00218 
00219 void Node::delDependChildNode( Relation *rel, bool remove) {
00220     if ( m_dependChildNodes.findRef(rel) != -1 ) {
00221         if(remove)
00222             m_dependChildNodes.remove();
00223         else
00224             m_dependChildNodes.take();
00225     }
00226 }
00227 
00228 void Node::delDependChildNode( int number, bool remove) {
00229     if(remove)
00230         m_dependChildNodes.remove(number);
00231     else
00232         m_dependChildNodes.take(number);
00233 }
00234 
00235 void Node::takeDependChildNode(Relation *rel) {
00236     if (m_dependChildNodes.findRef(rel) != -1) {
00237         m_dependChildNodes.take();
00238     }
00239 }
00240 
00241 void Node::addDependParentNode( Node *node, Relation::Type p) {
00242     addDependParentNode(node,p,Duration());
00243 }
00244 
00245 void Node::addDependParentNode( Node *node, Relation::Type p, Duration lag) {
00246     Relation *relation = new Relation(node, this, p, lag);
00247     if (node->addDependChildNode(relation))
00248         m_dependParentNodes.append(relation);
00249     else
00250         delete relation;
00251 }
00252 
00253 void Node::insertDependParentNode( unsigned int index, Node *node, Relation::Type p) {
00254     Relation *relation = new Relation(this, node, p, Duration());
00255     if (node->addDependChildNode(relation))
00256         m_dependParentNodes.insert(index,relation);
00257     else
00258         delete relation;
00259 }
00260 
00261 bool Node::addDependParentNode( Relation *relation) {
00262     if(m_dependParentNodes.findRef(relation) != -1)
00263         return false;
00264     m_dependParentNodes.append(relation);
00265     return true;
00266 }
00267 
00268 // These delDepend... methods look suspicious to me, can someone review?
00269 void Node::delDependParentNode( Node *node, bool remove) {
00270     if ( m_nodes.findRef(node) != -1 ) {
00271         if(remove)
00272             m_dependParentNodes.remove();
00273         else
00274             m_dependParentNodes.take();
00275     }
00276 }
00277 
00278 void Node::delDependParentNode( Relation *rel, bool remove) {
00279     if ( m_dependParentNodes.findRef(rel) != -1 ) {
00280         if(remove)
00281             m_dependParentNodes.remove();
00282         else
00283             m_dependParentNodes.take();
00284     }
00285 }
00286 
00287 void Node::delDependParentNode( int number, bool remove) {
00288     if(remove)
00289         m_dependParentNodes.remove(number);
00290     else
00291         m_dependParentNodes.take(number);
00292 }
00293 
00294 void Node::takeDependParentNode(Relation *rel) {
00295     if (m_dependParentNodes.findRef(rel) != -1) {
00296         rel = m_dependParentNodes.take();
00297     }      
00298 }
00299 
00300 bool Node::isParentOf(Node *node) {
00301     if (m_nodes.findRef(node) != -1)
00302         return true;
00303 
00304     QPtrListIterator<Node> nit(childNodeIterator());
00305     for ( ; nit.current(); ++nit ) {
00306         if (nit.current()->isParentOf(node))
00307             return true;
00308     }
00309     return false;
00310 }
00311 
00312 Relation *Node::findParentRelation(Node *node) {
00313     for (int i=0; i<numDependParentNodes(); i++) {
00314         Relation *rel = getDependParentNode(i);
00315         if (rel->parent() == node)
00316             return rel;
00317     }
00318     return (Relation *)0;
00319 }
00320 
00321 Relation *Node::findChildRelation(Node *node) {
00322     for (int i=0; i<numDependChildNodes(); i++) {
00323         Relation *rel = getDependChildNode(i);
00324         if (rel->child() == node)
00325             return rel;
00326     }
00327     return (Relation *)0;
00328 }
00329 
00330 Relation *Node::findRelation(Node *node) {
00331     Relation *rel = findParentRelation(node);
00332     if (!rel)
00333         rel = findChildRelation(node);
00334     return rel;
00335 }
00336 
00337 bool Node::isDependChildOf(Node *node) {
00338     //kdDebug()<<k_funcinfo<<" '"<<m_name<<"' checking against '"<<node->name()<<"'"<<endl;
00339     for (int i=0; i<numDependParentNodes(); i++) {
00340         Relation *rel = getDependParentNode(i);
00341         if (rel->parent() == node)
00342             return true;
00343         if (rel->parent()->isDependChildOf(node))
00344             return true;
00345     }
00346     return false;
00347 }
00348 
00349 Duration Node::duration(const DateTime &time, int use, bool backward) {
00350     //kdDebug()<<k_funcinfo<<endl;
00351     // TODO: handle risc
00352     if (!time.isValid()) {
00353         kdError()<<k_funcinfo<<"Time is invalid"<<endl;
00354         return Duration::zeroDuration;
00355     }
00356     if (m_effort == 0) {
00357         kdError()<<k_funcinfo<<"m_effort == 0"<<endl;
00358         return Duration::zeroDuration;
00359     }
00360     if (m_currentSchedule == 0) {
00361         return Duration::zeroDuration;
00362         kdError()<<k_funcinfo<<"No current schedule"<<endl;
00363     }
00364     return calcDuration(time, m_effort->effort(use), backward);
00365 }
00366 
00367 void Node::makeAppointments() {
00368     QPtrListIterator<Node> nit(m_nodes);
00369     for ( ; nit.current(); ++nit ) {
00370         nit.current()->makeAppointments();
00371     }
00372 }
00373 
00374 void Node::calcResourceOverbooked() {
00375     QPtrListIterator<Node> nit(m_nodes);
00376     for ( ; nit.current(); ++nit ) {
00377         nit.current()->calcResourceOverbooked();
00378     }
00379 }
00380 
00381 void Node::saveRelations(QDomElement &element) const {
00382     QPtrListIterator<Relation> it(m_dependChildNodes);
00383     for (; it.current(); ++it) {
00384         it.current()->save(element);
00385     }
00386     QPtrListIterator<Node> nodes(m_nodes);
00387     for ( ; nodes.current(); ++nodes ) {
00388         nodes.current()->saveRelations(element);
00389     }
00390 }
00391 
00392 void Node::setConstraint(QString &type) {
00393     // Do not i18n these, they are used in load()
00394     if (type == "ASAP")
00395         setConstraint(ASAP);
00396     else if (type == "ALAP")
00397         setConstraint(ALAP);
00398     else if (type == "StartNotEarlier")
00399         setConstraint(StartNotEarlier);
00400     else if (type == "FinishNotLater")
00401         setConstraint(FinishNotLater);
00402     else if (type == "MustStartOn")
00403         setConstraint(MustStartOn);
00404     else if (type == "MustFinishOn")
00405         setConstraint(MustFinishOn);
00406     else if (type == "FixedInterval")
00407         setConstraint(FixedInterval);
00408     else
00409         setConstraint(ASAP);  // default
00410 }
00411 
00412 QString Node::constraintToString() const {
00413     // Do not i18n these, they are used in save()
00414     if (m_constraint == ASAP)
00415         return QString("ASAP");
00416     else if (m_constraint == ALAP)
00417         return QString("ALAP");
00418     else if (m_constraint == StartNotEarlier)
00419         return QString("StartNotEarlier");
00420     else if (m_constraint == FinishNotLater)
00421         return QString("FinishNotLater");
00422     else if (m_constraint == MustStartOn)
00423         return QString("MustStartOn");
00424     else if (m_constraint == MustFinishOn)
00425         return QString("MustFinishOn");
00426     else if (m_constraint == FixedInterval)
00427         return QString("FixedInterval");
00428 
00429     return QString();
00430 }
00431 
00432 void Node::propagateEarliestStart(DateTime &time) {
00433     if (m_currentSchedule == 0)
00434         return;
00435     m_currentSchedule->earliestStart = time;
00436     //kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->earliestStart.toString()<<endl;
00437     QPtrListIterator<Node> it = m_nodes;
00438     for (; it.current(); ++it) {
00439         it.current()->propagateEarliestStart(time);
00440     }
00441 }
00442 
00443 void Node::propagateLatestFinish(DateTime &time) {
00444     if (m_currentSchedule == 0)
00445         return;
00446     m_currentSchedule->latestFinish = time;
00447     //kdDebug()<<k_funcinfo<<m_name<<": "<<m_currentSchedule->latestFinish<<endl;
00448     QPtrListIterator<Node> it = m_nodes;
00449     for (; it.current(); ++it) {
00450         it.current()->propagateLatestFinish(time);
00451     }
00452 }
00453 
00454 void Node::moveEarliestStart(DateTime &time) {
00455     if (m_currentSchedule == 0)
00456         return;
00457     if (m_currentSchedule->earliestStart < time)
00458         m_currentSchedule->earliestStart = time;
00459     QPtrListIterator<Node> it = m_nodes;
00460     for (; it.current(); ++it) {
00461         it.current()->moveEarliestStart(time);
00462     }
00463 }
00464 
00465 void Node::moveLatestFinish(DateTime &time) {
00466     if (m_currentSchedule == 0)
00467         return;
00468     if (m_currentSchedule->latestFinish > time)
00469         m_currentSchedule->latestFinish = time;
00470     QPtrListIterator<Node> it = m_nodes;
00471     for (; it.current(); ++it) {
00472         it.current()->moveLatestFinish(time);
00473     }
00474 }
00475 
00476 void Node::initiateCalculation(Schedule &sch) {
00477     QPtrListIterator<Node> it = m_nodes;
00478     for (; it.current(); ++it) {
00479         it.current()->initiateCalculation(sch);
00480     }
00481 }
00482 
00483 void Node::resetVisited() {
00484     m_visitedForward = false;
00485     m_visitedBackward = false;
00486     QPtrListIterator<Node> it = m_nodes;
00487     for (; it.current(); ++it) {
00488         it.current()->resetVisited();
00489     }
00490 }
00491 
00492 Node *Node::siblingBefore() {
00493     //kdDebug()<<k_funcinfo<<endl;
00494     if (getParent())
00495         return getParent()->childBefore(this);
00496     return 0;
00497 }
00498 
00499 Node *Node::childBefore(Node *node) {
00500     //kdDebug()<<k_funcinfo<<endl;
00501     int index = m_nodes.findRef(node);
00502     if (index > 0){
00503         return m_nodes.at(index-1);
00504     }
00505     return 0;
00506 }
00507 
00508 Node *Node::siblingAfter() {
00509     //kdDebug()<<k_funcinfo<<endl;
00510     if (getParent())
00511         return getParent()->childAfter(this);
00512     return 0;
00513 }
00514 
00515 Node *Node::childAfter(Node *node)
00516 {
00517     //kdDebug()<<k_funcinfo<<endl;
00518     uint index = m_nodes.findRef(node);
00519     if (index < m_nodes.count()-1) {
00520         return m_nodes.at(index+1);    }
00521     return 0;
00522 }
00523 
00524 bool Node::moveChildUp(Node* node)
00525 {
00526     if (findChildNode(node) == -1)
00527         return false; // not my node!
00528     Node *sib = node->siblingBefore();
00529     if (!sib)
00530         return false;
00531     sib = sib->siblingBefore();
00532     delChildNode(node, false);
00533     if (sib) {
00534         addChildNode(node, sib);
00535     } else {
00536         insertChildNode(0, node);
00537     }        
00538     return true;
00539 }
00540 
00541 bool Node::moveChildDown(Node* node)
00542 {
00543     if (findChildNode(node) == -1)
00544         return false; // not my node!
00545     Node *sib = node->siblingAfter();
00546     if (!sib)
00547         return false;
00548     delChildNode(node, false);
00549     addChildNode(node, sib);
00550     return true;
00551 }
00552 
00553 bool Node::legalToLink(Node *node) {
00554     Node *p = projectNode();
00555     if (p)
00556         return p->legalToLink(this, node);
00557     return false;
00558 }
00559 
00560 bool Node::isEndNode() const {
00561     return m_dependChildNodes.isEmpty();
00562 }
00563 bool Node::isStartNode() const {
00564     return m_dependParentNodes.isEmpty();
00565 }
00566 
00567 bool Node::setId(QString id) {
00568     //kdDebug()<<k_funcinfo<<id<<endl;
00569     if (id.isEmpty()) {
00570         kdError()<<k_funcinfo<<"id is empty"<<endl;
00571         m_id = id;
00572         return false;
00573     }
00574     if (!m_id.isEmpty()) {
00575         Node *n = findNode();
00576         if (n == this) {
00577             //kdDebug()<<k_funcinfo<<"My id found, remove it"<<endl;
00578             removeId();
00579         } else if (n) {
00580             //Hmmm, shouldn't happen
00581             kdError()<<k_funcinfo<<"My id '"<<m_id<<"' already used for different node: "<<n->name()<<endl;
00582         }
00583     }
00584     if (findNode(id)) {
00585         kdError()<<k_funcinfo<<"id '"<<id<<"' is already used for different node: "<<findNode(id)->name()<<endl;
00586         m_id = QString(); // hmmm
00587         return false;
00588     }
00589     m_id = id;
00590     insertId(id);
00591     //kdDebug()<<k_funcinfo<<m_name<<": inserted id="<<id<<endl;
00592     return true;
00593 }
00594 
00595 void Node::setStartTime(DateTime startTime) { 
00596     if (m_currentSchedule)
00597         m_currentSchedule->startTime = startTime;
00598     m_dateOnlyStartDate = startTime.date();
00599 }
00600 
00601 void Node::setEndTime(DateTime endTime) { 
00602     if (m_currentSchedule)
00603         m_currentSchedule->endTime = endTime;
00604     
00605     m_dateOnlyEndDate = endTime.date();
00606     if (endTime.time().isNull() && m_dateOnlyEndDate > m_dateOnlyStartDate)
00607         m_dateOnlyEndDate = m_dateOnlyEndDate.addDays(-1);
00608 }
00609 
00610 void Node::saveAppointments(QDomElement &element, long id) const {
00611     //kdDebug()<<k_funcinfo<<m_name<<" id="<<id<<endl;
00612     QPtrListIterator<Node> it(m_nodes);
00613     for (; it.current(); ++it ) {
00614         it.current()->saveAppointments(element, id);
00615     }
00616 }
00617 
00618 QPtrList<Appointment> Node::appointments() {
00619     QPtrList<Appointment> lst;
00620     if (m_currentSchedule)
00621         lst = m_currentSchedule->appointments();
00622     return lst;
00623 }
00624 
00625 // Appointment *Node::findAppointment(Resource *resource) {
00626 //     if (m_currentSchedule)
00627 //         return m_currentSchedule->findAppointment(resource);
00628 //     return 0;
00629 // }
00630 bool Node::addAppointment(Appointment *appointment) {
00631     if (m_currentSchedule)
00632         return m_currentSchedule->add(appointment);
00633     return false;
00634 }
00635 
00636 bool Node::addAppointment(Appointment *appointment, Schedule &main) {
00637     //kdDebug()<<k_funcinfo<<this<<endl;
00638     Schedule *s = findSchedule(main.id());
00639     if (s == 0) {
00640         s = createSchedule(&main);
00641     }
00642     appointment->setNode(s);
00643     return s->add(appointment);
00644 }
00645 
00646 void Node::addAppointment(ResourceSchedule *resource, DateTime &start, DateTime &end, double load) {
00647     Schedule *node = findSchedule(resource->id());
00648     if (node == 0) {
00649         node = createSchedule(resource->parent());
00650     }
00651     node->addAppointment(resource, start, end, load);
00652 }
00653 
00654 void Node::takeSchedule(const Schedule *schedule) {
00655     if (schedule == 0)
00656         return;
00657     if (m_currentSchedule == schedule)
00658         m_currentSchedule = 0;
00659     m_schedules.take(schedule->id());
00660 }
00661 
00662 void Node::addSchedule(Schedule *schedule) {
00663     if (schedule == 0)
00664         return;
00665     m_schedules.replace(schedule->id(), schedule);
00666 }
00667 
00668 Schedule *Node::createSchedule(QString name, Schedule::Type type, long id) {
00669     //kdDebug()<<k_funcinfo<<name<<" type="<<type<<" id="<<(int)id<<endl;
00670     NodeSchedule *sch = new NodeSchedule(this, name, type, id);
00671     addSchedule(sch);
00672     return sch;
00673 }
00674 
00675 Schedule *Node::createSchedule(Schedule *parent) {
00676     //kdDebug()<<k_funcinfo<<name<<" type="<<type<<" id="<<(int)id<<endl;
00677     NodeSchedule *sch = new NodeSchedule(parent, this);
00678     addSchedule(sch);
00679     return sch;
00680 }
00681 
00682 Schedule *Node::findSchedule(const QString name, const Schedule::Type type) const {
00683     QIntDictIterator<Schedule> it = m_schedules;
00684     for (; it.current(); ++it) {
00685         if (!it.current()->isDeleted() && 
00686             it.current()->name() == name && it.current()->type() == type)
00687             return it.current();
00688     }
00689     return 0;
00690 }
00691 
00692 Schedule *Node::findSchedule(const Schedule::Type type) const {
00693     //kdDebug()<<k_funcinfo<<m_name<<" find type="<<type<<" nr="<<m_schedules.count()<<endl;
00694     QIntDictIterator<Schedule> it = m_schedules;
00695     for (; it.current(); ++it) {
00696         if (!it.current()->isDeleted() && it.current()->type() == type) {
00697             return it.current();
00698         }
00699     }
00700     return 0;
00701 }
00702 
00703 void Node::setScheduleDeleted(long id, bool on) {
00704     Schedule *ns = findSchedule(id);
00705     if (ns == 0) {
00706         kdError()<<k_funcinfo<<m_name<<" Could not find schedule with id="<<id<<endl;
00707     } else {
00708         ns->setDeleted(on);
00709     }
00710 }
00711 
00712 void Node::setParentSchedule(Schedule *sch) {
00713     Schedule *s = findSchedule(sch->id());
00714     if (s) {
00715         s->setParent(sch);
00716     }
00717     QPtrListIterator<Node> it = m_nodes;
00718     for (; it.current(); ++it) {
00719         it.current()->setParentSchedule(sch);
00720     }
00721 }
00722 
00723 bool Node::calcCriticalPath(bool fromEnd) {
00724     if (m_currentSchedule == 0)
00725         return false;
00726     //kdDebug()<<k_funcinfo<<m_name<<endl;
00727     if (!isCritical()) {
00728         return false;
00729     }
00730     if (!fromEnd && isStartNode()) {
00731         m_currentSchedule->inCriticalPath = true;
00732         return true;
00733     }
00734     if (fromEnd && isEndNode()) {
00735         m_currentSchedule->inCriticalPath = true;
00736         return true;
00737     }
00738     QPtrListIterator<Relation> pit(m_dependParentNodes);
00739     for (; pit.current(); ++pit) {
00740         if (pit.current()->parent()->calcCriticalPath(fromEnd)) {
00741             m_currentSchedule->inCriticalPath = true;
00742         }
00743     }
00744     return m_currentSchedule->inCriticalPath;
00745 }
00746 
00747 int Node::level() {
00748     Node *n = getParent();
00749     return n ? n->level() + 1 : 0;
00750 }
00751 
00752 void Node::generateWBS(int count, WBSDefinition &def, QString wbs) {
00753     m_wbs = wbs + def.code(count, level());
00754     //kdDebug()<<k_funcinfo<<m_name<<" wbs: "<<m_wbs<<endl;
00755     QString w = wbs + def.wbs(count, level());
00756     QPtrListIterator<Node> it = m_nodes;
00757     for (int i=0; it.current(); ++it) {
00758         it.current()->generateWBS(++i, def, w);
00759     }
00760 
00761 }
00762 
00763 void Node::setCurrentSchedule(long id) {
00764     QPtrListIterator<Node> it = m_nodes;
00765     for (; it.current(); ++it) {
00766         it.current()->setCurrentSchedule(id);
00767     }
00768     //kdDebug()<<k_funcinfo<<m_name<<" id: "<<id<<"="<<m_currentSchedule<<endl;
00769 }
00771 
00772 Effort::Effort( Duration e, Duration p, Duration o) {
00773   m_expectedEffort = e;
00774   m_pessimisticEffort = p;
00775   m_optimisticEffort = o;
00776   m_type = Type_Effort;
00777 }
00778 
00779 Effort::Effort(const Effort &effort) {
00780     set(effort.expected(), effort.pessimistic(), effort.optimistic());
00781     setType(effort.type());
00782 }
00783 
00784 Effort::~Effort() {
00785 }
00786 
00787 const Effort Effort::zeroEffort( Duration::zeroDuration,
00788                        Duration::zeroDuration,
00789                        Duration::zeroDuration );
00790 
00791 void Effort::set( Duration e, Duration p, Duration o ) {
00792     m_expectedEffort = e;
00793     m_pessimisticEffort = (p == Duration::zeroDuration) ? e :  p;
00794     m_optimisticEffort = (o == Duration::zeroDuration) ? e :  o;
00795     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.toString()<<endl;
00796 }
00797 
00798 void Effort::set( int e, int p, int o ) {
00799     m_expectedEffort = Duration(e);
00800     m_pessimisticEffort = (p < 0) ? Duration(e) :  Duration(p);
00801     m_optimisticEffort = (o < 0) ? Duration(e) :  Duration(o);
00802     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.toString()<<endl;
00803     //kdDebug()<<k_funcinfo<<"   Optimistic: "<<m_optimisticEffort.toString()<<endl;
00804     //kdDebug()<<k_funcinfo<<"   Pessimistic: "<<m_pessimisticEffort.toString()<<endl;
00805 
00806     //kdDebug()<<k_funcinfo<<"   Expected: "<<m_expectedEffort.duration()<<" manseconds"<<endl;
00807 }
00808 
00809 //TODO (?): effort is not really a duration, should maybe not use Duration for storage
00810 void Effort::set(unsigned days, unsigned hours, unsigned minutes) {
00811     Duration dur(days, hours, minutes);
00812     set(dur);
00813     //kdDebug()<<k_funcinfo<<"effort="<<dur.toString()<<endl;
00814 }
00815 
00816 void Effort::expectedEffort(unsigned *days, unsigned *hours, unsigned *minutes) {
00817     m_expectedEffort.get(days, hours, minutes);
00818 }
00819 
00820 bool Effort::load(QDomElement &element) {
00821     m_expectedEffort = Duration::fromString(element.attribute("expected"));
00822     m_optimisticEffort = Duration::fromString(element.attribute("optimistic"));
00823     m_pessimisticEffort = Duration::fromString(element.attribute("pessimistic"));
00824     setType(element.attribute("type", "WorkBased"));
00825     return true;
00826 }
00827 
00828 void Effort::save(QDomElement &element) const {
00829     QDomElement me = element.ownerDocument().createElement("effort");
00830     element.appendChild(me);
00831     me.setAttribute("expected", m_expectedEffort.toString());
00832     me.setAttribute("optimistic", m_optimisticEffort.toString());
00833     me.setAttribute("pessimistic", m_pessimisticEffort.toString());
00834     me.setAttribute("type", typeToString());
00835 }
00836 
00837 QString Effort::typeToString() const {
00838     if (m_type == Type_Effort)
00839         return QString("Effort");
00840     if (m_type == Type_FixedDuration)
00841         return QString("Type_FixedDuration");
00842 
00843     return QString();
00844 }
00845 
00846 void Effort::setType(QString type) {
00847     if (type == "Effort")
00848         setType(Type_Effort);
00849     else if (type == "Type_FixedDuration")
00850         setType(Type_FixedDuration);
00851     else
00852         setType(Type_Effort); // default
00853 }
00854 
00855 void Effort::setOptimisticRatio(int percent)
00856 {
00857     int p = percent>0 ? -percent : percent;
00858     m_optimisticEffort = m_expectedEffort*(100+p)/100;
00859 }
00860 
00861 int Effort::optimisticRatio() const {
00862     if (m_expectedEffort == Duration::zeroDuration)
00863         return 0;
00864     return (m_optimisticEffort.milliseconds()*100/m_expectedEffort.milliseconds())-100;
00865 }
00866 
00867 void Effort::setPessimisticRatio(int percent) 
00868 {
00869     int p = percent<0 ? -percent : percent;
00870     m_pessimisticEffort = m_expectedEffort*(100+p)/100;
00871 }
00872 int Effort::pessimisticRatio() const {
00873     if (m_expectedEffort == Duration::zeroDuration)
00874         return 0;
00875     return m_pessimisticEffort.milliseconds()*100/m_expectedEffort.milliseconds()-100;
00876 }
00877 
00878 // Debugging
00879 #ifndef NDEBUG
00880 void Node::printDebug(bool children, QCString indent) {
00881     kdDebug()<<indent<<"  Unique node identity="<<m_id<<endl;
00882     if (m_effort) m_effort->printDebug(indent);
00883     QString s = "  Constraint: " + constraintToString();
00884     if (m_constraint == MustStartOn || m_constraint == StartNotEarlier || m_constraint == FixedInterval)
00885         kdDebug()<<indent<<s<<" ("<<constraintStartTime().toString()<<")"<<endl;
00886     if (m_constraint == MustFinishOn || m_constraint == FinishNotLater || m_constraint == FixedInterval)
00887         kdDebug()<<indent<<s<<" ("<<constraintEndTime().toString()<<")"<<endl;
00888     Schedule *cs = m_currentSchedule; 
00889     if (cs) {
00890         kdDebug()<<indent<<"  Current schedule: "<<"id="<<cs->id()<<" '"<<cs->name()<<"' type: "<<cs->type()<<endl;
00891     } else {
00892         kdDebug()<<indent<<"  Current schedule: None"<<endl;
00893     }
00894     QIntDictIterator<Schedule> it = m_schedules;
00895     for (; it.current(); ++it) {
00896         it.current()->printDebug(indent+"  ");
00897     }
00898     kdDebug()<<indent<<"  Parent: "<<(m_parent ? m_parent->name() : QString("None"))<<endl;
00899     kdDebug()<<indent<<"  Level: "<<level()<<endl;
00900     kdDebug()<<indent<<"  No of predecessors: "<<m_dependParentNodes.count()<<endl;
00901     QPtrListIterator<Relation> pit(m_dependParentNodes);
00902     //kdDebug()<<indent<<"  Dependant parents="<<pit.count()<<endl;
00903     if (pit.count() > 0) {
00904         for ( ; pit.current(); ++pit ) {
00905             pit.current()->printDebug(indent);
00906         }
00907     }
00908     kdDebug()<<indent<<"  No of successors: "<<m_dependChildNodes.count()<<endl;
00909     QPtrListIterator<Relation> cit(m_dependChildNodes);
00910     //kdDebug()<<indent<<"  Dependant children="<<cit.count()<<endl;
00911     if (cit.count() > 0) {
00912         for ( ; cit.current(); ++cit ) {
00913             cit.current()->printDebug(indent);
00914         }
00915     }
00916 
00917     //kdDebug()<<indent<<endl;
00918     indent += "  ";
00919     if (children) {
00920         QPtrListIterator<Node> it(m_nodes);
00921         for ( ; it.current(); ++it ) {
00922             it.current()->printDebug(true,indent);
00923         }
00924     }
00925 
00926 }
00927 #endif
00928 
00929 
00930 #ifndef NDEBUG
00931 void Effort::printDebug(QCString indent) {
00932     kdDebug()<<indent<<"  Effort:"<<endl;
00933     indent += "  ";
00934     kdDebug()<<indent<<"  Expected: "<<m_expectedEffort.toString()<<endl;
00935     kdDebug()<<indent<<"  Optimistic: "<<m_optimisticEffort.toString()<<endl;
00936     kdDebug()<<indent<<"  Pessimistic: "<<m_pessimisticEffort.toString()<<endl;
00937 }
00938 #endif
00939 
00940 }  //KPlato namespace
KDE Home | KDE Accessibility Home | Description of Access Keys