kplato

kptproject.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 
00021 #include "kptproject.h"
00022 #include "kptappointment.h"
00023 #include "kpttask.h"
00024 #include "kptprojectdialog.h"
00025 #include "kptdatetime.h"
00026 #include "kptpart.h"
00027 #include "kptconfig.h"
00028 #include "kpteffortcostmap.h"
00029 #include "kptschedule.h"
00030 
00031 #include <qdom.h>
00032 #include <qstring.h>
00033 #include <qdatetime.h>
00034 #include <qbrush.h>
00035 #include <qcanvas.h>
00036 #include <qptrlist.h>
00037 
00038 #include <kdatetimewidget.h>
00039 #include <kdebug.h>
00040 
00041 namespace KPlato
00042 {
00043 
00044 
00045 Project::Project(Node *parent)
00046     : Node(parent),
00047       m_accounts(*this),
00048       m_defaultCalendar(0),
00049       m_baselined(false) {
00050     //kdDebug()<<k_funcinfo<<"("<<this<<")"<<endl;
00051     m_constraint = Node::MustStartOn;
00052     m_standardWorktime = new StandardWorktime();
00053     m_schedules.setAutoDelete(true);
00054     init();
00055 }
00056 
00057 void Project::init() {
00058     if (m_parent == 0) {
00059         // set sensible defaults for a project wo parent
00060         m_constraintStartTime = QDateTime(QDate::currentDate(), QTime());
00061         m_constraintEndTime = m_constraintStartTime.addDays(1);
00062     }
00063     m_calendars.setAutoDelete(true);
00064 }
00065 
00066 
00067 Project::~Project() {
00068     m_resourceGroups.setAutoDelete(true);
00069     m_resourceGroups.clear();
00070     delete m_standardWorktime;
00071 }
00072 
00073 int Project::type() const { return Node::Type_Project; }
00074 
00075 void Project::calculate(Schedule *schedule) {
00076     if (schedule == 0) {
00077         kdError()<<k_funcinfo<<"Schedule == 0, cannot calculate"<<endl;
00078         return;
00079     }
00080     m_currentSchedule = schedule;
00081     calculate();
00082 }
00083 
00084 void Project::calculate(Effort::Use estType) {
00085     m_currentSchedule = findSchedule((Schedule::Type)estType);
00086     if (m_currentSchedule == 0) {
00087         m_currentSchedule = createSchedule(i18n("Standard"), (Schedule::Type)estType);
00088     }
00089     calculate();
00090 }
00091 
00092 void Project::calculate() {
00093     if (m_currentSchedule == 0) {
00094         kdError()<<k_funcinfo<<"No current schedule to calculate"<<endl;
00095         return;
00096     }
00097     Effort::Use estType = (Effort::Use)m_currentSchedule->type();
00098     if (type() == Type_Project) {
00099         initiateCalculation(*m_currentSchedule);
00100         if (m_constraint == Node::MustStartOn) {
00101             //kdDebug()<<k_funcinfo<<"Node="<<m_name<<" Start="<<m_constraintStartTime.toString()<<endl;
00102             m_currentSchedule->startTime = m_constraintStartTime;
00103             m_currentSchedule->earliestStart = m_constraintStartTime;
00104             // Calculate from start time
00105             propagateEarliestStart(m_currentSchedule->earliestStart);
00106             m_currentSchedule->latestFinish = calculateForward(estType);
00107             propagateLatestFinish(m_currentSchedule->latestFinish);
00108             calculateBackward(estType);
00109             m_currentSchedule->endTime = scheduleForward(m_currentSchedule->startTime, estType);
00110             calcCriticalPath(false);
00111         } else {
00112             //kdDebug()<<k_funcinfo<<"Node="<<m_name<<" End="<<m_constraintEndTime.toString()<<endl;
00113             m_currentSchedule->endTime = m_constraintEndTime;
00114             m_currentSchedule->latestFinish = m_constraintEndTime;
00115             // Calculate from end time
00116             propagateLatestFinish(m_currentSchedule->latestFinish);
00117             m_currentSchedule->earliestStart = calculateBackward(estType);
00118             propagateEarliestStart(m_currentSchedule->earliestStart);
00119             calculateForward(estType);
00120             m_currentSchedule->startTime = scheduleBackward(m_currentSchedule->endTime, estType);
00121             calcCriticalPath(true);
00122         }
00123         makeAppointments();
00124         calcResourceOverbooked();
00125         m_currentSchedule->notScheduled = false;
00126     } else if (type() == Type_Subproject) {
00127         kdWarning()<<k_funcinfo<<"Subprojects not implemented"<<endl;
00128     } else {
00129         kdError()<<k_funcinfo<<"Illegal project type: "<<type()<<endl;
00130     }
00131 }
00132 
00133 bool Project::calcCriticalPath(bool fromEnd) {
00134     //kdDebug()<<k_funcinfo<<endl;
00135     if (fromEnd) {
00136         QPtrListIterator<Node> startnodes = m_startNodes;
00137         for (; startnodes.current(); ++startnodes) {
00138             startnodes.current()->calcCriticalPath(fromEnd);
00139         }
00140     } else {
00141         QPtrListIterator<Node> endnodes = m_endNodes;
00142         for (; endnodes.current(); ++endnodes) {
00143             endnodes.current()->calcCriticalPath(fromEnd);
00144         }
00145     }
00146     return false;
00147 }
00148 
00149 DateTime Project::startTime() const {
00150     //kdDebug()<<k_funcinfo<<(m_currentSchedule?m_currentSchedule->id():-1)<<" "<<(m_currentSchedule?m_currentSchedule->typeToString():"")<<endl;
00151     if (m_currentSchedule)
00152         return m_currentSchedule->startTime;
00153     
00154     return m_constraintStartTime;
00155 }
00156 
00157 DateTime Project::endTime() const {
00158     //kdDebug()<<k_funcinfo<<(m_currentSchedule?m_currentSchedule->id():-1)<<" "<<(m_currentSchedule?m_currentSchedule->typeToString():"")<<endl;
00159     if (m_currentSchedule)
00160         return m_currentSchedule->endTime;
00161     
00162     return m_constraintEndTime;
00163 }
00164 
00165 Duration *Project::getExpectedDuration() {
00166     //kdDebug()<<k_funcinfo<<endl;
00167     return new Duration(getLatestFinish() - getEarliestStart());
00168 }
00169 
00170 Duration *Project::getRandomDuration() {
00171     return 0L;
00172 }
00173 
00174 DateTime Project::calculateForward(int use) {
00175     //kdDebug()<<k_funcinfo<<m_name<<endl;
00176     if (type() == Node::Type_Project) {
00177         // Follow *parent* relations back and
00178         // calculate forwards following the child relations
00179         DateTime finish;
00180         DateTime time;
00181         QPtrListIterator<Node> endnodes = m_endNodes;
00182         for (; endnodes.current(); ++endnodes) {
00183             time = endnodes.current()->calculateForward(use);
00184             if (!finish.isValid() || time > finish)
00185                 finish = time;
00186         }
00187         //kdDebug()<<k_funcinfo<<m_name<<" finish="<<finish.toString()<<endl;
00188         return finish;
00189     } else {
00190         //TODO: subproject
00191     }
00192     return DateTime();
00193 }
00194 
00195 DateTime Project::calculateBackward(int use) {
00196     //kdDebug()<<k_funcinfo<<m_name<<endl;
00197     if (type() == Node::Type_Project) {
00198         // Follow *child* relations back and
00199         // calculate backwards following parent relation
00200         DateTime start;
00201         DateTime time;
00202         QPtrListIterator<Node> startnodes = m_startNodes;
00203         for (; startnodes.current(); ++startnodes) {
00204             time = startnodes.current()->calculateBackward(use);
00205             if (!start.isValid() || time < start)
00206                 start = time;
00207         }
00208         //kdDebug()<<k_funcinfo<<m_name<<" start="<<start.toString()<<endl;
00209         return start;
00210     } else {
00211         //TODO: subproject
00212     }
00213     return DateTime();
00214 }
00215 
00216 DateTime Project::scheduleForward(const DateTime &earliest, int use) {
00217     resetVisited();
00218     DateTime end = earliest;
00219     DateTime time;
00220     QPtrListIterator<Node> it(m_endNodes);
00221     for (; it.current(); ++it) {
00222         time = it.current()->scheduleForward(earliest, use);
00223         if (time > end)
00224             end = time;
00225     }
00226     // Fix summarytasks
00227     adjustSummarytask();
00228     return end;
00229 }
00230 
00231 DateTime Project::scheduleBackward(const DateTime &latest, int use) {
00232     resetVisited();
00233     DateTime start = latest;
00234     DateTime time;
00235     QPtrListIterator<Node> it(m_startNodes);
00236     for (; it.current(); ++it) {
00237         time = it.current()->scheduleBackward(latest, use);
00238         if (time < start)
00239             start = time;
00240     }
00241     // Fix summarytasks
00242     adjustSummarytask();
00243     return start;
00244 }
00245 
00246 void Project::adjustSummarytask() {
00247     QPtrListIterator<Node> it(m_summarytasks);
00248     for (; it.current(); ++it) {
00249         it.current()->adjustSummarytask();
00250     }
00251 }
00252 
00253 void Project::initiateCalculation(Schedule &sch) {
00254     //kdDebug()<<k_funcinfo<<m_name<<endl;
00255     // clear all resource appointments
00256     m_visitedForward = false;
00257     m_visitedBackward = false;
00258     QPtrListIterator<ResourceGroup> git(m_resourceGroups);
00259     for ( ; git.current(); ++git ) {
00260         git.current()->initiateCalculation(sch);
00261     }
00262     Node::initiateCalculation(sch);
00263     m_startNodes.clear();
00264     m_endNodes.clear();
00265     m_summarytasks.clear();
00266     initiateCalculationLists(m_startNodes, m_endNodes, m_summarytasks);
00267 }
00268 
00269 void Project::initiateCalculationLists(QPtrList<Node> &startnodes, QPtrList<Node> &endnodes, QPtrList<Node> &summarytasks) {
00270     //kdDebug()<<k_funcinfo<<m_name<<endl;
00271     if (type() == Node::Type_Project) {
00272         QPtrListIterator<Node> it = childNodeIterator();
00273         for (; it.current(); ++it) {
00274             it.current()->initiateCalculationLists(startnodes, endnodes, summarytasks);
00275         }
00276     } else {
00277         //TODO: subproject
00278     }
00279 }
00280 
00281 bool Project::load(QDomElement &element) {
00282     //kdDebug()<<k_funcinfo<<"--->"<<endl;
00283     QString s;
00284     bool ok = false;
00285     QString id = element.attribute("id");
00286     if (!setId(id)) {
00287         kdWarning()<<k_funcinfo<<"Id must be unique: "<<id<<endl;
00288     }
00289     m_name = element.attribute("name");
00290     m_leader = element.attribute("leader");
00291     m_description = element.attribute("description");
00292     
00293     //m_baselined = (bool)element.attribute("baselined","0").toInt(&ok);FIXME: Removed for this release  
00294     
00295     // Allow for both numeric and text
00296     s = element.attribute("scheduling","0");
00297     m_constraint = (Node::ConstraintType)s.toInt(&ok);
00298     if (!ok)
00299         setConstraint(s);
00300     if (m_constraint != Node::MustStartOn &&
00301         m_constraint != Node::MustFinishOn) {
00302         kdError()<<k_funcinfo<<"Illegal constraint: "<<constraintToString()<<endl;
00303         setConstraint(Node::MustStartOn);
00304     }
00305     s = element.attribute("start-time");
00306     if (!s.isEmpty())
00307         m_constraintStartTime = DateTime::fromString(s);
00308     s = element.attribute("end-time");
00309     if (!s.isEmpty())
00310         m_constraintEndTime = DateTime::fromString(s);
00311     
00312     // Load the project children
00313     // Must do these first
00314     QDomNodeList list = element.childNodes();
00315     for (unsigned int i=0; i<list.count(); ++i) {
00316         if (list.item(i).isElement()) {
00317             QDomElement e = list.item(i).toElement();
00318             if (e.tagName() == "calendar") {
00319                 // Load the calendar.
00320                 // References by resources
00321                 Calendar *child = new Calendar();
00322                 child->setProject(this);
00323                 if (child->load(e)) {
00324                     addCalendar(child);
00325                 } else {
00326                     // TODO: Complain about this
00327                     kdError()<<k_funcinfo<<"Failed to load calendar"<<endl;
00328                     delete child;
00329                 }
00330             } else if (e.tagName() == "standard-worktime") {
00331                 // Load standard worktime
00332                 StandardWorktime *child = new StandardWorktime();
00333                 if (child->load(e)) {
00334                     setStandardWorktime(child);
00335                 } else {
00336                     kdError()<<k_funcinfo<<"Failed to load standard worktime"<<endl;
00337                     delete child;
00338                 }
00339             }
00340         }
00341     }
00342     for (unsigned int i=0; i<list.count(); ++i) {
00343         if (list.item(i).isElement()) {
00344             QDomElement e = list.item(i).toElement();
00345     
00346             if (e.tagName() == "resource-group") {
00347                 // Load the resources
00348                 // References calendars
00349                 ResourceGroup *child = new ResourceGroup(this);
00350                 if (child->load(e)) {
00351                         addResourceGroup(child);
00352                 } else {
00353                     // TODO: Complain about this
00354                     delete child;
00355                 }
00356             }
00357         }
00358     }
00359     for (unsigned int i=0; i<list.count(); ++i) {
00360         if (list.item(i).isElement()) {
00361             QDomElement e = list.item(i).toElement();
00362     
00363             if (e.tagName() == "project") {
00364                 //kdDebug()<<k_funcinfo<<"Sub project--->"<<endl;
00365                 // Load the subproject
00366                 Project *child = new Project(this);
00367                 if (child->load(e)) {
00368                     addChildNode(child);
00369                 } else {
00370                     // TODO: Complain about this
00371                     delete child;
00372                 }
00373             } else if (e.tagName() == "task") {
00374                 //kdDebug()<<k_funcinfo<<"Task--->"<<endl;
00375                 // Load the task (and resourcerequests). 
00376                 // Depends on resources already loaded
00377                 Task *child = new Task(this);
00378                 if (child->load(e, *this)) {
00379                     addChildNode(child);
00380                 } else {
00381                     // TODO: Complain about this
00382                     delete child;
00383                 }
00384             }
00385         }
00386     }
00387     // These go last
00388     for (unsigned int i=0; i<list.count(); ++i) {
00389         if (list.item(i).isElement()) {
00390             QDomElement e = list.item(i).toElement();
00391             if (e.tagName() == "accounts") {
00392                 //kdDebug()<<k_funcinfo<<"Accounts--->"<<endl;
00393                 // Load accounts
00394                 // References tasks
00395                 if (!m_accounts.load(e, *this)) {
00396                     kdError()<<k_funcinfo<<"Failed to load accounts"<<endl;
00397                 }
00398             } else if (e.tagName() == "relation") {
00399                 //kdDebug()<<k_funcinfo<<"Relation--->"<<endl;
00400                 // Load the relation
00401                 // References tasks
00402                 Relation *child = new Relation();
00403                 if (!child->load(e, *this)) {
00404                     // TODO: Complain about this
00405                     kdError()<<k_funcinfo<<"Failed to load relation"<<endl;
00406                     delete child;
00407                 }
00408                 //kdDebug()<<k_funcinfo<<"Relation<---"<<endl;
00409             } else if (e.tagName() == "schedules") {
00410                 //kdDebug()<<k_funcinfo<<"Project schedules & task appointments--->"<<endl;
00411                 // Prepare for multiple schedules
00412                 // References tasks and resources
00413                 QDomNodeList lst = e.childNodes();
00414                 for (unsigned int i=0; i<lst.count(); ++i) {
00415                     if (lst.item(i).isElement()) {
00416                         QDomElement el = lst.item(i).toElement();
00417                         if (el.tagName() == "schedule") {
00418                             MainSchedule *sch = new MainSchedule();
00419                             if (sch->loadXML(el, *this)) {
00420                                 addSchedule(sch);
00421                                 sch->setNode(this);
00422                                 setParentSchedule(sch);
00423                                 // If it's here, it's scheduled!
00424                                 sch->setScheduled(true);
00425                             } else {
00426                                 kdError()<<k_funcinfo<<"Failed to load schedule"<<endl;
00427                                 delete sch;
00428                             }
00429                         }
00430                     }
00431                 }
00432                 //kdDebug()<<k_funcinfo<<"Node schedules<---"<<endl;
00433             }
00434         }
00435     }
00436     //kdDebug()<<k_funcinfo<<"Calendars--->"<<endl;
00437     // calendars references calendars in arbritary saved order
00438     QPtrListIterator<Calendar> calit(m_calendars);
00439     for (; calit.current(); ++calit) {
00440         if (calit.current()->id() == calit.current()->parentId()) {
00441             kdError()<<k_funcinfo<<"Calendar want itself as parent"<<endl;
00442             continue;
00443         }
00444         calit.current()->setParent(calendar(calit.current()->parentId()));
00445     }
00446     //kdDebug()<<k_funcinfo<<"Project schedules--->"<<endl;
00447     QIntDictIterator<Schedule> it = m_schedules;
00448     if (it.current()) {
00449         if (m_constraint == Node::MustFinishOn)
00450             m_constraintEndTime = it.current()->endTime;
00451         else
00452             m_constraintStartTime = it.current()->startTime;
00453     }
00454     //kdDebug()<<k_funcinfo<<"Project schedules<---"<<endl;
00455     //kdDebug()<<k_funcinfo<<"<---"<<endl;
00456     return true;
00457 }
00458 
00459 void Project::save(QDomElement &element)  const {
00460     QDomElement me = element.ownerDocument().createElement("project");
00461     element.appendChild(me);
00462 
00463     me.setAttribute("name", m_name);
00464     me.setAttribute("leader", m_leader);
00465     me.setAttribute("id", m_id);
00466     me.setAttribute("description", m_description);
00467     
00468     //me.setAttribute("baselined",(int)m_baselined); FIXME: Removed for this release  
00469 
00470     me.setAttribute("scheduling",constraintToString());    
00471     me.setAttribute("start-time", m_constraintStartTime.toString(Qt::ISODate));
00472     me.setAttribute("end-time", m_constraintEndTime.toString(Qt::ISODate));
00473     
00474     m_accounts.save(me);
00475     
00476     // save calendars
00477     QPtrListIterator<Calendar> calit(m_calendars);
00478     for (; calit.current(); ++calit) {
00479         calit.current()->save(me);
00480     }
00481     // save standard worktime
00482     if (m_standardWorktime)
00483         m_standardWorktime->save(me);
00484     
00485     // save project resources, must be after calendars
00486     QPtrListIterator<ResourceGroup> git(m_resourceGroups);
00487     for ( ; git.current(); ++git ) {
00488         git.current()->save(me);
00489     }
00490 
00491     // Only save parent relations
00492     QPtrListIterator<Relation> it(m_dependParentNodes);
00493     for ( ; it.current(); ++it ) {
00494         it.current()->save(me);
00495     }
00496 
00497     for (int i=0; i<numChildren(); i++)
00498     // Save all children
00499     getChildNode(i)->save(me);
00500 
00501     // Now we can save relations assuming no tasks have relations outside the project
00502     QPtrListIterator<Node> nodes(m_nodes);
00503     for ( ; nodes.current(); ++nodes ) {
00504         nodes.current()->saveRelations(me);
00505     }
00506     
00507     if (!m_schedules.isEmpty()) {
00508         QDomElement el = me.ownerDocument().createElement("schedules");
00509         me.appendChild(el);
00510         QIntDictIterator<Schedule> it = m_schedules;
00511         for (; it.current(); ++it) {
00512             if (!it.current()->isDeleted() && it.current()->isScheduled()) {
00513                 QDomElement schs = el.ownerDocument().createElement("schedule");
00514                 el.appendChild(schs);
00515                 it.current()->saveXML(schs);
00516                 //kdDebug()<<k_funcinfo<<m_name<<" id="<<it.current()->id()<<(it.current()->isDeleted()?"  Deleted":"")<<endl;
00517                 Node::saveAppointments(schs, it.current()->id());
00518             }
00519         }
00520     }
00521 }
00522 
00523 void Project::setParentSchedule(Schedule *sch) {
00524     QPtrListIterator<Node> it = m_nodes;
00525     for (; it.current(); ++it) {
00526         it.current()->setParentSchedule(sch);
00527     }
00528 }
00529 
00530 void Project::addResourceGroup(ResourceGroup * group) {
00531     m_resourceGroups.append(group);
00532 }
00533 
00534 
00535 void Project::removeResourceGroup(ResourceGroup * group){
00536     m_resourceGroups.remove(group);
00537 }
00538 
00539 
00540 void Project::removeResourceGroup(int /* number */){
00541    // always auto remove
00542 }
00543 
00544 
00545 void Project::insertResourceGroup( unsigned int /* index */,
00546                   ResourceGroup * /* resource */) {
00547 }
00548 
00549 QPtrList<ResourceGroup> &Project::resourceGroups() {
00550      return m_resourceGroups;
00551 }
00552 
00553 bool Project::addTask( Node* task, Node* position )
00554 {
00555     // we want to add a task at the given position. => the new node will
00556     // become next sibling right after position.
00557     if ( 0 == position ) {
00558       kdError()<<k_funcinfo<<"position=0, could not add task: "<<task->name()<<endl;
00559       return false;
00560     }
00561     //kdDebug()<<k_funcinfo<<"Add "<<task->name()<<" after "<<position->name()<<endl;
00562     // in case we want to add to the main project, we make it child element
00563     // of the root element.
00564     if ( Node::Type_Project == position->type() ) {
00565         return addSubTask(task, position);
00566     }
00567     // find the position
00568     // we have to tell the parent that we want to delete one of its children
00569     Node* parentNode = position->getParent();
00570     if ( !parentNode ) {
00571         kdDebug()<<k_funcinfo<<"parent node not found???"<<endl;
00572         return false;
00573     }
00574     int index = parentNode->findChildNode( position );
00575     if ( -1 == index ) {
00576         // ok, it does not exist
00577         kdDebug()<<k_funcinfo<<"Task not found???"<<endl;
00578         return false;
00579     }
00580     parentNode->insertChildNode( index+1, task );
00581     return true;
00582 }
00583 
00584 bool Project::addSubTask( Node* task, Node* position )
00585 {
00586     // we want to add a subtask to the node "position". It will become
00587     // position's last child.
00588     if ( 0 == position ) {
00589       kdError()<<k_funcinfo<<"No parent, can not add subtask: "<<task->name()<<endl;
00590       return false;
00591     }
00592     position->addChildNode(task);
00593     return true;
00594 }
00595 
00596 bool Project::canIndentTask(Node* node)
00597 {
00598     if (0 == node) {
00599         // should always be != 0. At least we would get the Project,
00600         // but you never know who might change that, so better be careful
00601         return false;
00602     }
00603     if (node->type() == Node::Type_Project) {
00604         //kdDebug()<<k_funcinfo<<"The root node cannot be indented"<<endl;
00605         return false;
00606     }
00607     // we have to find the parent of task to manipulate its list of children
00608     Node* parentNode = node->getParent();
00609     if ( !parentNode ) {
00610         return false;
00611     }
00612     if (parentNode->findChildNode(node) == -1) {
00613         kdError()<<k_funcinfo<<"Tasknot found???"<<endl;
00614         return false;
00615     }
00616     Node *sib = node->siblingBefore();
00617     if (!sib) {
00618         //kdDebug()<<k_funcinfo<<"new parent node not found"<<endl;
00619         return false;
00620     }
00621     if (node->findParentRelation(sib) || node->findChildRelation(sib)) {
00622         //kdDebug()<<k_funcinfo<<"Cannot have relations to parent"<<endl;
00623         return false;
00624     }
00625     return true;
00626 }
00627 
00628 bool Project::indentTask( Node* node )
00629 {
00630     if (canIndentTask(node)) {
00631         Node *newParent = node->siblingBefore();
00632         node->getParent()->delChildNode(node, false/*do not delete objekt*/);
00633         newParent->addChildNode(node);
00634         return true;
00635     }
00636     return false;
00637 }
00638 
00639 bool Project::canUnindentTask( Node* node )
00640 {
00641     if ( 0 == node ) {
00642         // is always != 0. At least we would get the Project, but you
00643         // never know who might change that, so better be careful
00644         return false;
00645     }
00646     if ( Node::Type_Project == node->type() ) {
00647         //kdDebug()<<k_funcinfo<<"The root node cannot be unindented"<<endl;
00648         return false;
00649     }
00650     // we have to find the parent of task to manipulate its list of children
00651     // and we need the parent's parent too
00652     Node* parentNode = node->getParent();
00653     if ( !parentNode ) {
00654         return false;
00655     }
00656     Node* grandParentNode = parentNode->getParent();
00657     if ( !grandParentNode ) {
00658         //kdDebug()<<k_funcinfo<<"This node already is at the top level"<<endl;
00659         return false;
00660     }
00661     int index = parentNode->findChildNode( node );
00662     if ( -1 == index ) {
00663         kdError()<<k_funcinfo<<"Tasknot found???"<<endl;
00664         return false;
00665     }
00666     return true;
00667 }
00668 
00669 bool Project::unindentTask( Node* node )
00670 {
00671     if (canUnindentTask(node)) {
00672         Node *parentNode = node->getParent();
00673         Node *grandParentNode = parentNode->getParent();
00674         parentNode->delChildNode(node, false/*do not delete objekt*/);
00675         grandParentNode->addChildNode(node,parentNode);
00676         return true;
00677     }
00678     return false;
00679 }
00680 
00681 bool Project::canMoveTaskUp( Node* node )
00682 {
00683     if (node == 0)
00684         return false; // safety
00685     // we have to find the parent of task to manipulate its list of children
00686     Node* parentNode = node->getParent();
00687     if (!parentNode) {
00688         //kdDebug()<<k_funcinfo<<"No parent found"<<endl;
00689         return false;
00690     }
00691     if (parentNode->findChildNode(node) == -1) {
00692         kdError()<<k_funcinfo<<"Tasknot found???"<<endl;
00693         return false;
00694     }
00695     if (node->siblingBefore()) {
00696         return true;
00697     }
00698     return false;
00699 }
00700 
00701 bool Project::moveTaskUp( Node* node )
00702 {
00703     if (canMoveTaskUp(node)) {
00704         return node->getParent()->moveChildUp(node);
00705     }
00706     return false;
00707 }
00708 
00709 bool Project::canMoveTaskDown( Node* node )
00710 {
00711     if (node == 0)
00712         return false; // safety
00713     // we have to find the parent of task to manipulate its list of children
00714     Node* parentNode = node->getParent();
00715     if (!parentNode) {
00716         return false;
00717     }
00718     if (parentNode->findChildNode(node) == -1) {
00719         kdError()<<k_funcinfo<<"Tasknot found???"<<endl;
00720         return false;
00721     }
00722     if (node->siblingAfter()) {
00723         return true;
00724     }
00725     return false;
00726 }
00727 
00728 bool Project::moveTaskDown( Node* node )
00729 {
00730     if (canMoveTaskDown(node)) {
00731         return node->getParent()->moveChildDown(node);
00732     }
00733     return false;
00734 }
00735 
00736 Task *Project::createTask(Node* parent) {
00737     Task* node = new Task(parent);
00738     node->setId(uniqueNodeId());
00739     return node;
00740 }
00741 
00742 Task *Project::createTask(Task &def, Node* parent) {
00743     Task* node = new Task(def, parent);
00744     node->setId(uniqueNodeId());
00745     return node;
00746 }
00747 
00748 QString Project::uniqueNodeId(int seed) {
00749     int i = seed;
00750     while (findNode(QString("%1").arg(i))) {
00751         ++i;
00752     }
00753     return QString("%1").arg(i);
00754 }
00755 
00756 ResourceGroup *Project::group(QString id) {
00757     return findResourceGroup(id);
00758 }
00759 
00760 Resource *Project::resource(QString id) {
00761     return findResource(id);
00762 }
00763 
00764 // TODO
00765 EffortCostMap Project::plannedEffortCostPrDay(const QDate &/*start*/, const QDate &/*end*/) const {
00766     //kdDebug()<<k_funcinfo<<endl;
00767     EffortCostMap ec;
00768     return ec;
00769 
00770 }
00771 
00772 // Returns the total planned effort for this project (or subproject) 
00773 Duration Project::plannedEffort() {
00774    //kdDebug()<<k_funcinfo<<endl;
00775     Duration eff;
00776     QPtrListIterator<Node> it(childNodeIterator());
00777     for (; it.current(); ++it) {
00778         eff += it.current()->plannedEffort();
00779     }
00780     return eff;
00781 }
00782 
00783 // Returns the total planned effort for this project (or subproject) on date
00784 Duration Project::plannedEffort(const QDate &date) {
00785    //kdDebug()<<k_funcinfo<<endl;
00786     Duration eff;
00787     QPtrListIterator<Node> it(childNodeIterator());
00788     for (; it.current(); ++it) {
00789         eff += it.current()->plannedEffort(date);
00790     }
00791     return eff;
00792 }
00793 
00794 // Returns the total planned effort for this project (or subproject) upto and including date
00795 Duration Project::plannedEffortTo(const QDate &date) {
00796    //kdDebug()<<k_funcinfo<<endl;
00797     Duration eff;
00798     QPtrListIterator<Node> it(childNodeIterator());
00799     for (; it.current(); ++it) {
00800         eff += it.current()->plannedEffortTo(date);
00801     }
00802     return eff;
00803 }
00804 
00805 // Returns the total actual effort for this project (or subproject) 
00806 Duration Project::actualEffort() {
00807    //kdDebug()<<k_funcinfo<<endl;
00808     Duration eff;
00809     QPtrListIterator<Node> it(childNodeIterator());
00810     for (; it.current(); ++it) {
00811         eff += it.current()->actualEffort();
00812     }
00813     return eff;
00814 }
00815 
00816 // Returns the total actual effort for this project (or subproject) on date
00817 Duration Project::actualEffort(const QDate &date) {
00818    //kdDebug()<<k_funcinfo<<endl;
00819     Duration eff;
00820     QPtrListIterator<Node> it(childNodeIterator());
00821     for (; it.current(); ++it) {
00822         eff += it.current()->actualEffort(date);
00823     }
00824     return eff;
00825 }
00826 
00827 // Returns the total actual effort for this project (or subproject) upto and including date
00828 Duration Project::actualEffortTo(const QDate &date) {
00829    //kdDebug()<<k_funcinfo<<endl;
00830     Duration eff;
00831     QPtrListIterator<Node> it(childNodeIterator());
00832     for (; it.current(); ++it) {
00833         eff += it.current()->actualEffortTo(date);
00834     }
00835     return eff;
00836 }
00837 
00838 double Project::plannedCost() {
00839     //kdDebug()<<k_funcinfo<<endl;
00840     double c = 0;
00841     QPtrListIterator<Node> it(childNodeIterator());
00842     for (; it.current(); ++it) {
00843         c += it.current()->plannedCost();
00844     }
00845     return c;
00846 }
00847 
00848 // Returns the total planned effort for this project (or subproject) on date
00849 double Project::plannedCost(const QDate &date) {
00850    //kdDebug()<<k_funcinfo<<endl;
00851     double c = 0;
00852     QPtrListIterator<Node> it(childNodeIterator());
00853     for (; it.current(); ++it) {
00854         c += it.current()->plannedCost(date);
00855     }
00856     return c;
00857 }
00858 
00859 // Returns the total planned effort for this project (or subproject) upto and including date
00860 double Project::plannedCostTo(const QDate &date) {
00861    //kdDebug()<<k_funcinfo<<endl;
00862     double c = 0;
00863     QPtrListIterator<Node> it(childNodeIterator());
00864     for (; it.current(); ++it) {
00865         c += it.current()->plannedCostTo(date);
00866     }
00867     return c;
00868 }
00869 
00870 double Project::actualCost() {
00871     //kdDebug()<<k_funcinfo<<endl;
00872     double c = 0;
00873     QPtrListIterator<Node> it(childNodeIterator());
00874     for (; it.current(); ++it) {
00875         c += it.current()->actualCost();
00876     }
00877     return c;
00878 }
00879 
00880 // Returns the total planned effort for this project (or subproject) on date
00881 double Project::actualCost(const QDate &date) {
00882    //kdDebug()<<k_funcinfo<<endl;
00883     double c = 0;
00884     QPtrListIterator<Node> it(childNodeIterator());
00885     for (; it.current(); ++it) {
00886         c += it.current()->actualCost(date);
00887     }
00888     return c;
00889 }
00890 
00891 // Returns the total planned effort for this project (or subproject) upto and including date
00892 double Project::actualCostTo(const QDate &date) {
00893    //kdDebug()<<k_funcinfo<<endl;
00894     double c = 0;
00895     QPtrListIterator<Node> it(childNodeIterator());
00896     for (; it.current(); ++it) {
00897         c += it.current()->actualCostTo(date);
00898     }
00899     return c;
00900 }
00901 
00902 void Project::addCalendar(Calendar *calendar) {
00903     //kdDebug()<<k_funcinfo<<calendar->name()<<endl;
00904     m_calendars.append(calendar);
00905 }
00906 
00907 Calendar *Project::calendar(const QString id) const {
00908     return findCalendar(id);
00909 }
00910 
00911 QPtrList<Calendar> Project::calendars() {
00912     QPtrList<Calendar> list;
00913     QPtrListIterator<Calendar> it = m_calendars;
00914     for (; it.current(); ++it) {
00915         if (!it.current()->isDeleted()) {
00916             list.append(it.current());
00917         }
00918     }
00919     return list;
00920 }
00921 
00922 void Project::setStandardWorktime(StandardWorktime * worktime) {
00923     if (m_standardWorktime != worktime) {
00924         delete m_standardWorktime; 
00925         m_standardWorktime = worktime; 
00926     }
00927 }
00928 
00929 void Project::setDefaultCalendar(Calendar *cal) {
00930     m_defaultCalendar = cal;
00931 }
00932 
00933 bool Project::legalToLink(Node *par, Node *child) {
00934     //kdDebug()<<k_funcinfo<<par.name()<<" ("<<par.numDependParentNodes()<<" parents) "<<child.name()<<" ("<<child.numDependChildNodes()<<" children)"<<endl;
00935     
00936     if (!child || par->isDependChildOf(child)) {
00937         return false;
00938     }
00939     bool legal = true;
00940     // see if par/child is related
00941     if (par->isParentOf(child) || child->isParentOf(par)) {
00942         legal = false;
00943     }
00944     if (legal)
00945         legal = legalChildren(par, child);
00946     if (legal)
00947         legal = legalParents(par, child);
00948     
00949     return legal;
00950 }
00951 
00952 bool Project::legalParents(Node *par, Node *child) {
00953     bool legal = true;
00954     //kdDebug()<<k_funcinfo<<par->name()<<" ("<<par->numDependParentNodes()<<" parents) "<<child->name()<<" ("<<child->numDependChildNodes()<<" children)"<<endl;
00955     for (int i=0; i < par->numDependParentNodes() && legal; ++i) {
00956         Node *pNode = par->getDependParentNode(i)->parent();
00957         if (child->isParentOf(pNode) || pNode->isParentOf(child)) {
00958             //kdDebug()<<k_funcinfo<<"Found: "<<pNode->name()<<" is related to "<<child->name()<<endl;
00959             legal = false;
00960         } else {
00961             legal = legalChildren(pNode, child);
00962         }
00963         if (legal)
00964             legal = legalParents(pNode, child);
00965     }
00966     return legal;
00967 }
00968 
00969 bool Project::legalChildren(Node *par, Node *child) {
00970     bool legal = true;
00971     //kdDebug()<<k_funcinfo<<par->name()<<" ("<<par->numDependParentNodes()<<" parents) "<<child->name()<<" ("<<child->numDependChildNodes()<<" children)"<<endl;
00972     for (int j=0; j < child->numDependChildNodes() && legal; ++j) {
00973         Node *cNode = child->getDependChildNode(j)->child();
00974         if (par->isParentOf(cNode) || cNode->isParentOf(par)) {
00975             //kdDebug()<<k_funcinfo<<"Found: "<<par->name()<<" is related to "<<cNode->name()<<endl;
00976             legal = false;
00977         } else {
00978             legal = legalChildren(par, cNode);
00979         }
00980     }
00981     return legal;
00982 }
00983 
00984 void Project::generateWBS(int count, WBSDefinition &def, QString wbs) {
00985     if (type() == Type_Subproject || def.level0Enabled()) {
00986         Node::generateWBS(count, def, wbs);
00987     } else {
00988         QPtrListIterator<Node> it = m_nodes;
00989         for (int i=0; it.current(); ++it) {
00990             it.current()->generateWBS(++i, def, m_wbs);
00991         }
00992     }
00993 }
00994 
00995 void Project::setCurrentSchedule(long id) {
00996     setCurrentSchedulePtr(findSchedule(id));
00997     Node::setCurrentSchedule(id);
00998     QDictIterator<Resource> it = resourceIdDict;
00999     for (; it.current(); ++it) {
01000         it.current()->setCurrentSchedule(id);
01001     }
01002 }
01003 
01004 MainSchedule *Project::createSchedule(QString name, Schedule::Type type) {
01005     //kdDebug()<<k_funcinfo<<"No of schedules: "<<m_schedules.count()<<endl;
01006     long i=1;
01007     while (m_schedules.find(i)) {
01008         ++i;
01009     }
01010     MainSchedule *sch = new MainSchedule(this, name, type, i);
01011     addSchedule(sch);
01012     return sch;
01013 }
01014 
01015 #ifndef NDEBUG
01016 void Project::printDebug(bool children, QCString indent) {
01017 
01018     kdDebug()<<indent<<"+ Project node: "<<name()<<endl;
01019     indent += "!";
01020     QPtrListIterator<ResourceGroup> it(resourceGroups());
01021     for ( ; it.current(); ++it)
01022         it.current()->printDebug(indent);
01023 
01024     Node::printDebug(children, indent);
01025 }
01026 void Project::printCalendarDebug(QCString indent) {
01027     kdDebug()<<indent<<"-------- Calendars debug printout --------"<<endl;
01028     QPtrListIterator<Calendar> it = m_calendars;
01029     for (; it.current(); ++it) {
01030         it.current()->printDebug(indent + "--");
01031         kdDebug()<<endl;
01032     }
01033     if (m_standardWorktime)
01034         m_standardWorktime->printDebug();
01035 }
01036 #endif
01037 
01038 }  //KPlato namespace
KDE Home | KDE Accessibility Home | Description of Access Keys