F:/KPlato/koffice/kplato/kptproject.cc

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

Généré le Wed Nov 22 23:40:57 2006 pour KPlato par  doxygen 1.5.1-p1