00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kptschedule.h"
00021
00022 #include "kptappointment.h"
00023 #include "kptdatetime.h"
00024 #include "kptduration.h"
00025 #include "kptnode.h"
00026
00027 #include <QDomElement>
00028 #include <QString>
00029 #include <QStringList>
00030
00031 #include <klocale.h>
00032 #include <kdebug.h>
00033
00034 namespace KPlato
00035 {
00036
00037 Schedule::Schedule()
00038 : m_type( Expected ),
00039 m_id( 0 ),
00040 m_deleted( false ),
00041 m_parent( 0 )
00042 {}
00043
00044 Schedule::Schedule( Schedule *parent )
00045 : m_type( Expected ),
00046 m_id( 0 ),
00047 m_deleted( false ),
00048 m_appointments(),
00049 m_parent( parent )
00050 {
00051
00052 if ( parent ) {
00053 m_name = parent->name();
00054 m_type = parent->type();
00055 m_id = parent->id();
00056 }
00057
00058 }
00059
00060 Schedule::Schedule( QString name, Type type, long id )
00061 : m_name( name ),
00062 m_type( type ),
00063 m_id( id ),
00064 m_deleted( false ),
00065 m_appointments(),
00066 m_parent( 0 )
00067 {
00068
00069
00070 }
00071
00072 Schedule::~Schedule()
00073 {
00074
00075 while ( !m_appointments.isEmpty() )
00076 delete m_appointments.takeFirst();
00077 }
00078
00079 void Schedule::setParent( Schedule *parent )
00080 {
00081 m_parent = parent;
00082 }
00083
00084 void Schedule::setDeleted( bool on )
00085 {
00086
00087 m_deleted = on;
00088 }
00089
00090 bool Schedule::isDeleted() const
00091 {
00092 return m_parent == 0 ? m_deleted : m_parent->isDeleted();
00093 }
00094
00095 void Schedule::setType( const QString type )
00096 {
00097 m_type = Expected;
00098 if ( type == "Expected" )
00099 m_type = Expected;
00100 else if ( type == "Optimistic" )
00101 m_type = Optimistic;
00102 else if ( type == "Pessimistic" )
00103 m_type = Pessimistic;
00104 }
00105
00106 QString Schedule::typeToString( bool translate ) const
00107 {
00108 if ( translate ) {
00109 if ( m_type == Expected )
00110 return i18n( "Expected" );
00111 if ( m_type == Optimistic )
00112 return i18n( "Optimistic" );
00113 if ( m_type == Pessimistic )
00114 return i18n( "Pessimistic" );
00115 return i18n( "Expected" );
00116 } else {
00117 if ( m_type == Expected )
00118 return "Expected";
00119 if ( m_type == Optimistic )
00120 return "Optimistic";
00121 if ( m_type == Pessimistic )
00122 return "Pessimistic";
00123 return "Expected";
00124 }
00125 }
00126
00127 void Schedule::initiateCalculation()
00128 {
00129 resourceError = false;
00130 resourceOverbooked = false;
00131 schedulingError = false;
00132 inCriticalPath = false;
00133 workStartTime = DateTime();
00134 workEndTime = DateTime();
00135 }
00136
00137 void Schedule::calcResourceOverbooked()
00138 {
00139 resourceOverbooked = false;
00140 QListIterator<Appointment*> it = m_appointments;
00141 while ( it.hasNext() ) {
00142 if ( it.next() ->resource() ->isOverbooked( startTime, endTime ) ) {
00143 resourceOverbooked = true;
00144 break;
00145 }
00146 }
00147 }
00148
00149 QStringList Schedule::overbookedResources() const
00150 {
00151 QStringList rl;
00152 QListIterator<Appointment*> it = m_appointments;
00153 while ( it.hasNext() ) {
00154 Appointment * a = it.next();
00155 if ( a->resource() ->isOverbooked( a->startTime(), a->endTime() ) ) {
00156 rl += a->resource() ->resource() ->name();
00157 }
00158 }
00159 return rl;
00160 }
00161
00162 bool Schedule::loadXML( const QDomElement &sch )
00163 {
00164 m_name = sch.attribute( "name" );
00165 setType( sch.attribute( "type" ) );
00166 m_id = sch.attribute( "id" ).toLong();
00167
00168 return true;
00169 }
00170
00171 void Schedule::saveXML( QDomElement &element ) const
00172 {
00173 QDomElement sch = element.ownerDocument().createElement( "schedule" );
00174 element.appendChild( sch );
00175 saveCommonXML( sch );
00176 }
00177
00178 void Schedule::saveCommonXML( QDomElement &element ) const
00179 {
00180
00181 element.setAttribute( "name", m_name );
00182 element.setAttribute( "type", typeToString() );
00183 element.setAttribute( "id", qlonglong( m_id ) );
00184 }
00185
00186 void Schedule::saveAppointments( QDomElement &element ) const
00187 {
00188
00189 QListIterator<Appointment*> it = m_appointments;
00190 while ( it.hasNext() ) {
00191 it.next() ->saveXML( element );
00192 }
00193 }
00194
00195 bool Schedule::add( Appointment *appointment )
00196 {
00197 if ( m_appointments.indexOf( appointment ) != -1 ) {
00198 kError() << k_funcinfo << "Appointment already exists" << endl;
00199 return false;
00200 }
00201 m_appointments.append( appointment );
00202
00203
00204 return true;
00205 }
00206
00207 void Schedule::removeAppointment( Appointment *appointment )
00208 {
00209 takeAppointment( appointment );
00210 delete appointment;
00211 }
00212
00213 void Schedule::takeAppointment( Appointment *appointment )
00214 {}
00215
00216 Appointment *Schedule::findAppointment( Schedule *resource, Schedule *node )
00217 {
00218 QListIterator<Appointment*> it = m_appointments;
00219 while ( it.hasNext() ) {
00220 Appointment * a = it.next();
00221 if ( a->node() == node && a->resource() == resource )
00222 return a;
00223 }
00224 return 0;
00225 }
00226
00227 EffortCostMap Schedule::plannedEffortCostPrDay( const QDate &start, const QDate &end ) const
00228 {
00229
00230 EffortCostMap ec;
00231 QListIterator<Appointment*> it( m_appointments );
00232 while ( it.hasNext() ) {
00233
00234 ec += it.next() ->plannedPrDay( start, end );
00235 }
00236 return ec;
00237 }
00238
00239 Duration Schedule::plannedEffort() const
00240 {
00241
00242 Duration eff;
00243 QListIterator<Appointment*> it( m_appointments );
00244 while ( it.hasNext() ) {
00245 eff += it.next() ->plannedEffort();
00246 }
00247 return eff;
00248 }
00249
00250 Duration Schedule::plannedEffort( const QDate &date ) const
00251 {
00252
00253 Duration eff;
00254 QListIterator<Appointment*> it( m_appointments );
00255 while ( it.hasNext() ) {
00256 eff += it.next() ->plannedEffort( date );
00257 }
00258 return eff;
00259 }
00260
00261 Duration Schedule::plannedEffortTo( const QDate &date ) const
00262 {
00263
00264 Duration eff;
00265 QListIterator<Appointment*> it( m_appointments );
00266 while ( it.hasNext() ) {
00267 eff += it.next() ->plannedEffortTo( date );
00268 }
00269 return eff;
00270 }
00271
00272 Duration Schedule::actualEffort() const
00273 {
00274
00275 Duration eff;
00276 QListIterator<Appointment*> it( m_appointments );
00277 while ( it.hasNext() ) {
00278 eff += it.next() ->actualEffort();
00279 }
00280 return eff;
00281 }
00282
00283 Duration Schedule::actualEffort( const QDate &date ) const
00284 {
00285
00286 Duration eff;
00287 QListIterator<Appointment*> it( m_appointments );
00288 while ( it.hasNext() ) {
00289 eff += it.next() ->actualEffort( date );
00290 }
00291 return eff;
00292 }
00293
00294 Duration Schedule::actualEffortTo( const QDate &date ) const
00295 {
00296
00297 Duration eff;
00298 QListIterator<Appointment*> it( m_appointments );
00299 while ( it.hasNext() ) {
00300 eff += it.next() ->actualEffortTo( date );
00301 }
00302 return eff;
00303 }
00304
00305 double Schedule::plannedCost() const
00306 {
00307
00308 double c = 0;
00309 QListIterator<Appointment*> it( m_appointments );
00310 while ( it.hasNext() ) {
00311 c += it.next() ->plannedCost();
00312 }
00313 return c;
00314 }
00315
00316 double Schedule::plannedCost( const QDate &date ) const
00317 {
00318
00319 double c = 0;
00320 QListIterator<Appointment*> it( m_appointments );
00321 while ( it.hasNext() ) {
00322 c += it.next() ->plannedCost( date );
00323 }
00324 return c;
00325 }
00326
00327 double Schedule::plannedCostTo( const QDate &date ) const
00328 {
00329
00330 double c = 0;
00331 QListIterator<Appointment*> it( m_appointments );
00332 while ( it.hasNext() ) {
00333 c += it.next() ->plannedCostTo( date );
00334 }
00335 return c;
00336 }
00337
00338 double Schedule::actualCost() const
00339 {
00340
00341 double c = 0;
00342 QListIterator<Appointment*> it( m_appointments );
00343 while ( it.hasNext() ) {
00344 c += it.next() ->actualCost();
00345 }
00346 return c;
00347 }
00348
00349 double Schedule::actualCost( const QDate &date ) const
00350 {
00351
00352 double c = 0;
00353 QListIterator<Appointment*> it( m_appointments );
00354 while ( it.hasNext() ) {
00355 c += it.next() ->actualCost( date );
00356 }
00357 return c;
00358 }
00359
00360 double Schedule::actualCostTo( const QDate &date ) const
00361 {
00362
00363 double c = 0;
00364 QListIterator<Appointment*> it( m_appointments );
00365 while ( it.hasNext() ) {
00366 c += it.next() ->actualCostTo( date );
00367 }
00368 return c;
00369 }
00370
00371
00372 NodeSchedule::NodeSchedule()
00373 : Schedule(),
00374 m_node( 0 )
00375 {
00376
00377 init();
00378 }
00379
00380 NodeSchedule::NodeSchedule( Node *node, QString name, Schedule::Type type, long id )
00381 : Schedule( name, type, id ),
00382 m_node( node )
00383 {
00384
00385 init();
00386 }
00387
00388 NodeSchedule::NodeSchedule( Schedule *parent, Node *node )
00389 : Schedule( parent ),
00390 m_node( node )
00391 {
00392
00393
00394 init();
00395 }
00396
00397 NodeSchedule::~NodeSchedule()
00398 {
00399
00400 }
00401
00402 void NodeSchedule::init()
00403 {
00404 resourceError = false;
00405 resourceOverbooked = false;
00406 resourceNotAvailable = false;
00407 schedulingError = false;
00408 notScheduled = true;
00409 inCriticalPath = false;
00410 }
00411
00412 void NodeSchedule::setDeleted( bool on )
00413 {
00414
00415 m_deleted = on;
00416
00417 QListIterator<Appointment*> it = m_appointments;
00418 while ( it.hasNext() ) {
00419 Appointment * a = it.next();
00420 if ( a->resource() ) {
00421 a->resource() ->setDeleted( on );
00422 }
00423 }
00424 }
00425
00426 bool NodeSchedule::loadXML( const QDomElement &sch )
00427 {
00428
00429 QString s;
00430 Schedule::loadXML( sch );
00431 s = sch.attribute( "earlieststart" );
00432 if ( s != "" )
00433 earliestStart = DateTime::fromString( s );
00434 s = sch.attribute( "latestfinish" );
00435 if ( s != "" )
00436 latestFinish = DateTime::fromString( s );
00437 s = sch.attribute( "start" );
00438 if ( s != "" )
00439 startTime = DateTime::fromString( s );
00440 s = sch.attribute( "end" );
00441 if ( s != "" )
00442 endTime = DateTime::fromString( s );
00443 s = sch.attribute( "start-work" );
00444 if ( s != "" )
00445 workStartTime = DateTime::fromString( s );
00446 s = sch.attribute( "end-work" );
00447 if ( s != "" )
00448 workEndTime = DateTime::fromString( s );
00449 duration = Duration::fromString( sch.attribute( "duration" ) );
00450
00451 inCriticalPath = sch.attribute( "in-critical-path", "0" ).toInt();
00452 resourceError = sch.attribute( "resource-error", "0" ).toInt();
00453 resourceOverbooked = sch.attribute( "resource-overbooked", "0" ).toInt();
00454 resourceNotAvailable = sch.attribute( "resource-not-available", "0" ).toInt();
00455 schedulingError = sch.attribute( "scheduling-conflict", "0" ).toInt();
00456 notScheduled = sch.attribute( "not-scheduled", "1" ).toInt();
00457
00458 return true;
00459 }
00460
00461 void NodeSchedule::saveXML( QDomElement &element ) const
00462 {
00463
00464 QDomElement sch = element.ownerDocument().createElement( "schedule" );
00465 element.appendChild( sch );
00466 saveCommonXML( sch );
00467
00468 if ( earliestStart.isValid() )
00469 sch.setAttribute( "earlieststart", earliestStart.toString( Qt::ISODate ) );
00470 if ( latestFinish.isValid() )
00471 sch.setAttribute( "latestfinish", latestFinish.toString( Qt::ISODate ) );
00472 if ( startTime.isValid() )
00473 sch.setAttribute( "start", startTime.toString( Qt::ISODate ) );
00474 if ( endTime.isValid() )
00475 sch.setAttribute( "end", endTime.toString( Qt::ISODate ) );
00476 if ( workStartTime.isValid() )
00477 sch.setAttribute( "start-work", workStartTime.toString( Qt::ISODate ) );
00478 if ( workEndTime.isValid() )
00479 sch.setAttribute( "end-work", workEndTime.toString( Qt::ISODate ) );
00480
00481 sch.setAttribute( "duration", duration.toString() );
00482
00483 sch.setAttribute( "in-critical-path", inCriticalPath );
00484 sch.setAttribute( "resource-error", resourceError );
00485 sch.setAttribute( "resource-overbooked", resourceOverbooked );
00486 sch.setAttribute( "resource-not-available", resourceNotAvailable );
00487 sch.setAttribute( "scheduling-conflict", schedulingError );
00488 sch.setAttribute( "not-scheduled", notScheduled );
00489 }
00490
00491 void NodeSchedule::addAppointment( Schedule *resource, DateTime &start, DateTime &end, double load )
00492 {
00493
00494 Appointment * a = findAppointment( resource, this );
00495 if ( a != 0 ) {
00496
00497 a->addInterval( start, end, load );
00498 return ;
00499 }
00500 a = new Appointment( resource, this, start, end, load );
00501 if ( !add( a ) && !resource->add( a ) )
00502 delete a;
00503 }
00504
00505 void NodeSchedule::takeAppointment( Appointment *appointment )
00506 {
00507 int i = m_appointments.indexOf( appointment );
00508 if ( i != -1 ) {
00509 m_appointments.removeAt( i );
00510
00511 if ( appointment->resource() )
00512 appointment->resource() ->takeAppointment( appointment );
00513 } else {
00514
00515 }
00516 }
00517
00518
00519 ResourceSchedule::ResourceSchedule()
00520 : Schedule(),
00521 m_resource( 0 )
00522 {
00523
00524 }
00525
00526 ResourceSchedule::ResourceSchedule( Resource *resource, QString name, Schedule::Type type, long id )
00527 : Schedule( name, type, id ),
00528 m_resource( resource ),
00529 m_parent( 0 )
00530 {
00531
00532 }
00533
00534 ResourceSchedule::ResourceSchedule( Schedule *parent, Resource *resource )
00535 : Schedule( parent ),
00536 m_resource( resource ),
00537 m_parent( parent )
00538 {
00539
00540 }
00541
00542 ResourceSchedule::~ResourceSchedule()
00543 {
00544
00545 }
00546
00547 void ResourceSchedule::addAppointment( Schedule *node, DateTime &start, DateTime &end, double load )
00548 {
00549
00550 Appointment * a = findAppointment( this, node );
00551 if ( a != 0 ) {
00552
00553 a->addInterval( start, end, load );
00554 return ;
00555 }
00556 a = new Appointment( this, node, start, end, load );
00557 if ( !add( a ) && !node->add( a ) )
00558 delete a;
00559 }
00560
00561 void ResourceSchedule::takeAppointment( Appointment *appointment )
00562 {
00563 int i = m_appointments.indexOf( appointment );
00564 if ( i != -1 ) {
00565 m_appointments.removeAt( i );
00566
00567 if ( appointment->node() )
00568 appointment->node() ->takeAppointment( appointment );
00569 } else {
00570
00571 }
00572 }
00573
00574 bool ResourceSchedule::isOverbooked() const
00575 {
00576 return false;
00577 }
00578
00579 bool ResourceSchedule::isOverbooked( const DateTime &start, const DateTime &end ) const
00580 {
00581 if ( m_resource == 0 )
00582 return false;
00583
00584 Appointment a = appointmentIntervals();
00585 QListIterator<AppointmentInterval*> it = a.intervals();
00586 while ( it.hasNext() ) {
00587 AppointmentInterval * i = it.next();
00588 if ( ( !end.isValid() || i->startTime() < end ) &&
00589 ( !start.isValid() || i->endTime() > start ) ) {
00590 if ( i->load() > m_resource->units() ) {
00591
00592 return true;
00593 }
00594 }
00595 if ( i->startTime() >= end )
00596 break;
00597 }
00598
00599 return false;
00600 }
00601
00602 Appointment ResourceSchedule::appointmentIntervals() const
00603 {
00604 Appointment a;
00605 QListIterator<Appointment*> it = m_appointments;
00606 while ( it.hasNext() ) {
00607 a += *( it.next() );
00608 }
00609 return a;
00610 }
00611
00612 double ResourceSchedule::normalRatePrHour() const
00613 {
00614 return m_resource ? m_resource->normalRate() : 0.0;
00615 }
00616
00617
00618 MainSchedule::MainSchedule()
00619 : NodeSchedule()
00620 {
00621
00622 init();
00623 }
00624
00625 MainSchedule::MainSchedule( Node *node, QString name, Schedule::Type type, long id )
00626 : NodeSchedule( node, name, type, id )
00627 {
00628
00629 init();
00630 }
00631
00632 MainSchedule::~MainSchedule()
00633 {
00634
00635 }
00636
00637 bool MainSchedule::loadXML( const QDomElement &sch, Project &project )
00638 {
00639
00640 QString s;
00641 Schedule::loadXML( sch );
00642
00643 s = sch.attribute( "start" );
00644 if ( s != "" )
00645 startTime = DateTime::fromString( s );
00646 s = sch.attribute( "end" );
00647 if ( s != "" )
00648 endTime = DateTime::fromString( s );
00649
00650 QDomNodeList al = sch.childNodes();
00651
00652 for ( unsigned int i = 0; i < al.count(); ++i ) {
00653 if ( al.item( i ).isElement() ) {
00654 QDomElement app = al.item( i ).toElement();
00655 if ( app.tagName() == "appointment" ) {
00656
00657
00658 Appointment * child = new Appointment();
00659 if ( !child->loadXML( app, project, *this ) ) {
00660
00661 kError() << k_funcinfo << "Failed to load appointment" << endl;
00662 delete child;
00663 }
00664 }
00665 }
00666 }
00667 return true;
00668 }
00669
00670 void MainSchedule::saveXML( QDomElement &element ) const
00671 {
00672 saveCommonXML( element );
00673
00674 element.setAttribute( "start", startTime.toString( Qt::ISODate ) );
00675 element.setAttribute( "end", endTime.toString( Qt::ISODate ) );
00676 }
00677
00678 #ifndef NDEBUG
00679 void Schedule::printDebug( QString indent )
00680 {
00681 kDebug() << indent << "Schedule[" << m_id << "] '" << m_name << "' type: " << typeToString() << " (" << m_type << ")" << ( isDeleted() ? " Deleted" : "" ) << endl;
00682 }
00683 void NodeSchedule::printDebug( QString indent )
00684 {
00685 Schedule::printDebug( indent );
00686 indent += "! ";
00687 if ( m_parent == 0 )
00688 kDebug() << indent << "No parent schedule!" << endl;
00689 if ( !notScheduled ) {
00690
00691
00692
00693
00694
00695 }
00696 kDebug() << indent << "Not scheduled=" << notScheduled << endl;
00697 kDebug() << indent << "Start time: " << startTime.toString() << endl;
00698 kDebug() << indent << "End time: " << endTime.toString() << endl;
00699 kDebug() << indent << "Duration: " << duration.seconds() << QByteArray( " secs" ) << " (" << duration.toString() << ")" << endl;
00700 kDebug() << indent << "Earliest start: " << earliestStart.toString() << endl;
00701 kDebug() << indent << "Latest finish: " << latestFinish.toString() << endl;
00702
00703 kDebug() << indent << "Resource overbooked=" << resourceOverbooked << endl;
00704 kDebug() << indent << "resourceError=" << resourceError << endl;
00705 kDebug() << indent << "schedulingError=" << schedulingError << endl;
00706 kDebug() << indent << "resourceNotAvailable=" << resourceNotAvailable << endl;
00707 kDebug() << indent << "Resource overbooked=" << resourceOverbooked << endl;
00708 kDebug() << indent << " " << overbookedResources() << endl;
00709
00710 kDebug() << indent << "inCriticalPath=" << inCriticalPath << endl;
00711 kDebug() << indent << endl;
00712 kDebug() << indent << "workStartTime=" << workStartTime.toString() << endl;
00713 kDebug() << indent << "workEndTime=" << workEndTime.toString() << endl;
00714 kDebug() << indent << endl;
00715 kDebug() << indent << "Appointments: " << m_appointments.count() << endl;
00716 QListIterator<Appointment*> it = m_appointments;
00717 while ( it.hasNext() ) {
00718 it.next() ->printDebug( indent + " " );
00719 }
00720 }
00721 void ResourceSchedule::printDebug( QString indent )
00722 {
00723 Schedule::printDebug( indent );
00724 indent += "! ";
00725 if ( m_parent == 0 )
00726 kDebug() << indent << "No parent schedule!" << endl;
00727 if ( resource() )
00728 kDebug() << indent << "Resource: " << resource() ->name() << endl;
00729 else
00730 kDebug() << indent << "No parent resource!" << endl;
00731 kDebug() << indent << endl;
00732 kDebug() << indent << "Appointments: " << m_appointments.count() << endl;
00733 }
00734
00735 void MainSchedule::printDebug( QString indent )
00736 {
00737 Schedule::printDebug( indent );
00738 indent += "! ";
00739
00740
00741
00742
00743
00744
00745 kDebug() << indent << "Not scheduled=" << notScheduled << endl;
00746 kDebug() << indent << "Start time: " << startTime.toString() << endl;
00747 kDebug() << indent << "End time: " << endTime.toString() << endl;
00748 kDebug() << indent << "Duration: " << duration.seconds() << QByteArray( " secs" ) << " (" << duration.toString() << ")" << endl;
00749 kDebug() << indent << "Earliest start: " << earliestStart.toString() << endl;
00750 kDebug() << indent << "Latest finish: " << latestFinish.toString() << endl;
00751
00752 kDebug() << indent << endl;
00753 kDebug() << indent << "Appointments: " << m_appointments.count() << endl;
00754 QListIterator<Appointment*> it = m_appointments;
00755 while ( it.hasNext() ) {
00756 it.next() ->printDebug( indent + " " );
00757 }
00758 }
00759 #endif
00760
00761 }
00762