1
/* This file is part of the KDE project
2
Copyright (C) 2005 - 2011, 2012 Dag Andersen <danders@get2net.dk>
3
Copyright (C) 2016 Dag Andersen <danders@get2net.dk>
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public License
16
along with this library; see the file COPYING.LIB. If not, write to
17
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
Boston, MA 02110-1301, USA.
21
#include "kptschedule.h"
23
#include "kptappointment.h"
24
#include "kptdatetime.h"
25
#include "kptduration.h"
27
#include "kptproject.h"
29
#include "kptxmlloaderobject.h"
30
#include "kptschedulerplugin.h"
33
#include <KoXmlReader.h>
35
#include <KLocalizedString>
37
#include <QStringList>
43
class ScheduleManager;
45
Schedule::Log::Log( const Node *n, int sev, const QString &msg, int ph )
46
: node( n ), resource( 0 ), message( msg ), severity( sev ), phase( ph )
49
// debugPlan<<*this<<nodeId;
52
Schedule::Log::Log( const Node *n, const Resource *r, int sev, const QString &msg, int ph )
53
: node( n ), resource( r ), message( msg ), severity( sev ), phase( ph )
56
// debugPlan<<*this<<resourceId;
59
Schedule::Log::Log( const Log &other )
62
resource = other.resource;
63
message = other.message;
64
severity = other.severity;
68
Schedule::Log &Schedule::Log::operator=( const Schedule::Log &other )
71
resource = other.resource;
72
message = other.message;
73
severity = other.severity;
83
m_obstate( OBS_Parent ),
84
m_calculationMode( Schedule::Scheduling ),
87
initiateCalculation();
90
Schedule::Schedule( Schedule *parent )
95
m_obstate( OBS_Parent ),
96
m_calculationMode( Schedule::Scheduling ),
101
m_name = parent->name();
102
m_type = parent->type();
105
initiateCalculation();
106
//debugPlan<<"("<<this<<") Name: '"<<name<<"' Type="<<type<<" id="<<id;
109
Schedule::Schedule( const QString& name, Type type, long id )
115
m_obstate( OBS_Parent ),
116
m_calculationMode( Schedule::Scheduling ),
119
//debugPlan<<"("<<this<<") Name: '"<<name<<"' Type="<<type<<" id="<<id;
120
initiateCalculation();
123
Schedule::~Schedule()
127
void Schedule::setParent( Schedule *parent )
132
void Schedule::setDeleted( bool on )
134
//debugPlan<<"deleted="<<on;
136
//changed( this ); don't do this!
139
bool Schedule::isDeleted() const
141
return m_parent == 0 ? m_deleted : m_parent->isDeleted();
144
void Schedule::setType( const QString& type )
147
if ( type == "Expected" )
151
QString Schedule::typeToString( bool translate ) const
154
return i18n( "Expected" );
160
QStringList Schedule::state() const
164
lst << SchedulingState::deleted();
166
lst << SchedulingState::notScheduled();
167
if ( constraintError )
168
lst << SchedulingState::constraintsNotMet();
170
lst << SchedulingState::resourceNotAllocated();
171
if ( resourceNotAvailable )
172
lst << SchedulingState::resourceNotAvailable();
173
if ( resourceOverbooked )
174
lst << SchedulingState::resourceOverbooked();
176
lst << SchedulingState::effortNotMet();
177
if ( schedulingError )
178
lst << SchedulingState::schedulingError();
180
lst << SchedulingState::scheduled();
184
bool Schedule::isBaselined() const
187
return m_parent->isBaselined();
192
bool Schedule::usePert() const
195
return m_parent->usePert();
200
void Schedule::setAllowOverbookingState( Schedule::OBState state )
205
Schedule::OBState Schedule::allowOverbookingState() const
210
bool Schedule::allowOverbooking() const
212
if ( m_obstate == OBS_Parent && m_parent ) {
213
return m_parent->allowOverbooking();
215
return m_obstate == OBS_Allow;
218
bool Schedule::checkExternalAppointments() const
221
return m_parent->checkExternalAppointments();
226
void Schedule::setScheduled( bool on )
232
Duration Schedule::effort( const DateTimeInterval &interval ) const
234
return interval.second - interval.first;
237
DateTimeInterval Schedule::available( const DateTimeInterval &interval ) const
239
return DateTimeInterval( interval.first, interval.second );
242
void Schedule::initiateCalculation()
244
resourceError = false;
245
resourceOverbooked = false;
246
resourceNotAvailable = false;
247
constraintError = false;
248
schedulingError = false;
249
inCriticalPath = false;
250
effortNotMet = false;
251
workStartTime = DateTime();
252
workEndTime = DateTime();
255
void Schedule::calcResourceOverbooked()
257
resourceOverbooked = false;
258
foreach( Appointment *a, m_appointments ) {
259
if ( a->resource() ->isOverbooked( a->startTime(), a->endTime() ) ) {
260
resourceOverbooked = true;
266
DateTimeInterval Schedule::firstBookedInterval( const DateTimeInterval &interval, const Schedule *node ) const
268
QList<Appointment*> lst = m_appointments;
269
switch ( m_calculationMode ) {
270
case CalculateForward: lst = m_forward; break;
271
case CalculateBackward: lst = m_backward; break;
274
foreach ( Appointment *a, lst ) {
275
if ( a->node() == node ) {
276
AppointmentIntervalList i = a->intervals( interval.first, interval.second );
280
return DateTimeInterval( i.map().values().first().startTime(), i.map().values().first().endTime() );
283
return DateTimeInterval();
286
QStringList Schedule::overbookedResources() const
289
foreach( Appointment *a, m_appointments ) {
290
if ( a->resource() ->isOverbooked( a->startTime(), a->endTime() ) ) {
291
rl += a->resource() ->resource() ->name();
297
QStringList Schedule::resourceNameList() const
299
return QStringList();
302
QList<Resource*> Schedule::resources() const
304
return QList<Resource*>();
307
bool Schedule::loadXML( const KoXmlElement &sch, XMLLoaderObject & )
309
m_name = sch.attribute( "name" );
310
setType( sch.attribute( "type" ) );
311
m_id = sch.attribute( "id" ).toLong();
316
void Schedule::saveXML( QDomElement &element ) const
318
QDomElement sch = element.ownerDocument().createElement( "schedule" );
319
element.appendChild( sch );
320
saveCommonXML( sch );
323
void Schedule::saveCommonXML( QDomElement &element ) const
325
//debugPlan<<m_name<<" save schedule";
326
element.setAttribute( "name", m_name );
327
element.setAttribute( "type", typeToString() );
328
element.setAttribute( "id", QString::number(qlonglong( m_id )) );
331
void Schedule::saveAppointments( QDomElement &element ) const
334
QListIterator<Appointment*> it = m_appointments;
335
while ( it.hasNext() ) {
336
it.next() ->saveXML( element );
340
void Schedule::insertForwardNode( Node *node )
343
m_parent->insertForwardNode( node );
347
void Schedule::insertBackwardNode( Node *node )
350
m_parent->insertBackwardNode( node );
354
// used (directly) when appointment wants to attatch itself again
355
bool Schedule::attatch( Appointment *appointment )
357
int mode = appointment->calculationMode();
358
//debugPlan<<appointment<<mode;
359
if ( mode == Scheduling ) {
360
if ( m_appointments.indexOf( appointment ) != -1 ) {
361
errorPlan << "Appointment already exists" << endl;
364
m_appointments.append( appointment );
365
//if (resource()) debugPlan<<appointment<<" For resource '"<<resource()->name()<<"'"<<" count="<<m_appointments.count();
366
//if (node()) debugPlan<<"("<<this<<")"<<appointment<<" For node '"<<node()->name()<<"'"<<" count="<<m_appointments.count();
369
if ( mode == CalculateForward ) {
370
if ( m_forward.indexOf( appointment ) != -1 ) {
371
errorPlan << "Appointment already exists" << endl;
374
m_forward.append( appointment );
375
//if (resource()) debugPlan<<"For resource '"<<resource()->name()<<"'";
376
//if (node()) debugPlan<<"For node '"<<node()->name()<<"'";
379
if ( mode == CalculateBackward ) {
380
if ( m_backward.indexOf( appointment ) != -1 ) {
381
errorPlan << "Appointment already exists" << endl;
384
m_backward.append( appointment );
385
//if (resource()) debugPlan<<"For resource '"<<resource()->name()<<"'";
386
//if (node()) debugPlan<<"For node '"<<node()->name()<<"'";
389
errorPlan<<"Unknown mode: "<<m_calculationMode<<endl;
393
// used to add new schedules
394
bool Schedule::add( Appointment *appointment )
397
appointment->setCalculationMode( m_calculationMode );
398
return attatch( appointment );
401
void Schedule::takeAppointment( Appointment *appointment, int mode )
404
//debugPlan<<"("<<this<<")"<<mode<<":"<<appointment<<","<<appointment->calculationMode();
405
int i = m_forward.indexOf( appointment );
407
m_forward.removeAt( i );
408
Q_ASSERT( mode == CalculateForward );
410
i = m_backward.indexOf( appointment );
412
m_backward.removeAt( i );
413
Q_ASSERT( mode == CalculateBackward );
415
i = m_appointments.indexOf( appointment );
417
m_appointments.removeAt( i );
418
Q_ASSERT( mode == Scheduling );
422
Appointment *Schedule::findAppointment( Schedule *resource, Schedule *node, int mode )
424
//debugPlan<<this<<" ("<<resourceError<<","<<node<<")"<<mode;
425
if ( mode == Scheduling ) {
426
foreach( Appointment *a, m_appointments ) {
427
if ( a->node() == node && a->resource() == resource ) {
432
} else if ( mode == CalculateForward ) {
433
foreach( Appointment *a, m_forward ) {
434
if ( a->node() == node && a->resource() == resource ) {
438
} else if ( mode == CalculateBackward ) {
439
foreach( Appointment *a, m_backward ) {
440
if ( a->node() == node && a->resource() == resource ) {
441
Q_ASSERT( mode == CalculateBackward );
446
Q_ASSERT( false ); // unknown mode
451
DateTime Schedule::appointmentStartTime() const
454
foreach ( const Appointment *a, m_appointments ) {
455
if ( ! dt.isValid() || dt > a->startTime() ) {
461
DateTime Schedule::appointmentEndTime() const
464
foreach ( const Appointment *a, m_appointments ) {
465
if ( ! dt.isValid() || dt > a->endTime() ) {
472
bool Schedule::hasAppointments( int which ) const
474
if ( which == CalculateForward ) {
475
return m_forward.isEmpty();
476
} else if ( which == CalculateBackward ) {
477
return m_backward.isEmpty();
479
return m_appointments.isEmpty();
482
QList<Appointment*> Schedule::appointments( int which ) const
484
if ( which == CalculateForward ) {
486
} else if ( which == CalculateBackward ) {
489
return m_appointments;
492
Appointment Schedule::appointmentIntervals( int which, const DateTimeInterval &interval ) const
495
if ( which == Schedule::CalculateForward ) {
496
//debugPlan<<"list == CalculateForward";
497
foreach ( Appointment *a, m_forward ) {
498
app += interval.isValid() ? a->extractIntervals( interval ) : *a;
501
} else if ( which == Schedule::CalculateBackward ) {
502
//debugPlan<<"list == CalculateBackward";
503
foreach ( Appointment *a, m_backward ) {
504
app += interval.isValid() ? a->extractIntervals( interval ) : *a;
506
//debugPlan<<"list == CalculateBackward:"<<m_backward.count();
509
foreach ( Appointment *a, m_appointments ) {
510
app += interval.isValid() ? a->extractIntervals( interval ) : *a;
515
void Schedule::copyAppointments( Schedule::CalculationMode from, Schedule::CalculationMode to )
519
m_appointments.clear();
521
case CalculateForward:
522
m_appointments = m_forward;
524
case CalculateBackward:
525
m_appointments = m_backward;
531
case CalculateForward: break;
532
case CalculateBackward: break;
536
EffortCostMap Schedule::bcwsPrDay( EffortCostCalculationType type ) const
538
return const_cast<Schedule*>( this )->bcwsPrDay( type );
541
EffortCostMap Schedule::bcwsPrDay( EffortCostCalculationType type )
543
//debugPlan<<m_name<<m_appointments;
544
EffortCostCache &ec = m_bcwsPrDay[ (int)type ];
546
foreach ( Appointment *a, m_appointments ) {
547
ec.effortcostmap += a->plannedPrDay( a->startTime().date(), a->endTime().date(), type );
550
return ec.effortcostmap;
553
EffortCostMap Schedule::plannedEffortCostPrDay( const QDate &start, const QDate &end, EffortCostCalculationType type ) const
555
//debugPlan<<m_name<<m_appointments;
557
QListIterator<Appointment*> it( m_appointments );
558
while ( it.hasNext() ) {
560
ec += it.next() ->plannedPrDay( start, end, type );
565
EffortCostMap Schedule::plannedEffortCostPrDay( const Resource *resource, const QDate &start, const QDate &end, EffortCostCalculationType type ) const
567
//debugPlan<<m_name<<m_appointments;
569
foreach ( Appointment *a, m_appointments ) {
570
if ( a->resource() && a->resource()->resource() == resource ) {
571
ec += a->plannedPrDay( start, end, type );
578
Duration Schedule::plannedEffort( const Resource *resource, EffortCostCalculationType type ) const
582
QListIterator<Appointment*> it( m_appointments );
583
while ( it.hasNext() ) {
584
eff += it.next() ->plannedEffort( resource, type );
589
Duration Schedule::plannedEffort( EffortCostCalculationType type ) const
593
QListIterator<Appointment*> it( m_appointments );
594
while ( it.hasNext() ) {
595
eff += it.next() ->plannedEffort( type );
600
Duration Schedule::plannedEffort( const QDate &date, EffortCostCalculationType type ) const
604
QListIterator<Appointment*> it( m_appointments );
605
while ( it.hasNext() ) {
606
eff += it.next() ->plannedEffort( date, type );
611
Duration Schedule::plannedEffort( const Resource *resource, const QDate &date, EffortCostCalculationType type ) const
615
QListIterator<Appointment*> it( m_appointments );
616
while ( it.hasNext() ) {
617
eff += it.next() ->plannedEffort( resource, date, type );
622
Duration Schedule::plannedEffortTo( const QDate &date, EffortCostCalculationType type ) const
626
QListIterator<Appointment*> it( m_appointments );
627
while ( it.hasNext() ) {
628
eff += it.next() ->plannedEffortTo( date, type );
633
Duration Schedule::plannedEffortTo( const Resource *resource, const QDate &date, EffortCostCalculationType type ) const
637
QListIterator<Appointment*> it( m_appointments );
638
while ( it.hasNext() ) {
639
eff += it.next() ->plannedEffortTo( resource, date, type );
644
EffortCost Schedule::plannedCost( EffortCostCalculationType type ) const
648
QListIterator<Appointment*> it( m_appointments );
649
while ( it.hasNext() ) {
650
c += it.next() ->plannedCost( type );
655
double Schedule::plannedCost( const QDate &date, EffortCostCalculationType type ) const
659
QListIterator<Appointment*> it( m_appointments );
660
while ( it.hasNext() ) {
661
c += it.next() ->plannedCost( date, type );
666
double Schedule::plannedCostTo( const QDate &date, EffortCostCalculationType type ) const
670
QListIterator<Appointment*> it( m_appointments );
671
while ( it.hasNext() ) {
672
c += it.next() ->plannedCostTo( date, type );
677
void Schedule::addLog( const Schedule::Log &log )
680
m_parent->addLog( log );
684
QString Schedule::Log::formatMsg() const
687
s += node ? QString( "%1 " ).arg( node->name(), -8 ) : "";
688
s += resource ? QString( "%1 ").arg(resource->name(), -8 ) : "";
693
void Schedule::clearPerformanceCache()
700
//-------------------------------------------------
701
NodeSchedule::NodeSchedule()
705
//debugPlan<<"("<<this<<")";
709
NodeSchedule::NodeSchedule( Node *node, const QString& name, Schedule::Type type, long id )
710
: Schedule( name, type, id ),
713
//debugPlan<<"node name:"<<node->name();
717
NodeSchedule::NodeSchedule( Schedule *parent, Node *node )
718
: Schedule( parent ),
722
//debugPlan<<"node name:"<<node->name();
726
NodeSchedule::~NodeSchedule()
728
//debugPlan<<this<<""<<m_appointments.count();
729
while ( !m_appointments.isEmpty() ) {
730
Appointment *a = m_appointments.takeFirst();
734
//debugPlan<<"forw"<<m_forward.count();
735
while ( !m_forward.isEmpty() ) {
736
Appointment *a = m_forward.takeFirst();
740
//debugPlan<<"backw"<<m_backward.count();
741
while ( !m_backward.isEmpty() ) {
742
Appointment *a = m_backward.takeFirst();
748
void NodeSchedule::init()
750
resourceError = false;
751
resourceOverbooked = false;
752
resourceNotAvailable = false;
753
constraintError = false;
754
schedulingError = false;
756
inCriticalPath = false;
757
m_calculationMode = Schedule::Scheduling;
758
positiveFloat = Duration::zeroDuration;
759
negativeFloat = Duration::zeroDuration;
760
freeFloat = Duration::zeroDuration;
763
void NodeSchedule::setDeleted( bool on )
765
//debugPlan<<"deleted="<<on;
767
// set deleted also for possible resource schedules
768
QListIterator<Appointment*> it = m_appointments;
769
while ( it.hasNext() ) {
770
Appointment * a = it.next();
771
if ( a->resource() ) {
772
a->resource() ->setDeleted( on );
777
bool NodeSchedule::loadXML( const KoXmlElement &sch, XMLLoaderObject &status )
781
Schedule::loadXML( sch, status );
782
s = sch.attribute( "earlystart" );
783
if ( s.isEmpty() ) { // try version < 0.6
784
s = sch.attribute( "earlieststart" );
786
if ( !s.isEmpty() ) {
787
earlyStart = DateTime::fromString( s, status.projectTimeZone() );
789
s = sch.attribute( "latefinish" );
790
if ( s.isEmpty() ) { // try version < 0.6
791
s = sch.attribute( "latestfinish" );
793
if ( !s.isEmpty() ) {
794
lateFinish = DateTime::fromString( s, status.projectTimeZone() );
796
s = sch.attribute( "latestart" );
797
if ( !s.isEmpty() ) {
798
lateStart = DateTime::fromString( s, status.projectTimeZone() );
800
s = sch.attribute( "earlyfinish" );
801
if ( !s.isEmpty() ) {
802
earlyFinish = DateTime::fromString( s, status.projectTimeZone() );
804
s = sch.attribute( "start" );
806
startTime = DateTime::fromString( s, status.projectTimeZone() );
807
s = sch.attribute( "end" );
809
endTime = DateTime::fromString( s, status.projectTimeZone() );
810
s = sch.attribute( "start-work" );
812
workStartTime = DateTime::fromString( s, status.projectTimeZone() );
813
s = sch.attribute( "end-work" );
815
workEndTime = DateTime::fromString( s, status.projectTimeZone() );
816
duration = Duration::fromString( sch.attribute( "duration" ) );
818
inCriticalPath = sch.attribute( "in-critical-path", "0" ).toInt();
819
resourceError = sch.attribute( "resource-error", "0" ).toInt();
820
resourceOverbooked = sch.attribute( "resource-overbooked", "0" ).toInt();
821
resourceNotAvailable = sch.attribute( "resource-not-available", "0" ).toInt();
822
constraintError = sch.attribute( "scheduling-conflict", "0" ).toInt();
823
schedulingError = sch.attribute( "scheduling-error", "0" ).toInt();
824
notScheduled = sch.attribute( "not-scheduled", "1" ).toInt();
826
positiveFloat = Duration::fromString( sch.attribute( "positive-float" ) );
827
negativeFloat = Duration::fromString( sch.attribute( "negative-float" ) );
828
freeFloat = Duration::fromString( sch.attribute( "free-float" ) );
833
void NodeSchedule::saveXML( QDomElement &element ) const
836
QDomElement sch = element.ownerDocument().createElement( "schedule" );
837
element.appendChild( sch );
838
saveCommonXML( sch );
840
if ( earlyStart.isValid() ) {
841
sch.setAttribute( "earlystart", earlyStart.toString( Qt::ISODate ) );
843
if ( lateStart.isValid() ) {
844
sch.setAttribute( "latestart", lateStart.toString( Qt::ISODate ) );
846
if ( earlyFinish.isValid() ) {
847
sch.setAttribute( "earlyfinish", earlyFinish.toString( Qt::ISODate ) );
849
if ( lateFinish.isValid() ) {
850
sch.setAttribute( "latefinish", lateFinish.toString( Qt::ISODate ) );
852
if ( startTime.isValid() )
853
sch.setAttribute( "start", startTime.toString( Qt::ISODate ) );
854
if ( endTime.isValid() )
855
sch.setAttribute( "end", endTime.toString( Qt::ISODate ) );
856
if ( workStartTime.isValid() )
857
sch.setAttribute( "start-work", workStartTime.toString( Qt::ISODate ) );
858
if ( workEndTime.isValid() )
859
sch.setAttribute( "end-work", workEndTime.toString( Qt::ISODate ) );
861
sch.setAttribute( "duration", duration.toString() );
863
sch.setAttribute( "in-critical-path", QString::number(inCriticalPath) );
864
sch.setAttribute( "resource-error", QString::number(resourceError) );
865
sch.setAttribute( "resource-overbooked", QString::number(resourceOverbooked) );
866
sch.setAttribute( "resource-not-available", QString::number(resourceNotAvailable) );
867
sch.setAttribute( "scheduling-conflict", QString::number(constraintError) );
868
sch.setAttribute( "scheduling-error", QString::number(schedulingError) );
869
sch.setAttribute( "not-scheduled", QString::number(notScheduled) );
871
sch.setAttribute( "positive-float", positiveFloat.toString() );
872
sch.setAttribute( "negative-float", negativeFloat.toString() );
873
sch.setAttribute( "free-float", freeFloat.toString() );
876
void NodeSchedule::addAppointment( Schedule *resource, const DateTime &start, const DateTime &end, double load )
879
Appointment * a = findAppointment( resource, this, m_calculationMode );
881
//debugPlan<<"Add interval to existing"<<a;
882
a->addInterval( start, end, load );
885
a = new Appointment( resource, this, start, end, load );
886
bool result = add( a );
888
result = resource->add( a );
890
Q_UNUSED ( result ); // cheating the compiler in release mode to not warn about unused-but-set-variable
891
//debugPlan<<"Added interval to new"<<a;
894
void NodeSchedule::takeAppointment( Appointment *appointment, int mode )
896
Schedule::takeAppointment( appointment, mode );
897
appointment->setNode( 0 ); // not my appointment anymore
898
//debugPlan<<"Taken:"<<appointment;
899
if ( appointment->resource() )
900
appointment->resource() ->takeAppointment( appointment );
903
QList<Resource*> NodeSchedule::resources() const
906
foreach( Appointment *a, m_appointments ) {
907
rl += a->resource() ->resource();
912
QStringList NodeSchedule::resourceNameList() const
915
foreach( Appointment *a, m_appointments ) {
916
rl += a->resource() ->resource() ->name();
921
void NodeSchedule::logError( const QString &msg, int phase )
923
Schedule::Log log( m_node, Log::Type_Error, msg, phase );
925
m_parent->addLog( log );
931
void NodeSchedule::logWarning( const QString &msg, int phase )
933
Schedule::Log log( m_node, Log::Type_Warning, msg, phase );
935
m_parent->addLog( log );
941
void NodeSchedule::logInfo( const QString &msg, int phase )
943
Schedule::Log log( m_node, Log::Type_Info, msg, phase );
945
m_parent->addLog( log );
951
void NodeSchedule::logDebug( const QString &msg, int phase )
953
Schedule::Log log( m_node, Log::Type_Debug, msg, phase );
955
m_parent->addLog( log );
961
//-----------------------------------------------
962
ResourceSchedule::ResourceSchedule()
966
//debugPlan<<"("<<this<<")";
969
ResourceSchedule::ResourceSchedule( Resource *resource, const QString& name, Schedule::Type type, long id )
970
: Schedule( name, type, id ),
971
m_resource( resource ),
975
//debugPlan<<"resource:"<<resource->name();
978
ResourceSchedule::ResourceSchedule( Schedule *parent, Resource *resource )
979
: Schedule( parent ),
980
m_resource( resource ),
984
//debugPlan<<"resource:"<<resource->name();
987
ResourceSchedule::~ResourceSchedule()
989
//debugPlan<<this<<""<<m_appointments.count();
990
while ( !m_appointments.isEmpty() ) {
991
Appointment *a = m_appointments.takeFirst();
995
//debugPlan<<"forw"<<m_forward.count();
996
while ( !m_forward.isEmpty() ) {
997
Appointment *a = m_forward.takeFirst();
1001
//debugPlan<<"backw"<<m_backward.count();
1002
while ( !m_backward.isEmpty() ) {
1003
Appointment *a = m_backward.takeFirst();
1004
a->setResource( 0 );
1009
// called from the resource
1010
void ResourceSchedule::addAppointment( Schedule *node, const DateTime &start, const DateTime &end, double load )
1012
Q_ASSERT( start < end );
1013
//debugPlan<<"("<<this<<")"<<node<<","<<m_calculationMode;
1014
Appointment * a = findAppointment( this, node, m_calculationMode );
1016
//debugPlan<<"Add interval to existing"<<a;
1017
a->addInterval( start, end, load );
1020
a = new Appointment( this, node, start, end, load );
1021
bool result = add( a );
1022
Q_ASSERT ( result == true );
1023
result = node->add( a );
1024
Q_ASSERT ( result == true );
1025
Q_UNUSED ( result ); //don't warn about unused-but-set-variable in release mode
1026
//debugPlan<<"Added interval to new"<<a;
1029
void ResourceSchedule::takeAppointment( Appointment *appointment, int mode )
1031
Schedule::takeAppointment( appointment, mode );
1032
appointment->setResource( 0 );
1033
//debugPlan<<"Taken:"<<appointment;
1034
if ( appointment->node() )
1035
appointment->node() ->takeAppointment( appointment );
1038
bool ResourceSchedule::isOverbooked() const
1043
bool ResourceSchedule::isOverbooked( const DateTime &start, const DateTime &end ) const
1045
if ( m_resource == 0 )
1047
//debugPlan<<start.toString()<<" -"<<end.toString();
1048
Appointment a = appointmentIntervals();
1049
foreach ( const AppointmentInterval &i, a.intervals().map() ) {
1050
if ( ( !end.isValid() || i.startTime() < end ) &&
1051
( !start.isValid() || i.endTime() > start ) ) {
1052
if ( i.load() > m_resource->units() ) {
1053
//debugPlan<<m_name<<" overbooked";
1057
if ( i.startTime() >= end )
1060
//debugPlan<<m_name<<" not overbooked";
1064
double ResourceSchedule::normalRatePrHour() const
1066
return m_resource ? m_resource->normalRate() : 0.0;
1069
//TODO change to return the booked effort
1070
Duration ResourceSchedule::effort( const DateTimeInterval &interval ) const
1072
Duration eff = interval.second - interval.first;
1073
if ( allowOverbooking() ) {
1077
if ( checkExternalAppointments() ) {
1078
a.setIntervals( m_resource->externalAppointments() );
1080
a.merge( appointmentIntervals( m_calculationMode ) );
1081
if ( a.isEmpty() || a.startTime() >= interval.second || a.endTime() <= interval.first ) {
1084
foreach ( const AppointmentInterval &i, a.intervals().map() ) {
1085
if ( interval.second <= i.startTime() ) {
1088
if ( interval.first >= i.startTime() ) {
1089
DateTime et = i.endTime() < interval.second ? i.endTime() : interval.second;
1090
eff -= ( et - interval.first ) * ((double)i.load()/100.0 );
1092
DateTime et = i.endTime() < interval.second ? i.endTime() : interval.second;
1093
eff -= ( et - i.startTime() ) * ((double)i.load()/100.0 );
1099
DateTimeInterval ResourceSchedule::available( const DateTimeInterval &interval ) const
1101
//const_cast<ResourceSchedule*>(this)->logDebug( QString( "Schedule available id=%1, Mode=%2: interval=%3 - %4" ).arg(m_id).arg(m_calculationMode).arg(interval.first.toString()).arg(interval.second.toString()) );
1102
if ( allowOverbooking() ) {
1103
return DateTimeInterval( interval.first, interval.second );
1105
QTimeZone projectTimeZone = QTimeZone::systemTimeZone();
1107
projectTimeZone = m_resource->project()->timeZone();
1109
DateTimeInterval ci(interval.first.toTimeZone(projectTimeZone), interval.second.toTimeZone(projectTimeZone));
1111
if ( checkExternalAppointments() ) {
1112
a.setIntervals( m_resource->externalAppointments( ci ) );
1114
a.merge( appointmentIntervals( m_calculationMode, ci ) );
1115
if ( a.isEmpty() || a.startTime() >= ci.second || a.endTime() <= ci.first ) {
1116
//debugPlan<<this<<"id="<<m_id<<"Mode="<<m_calculationMode<<""<<interval.first<<","<<interval.second<<" FREE";
1117
return DateTimeInterval( interval.first, interval.second ); // just return the interval
1119
//debugPlan<<"available:"<<interval<<endl<<a.intervals();
1120
DateTimeInterval res;
1121
int units = m_resource ? m_resource->units() : 100;
1122
foreach ( const AppointmentInterval &i, a.intervals().map() ) {
1123
//const_cast<ResourceSchedule*>(this)->logDebug( QString( "Schedule available check interval=%1 - %2" ).arg(i.startTime().toString()).arg(i.endTime().toString()) );
1124
if ( i.startTime() < ci.second && i.endTime() > ci.first ) {
1125
// interval intersects appointment
1126
if ( ci.first >= i.startTime() && ci.second <= i.endTime() ) {
1127
// interval within appointment
1128
if ( i.load() < units ) {
1129
if ( ! res.first.isValid() ) {
1130
res.first = qMax( ci.first, i.startTime() );
1132
res.second = qMin( ci.second, i.endTime() );
1135
if ( res.first.isValid() ) {
1136
res.second = i.startTime();
1137
if ( res.first >= res.second ) {
1138
res = DateTimeInterval();
1142
//debugPlan<<"available within:"<<interval<<i<<":"<<ci<<res;
1145
DateTime t = i.startTime();
1146
if ( ci.first < t ) {
1147
// Interval starts before appointment, so free from interval start
1148
//debugPlan<<"available before:"<<interval<<i<<":"<<ci<<res;
1149
//const_cast<ResourceSchedule*>(this)->logDebug( QString( "Schedule available t>first: returns interval=%1 - %2" ).arg(ci.first.toString()).arg(t.toString()) );
1150
if ( ! res.first.isValid() ) {
1151
res.first = ci.first;
1154
if ( i.load() < units ) {
1155
res.second = qMin( ci.second, i.endTime() );
1156
if ( ci.second > i.endTime() ) {
1157
ci.first = i.endTime();
1158
//debugPlan<<"available next 1:"<<interval<<i<<":"<<ci<<res;
1159
continue; // check next appointment
1162
//debugPlan<<"available:"<<interval<<i<<":"<<ci<<res;
1165
// interval start >= appointment start
1167
if ( t < ci.second ) {
1168
// check if rest of appointment is free
1169
if ( units <= i.load() ) {
1170
ci.first = t; // fully booked, so move forvard to appointment end
1173
//debugPlan<<"available next 2:"<<interval<<i<<":"<<ci<<res;
1176
//debugPlan<<"available:"<<interval<<i<<":"<<ci<<res;
1178
} else if ( i.startTime() >= interval.second ) {
1183
//debugPlan<<"available: result="<<interval<<":"<<res;
1184
return DateTimeInterval(res.first.toTimeZone(interval.first.timeZone()), res.second.toTimeZone(interval.second.timeZone()));
1187
void ResourceSchedule::logError( const QString &msg, int phase )
1190
Schedule::Log log( m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Error, msg, phase );
1191
m_parent->addLog( log );
1195
void ResourceSchedule::logWarning( const QString &msg, int phase )
1198
Schedule::Log log( m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Warning, msg, phase );
1199
m_parent->addLog( log );
1203
void ResourceSchedule::logInfo( const QString &msg, int phase )
1206
Schedule::Log log( m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Info, msg, phase );
1207
m_parent->addLog( log );
1211
void ResourceSchedule::logDebug( const QString &msg, int phase )
1214
Schedule::Log log( m_nodeSchedule ? m_nodeSchedule->node() : 0, m_resource, Log::Type_Debug, msg, phase );
1215
m_parent->addLog( log );
1219
//--------------------------------------
1220
MainSchedule::MainSchedule()
1225
//debugPlan<<"("<<this<<")";
1229
MainSchedule::MainSchedule( Node *node, const QString& name, Schedule::Type type, long id )
1230
: NodeSchedule( node, name, type, id ),
1231
criticalPathListCached( false ),
1233
m_currentCriticalPath( 0 )
1235
//debugPlan<<"node name:"<<node->name();
1239
MainSchedule::~MainSchedule()
1241
//debugPlan<<"("<<this<<")";
1244
void MainSchedule::incProgress()
1246
if ( m_manager ) m_manager->incProgress();
1249
bool MainSchedule::isBaselined() const
1251
return m_manager == 0 ? false : m_manager->isBaselined();
1254
bool MainSchedule::usePert() const
1256
return m_manager == 0 ? false : m_manager->usePert();
1259
bool MainSchedule::allowOverbooking() const
1261
return m_manager == 0 ? false : m_manager->allowOverbooking();
1264
bool MainSchedule::checkExternalAppointments() const
1266
return m_manager == 0 ? false : m_manager->checkExternalAppointments();
1269
void MainSchedule::changed( Schedule *sch )
1272
m_manager->scheduleChanged( static_cast<MainSchedule*>( sch ) );
1276
bool MainSchedule::loadXML( const KoXmlElement &sch, XMLLoaderObject &status )
1280
Schedule::loadXML( sch, status );
1282
s = sch.attribute( "start" );
1284
startTime = DateTime::fromString( s, status.projectTimeZone() );
1285
s = sch.attribute( "end" );
1287
endTime = DateTime::fromString( s, status.projectTimeZone() );
1289
duration = Duration::fromString( sch.attribute( "duration" ) );
1290
constraintError = sch.attribute( "scheduling-conflict", "0" ).toInt();
1291
schedulingError = sch.attribute( "scheduling-error", "0" ).toInt();
1292
//NOTE: we use "scheduled" as default to match old format without "not-scheduled" element
1293
notScheduled = sch.attribute( "not-scheduled", "0" ).toInt();
1295
KoXmlNode n = sch.firstChild();
1296
for ( ; ! n.isNull(); n = n.nextSibling() ) {
1297
if ( ! n.isElement() ) {
1300
KoXmlElement el = n.toElement();
1301
if ( el.tagName() == "appointment" ) {
1302
// Load the appointments.
1303
// Resources and tasks must already be loaded
1304
Appointment * child = new Appointment();
1305
if ( !child->loadXML( el, status, *this ) ) {
1306
// TODO: Complain about this
1307
errorPlan << "Failed to load appointment" << endl;
1310
} else if ( el.tagName() == "criticalpath-list" ) {
1311
// Tasks must already be loaded
1312
for ( KoXmlNode n1 = el.firstChild(); ! n1.isNull(); n1 = n1.nextSibling() ) {
1313
if ( ! n1.isElement() ) {
1316
KoXmlElement e1 = n1.toElement();
1317
if ( e1.tagName() != "criticalpath" ) {
1321
for ( KoXmlNode n2 = e1.firstChild(); ! n2.isNull(); n2 = n2.nextSibling() ) {
1322
if ( ! n2.isElement() ) {
1325
KoXmlElement e2 = n2.toElement();
1326
if ( e2.tagName() != "node" ) {
1329
QString s = e2.attribute( "id" );
1330
Node *node = status.project().findNode( s );
1334
errorPlan<<"Failed to find node id="<<s;
1337
m_pathlists.append( lst );
1339
criticalPathListCached = true;
1345
void MainSchedule::saveXML( QDomElement &element ) const
1347
saveCommonXML( element );
1349
element.setAttribute( "start", startTime.toString( Qt::ISODate ) );
1350
element.setAttribute( "end", endTime.toString( Qt::ISODate ) );
1351
element.setAttribute( "duration", duration.toString() );
1352
element.setAttribute( "scheduling-conflict", QString::number(constraintError) );
1353
element.setAttribute( "scheduling-error", QString::number(schedulingError) );
1354
element.setAttribute( "not-scheduled", QString::number(notScheduled) );
1356
if ( ! m_pathlists.isEmpty() ) {
1357
QDomElement lists = element.ownerDocument().createElement( "criticalpath-list" );
1358
element.appendChild( lists );
1359
foreach ( const QList<Node*> &l, m_pathlists ) {
1360
if ( l.isEmpty() ) {
1363
QDomElement list = lists.ownerDocument().createElement( "criticalpath" );
1364
lists.appendChild( list );
1365
foreach ( Node *n, l ) {
1366
QDomElement el = list.ownerDocument().createElement( "node" );
1367
list.appendChild( el );
1368
el.setAttribute( "id", n->id() );
1374
DateTime MainSchedule::calculateForward( int use )
1377
foreach( Node *n, m_backwardnodes ) {
1378
DateTime t = n->calculateForward( use );
1379
if ( !late.isValid() || late < t ) {
1386
DateTime MainSchedule::calculateBackward( int use )
1389
foreach( Node *n, m_forwardnodes ) {
1390
DateTime t = n->calculateBackward( use );
1391
if ( !early.isValid() || early > t ) {
1398
DateTime MainSchedule::scheduleForward( const DateTime &earliest, int use )
1401
foreach( Node *n, m_forwardnodes ) {
1402
DateTime t = n->scheduleForward( earliest, use );
1403
if ( !end.isValid() || end < t ) {
1410
DateTime MainSchedule::scheduleBackward( const DateTime &latest, int use )
1413
foreach( Node *n, m_backwardnodes ) {
1414
DateTime t = n->scheduleBackward( latest, use );
1415
if ( !start.isValid() || start > t ) {
1422
bool MainSchedule::recalculate() const
1424
return m_manager == 0 ? false : m_manager->recalculate();
1427
DateTime MainSchedule::recalculateFrom() const
1429
return m_manager == 0 ? DateTime() : m_manager->recalculateFrom();
1432
long MainSchedule::parentScheduleId() const
1434
return m_manager == 0 ? -2 : m_manager->parentScheduleId();
1437
void MainSchedule::clearCriticalPathList()
1439
m_pathlists.clear();
1440
m_currentCriticalPath = 0;
1441
criticalPathListCached = false;
1444
QList<Node*> *MainSchedule::currentCriticalPath() const
1446
return m_currentCriticalPath;
1449
void MainSchedule::addCriticalPath( QList<Node*> *lst )
1455
m_pathlists.append( l );
1456
m_currentCriticalPath = &( m_pathlists.last() );
1459
void MainSchedule::addCriticalPathNode( Node *node )
1461
if ( m_currentCriticalPath == 0 ) {
1462
errorPlan<<"No currentCriticalPath"<<endl;
1465
m_currentCriticalPath->append( node );
1468
QVector<Schedule::Log> MainSchedule::logs() const
1473
void MainSchedule::addLog( const KPlato::Schedule::Log &log )
1475
Q_ASSERT( log.resource || log.node );
1477
if ( log.resource ) {
1478
Q_ASSERT( manager()->project().findResource( log.resource->id() ) == log.resource );
1479
} else if ( log.node ) {
1480
Q_ASSERT( manager()->project().findNode( log.node->id() ) == log.node );
1483
const int phaseToSet = ( log.phase == -1 && ! m_log.isEmpty() ) ? m_log.last().phase : -1;
1484
m_log.append( log );
1486
if ( phaseToSet != -1 ) {
1487
m_log.last().phase = phaseToSet;
1490
m_manager->logAdded(m_log.last());
1495
QString MainSchedule::logSeverity( int severity )
1497
switch ( severity ) {
1498
case Log::Type_Debug: return "Debug";//FIXME i18n( "Debug" );
1499
case Log::Type_Info: return i18n( "Info" );
1500
case Log::Type_Warning: return i18n( "Warning" );
1501
case Log::Type_Error: return i18n( "Error" );
1504
return QString( "Severity %1" ).arg( severity );
1507
QStringList MainSchedule::logMessages() const
1510
foreach ( const Schedule::Log &l, m_log ) {
1511
lst << l.formatMsg();
1516
//-----------------------------------------
1517
ScheduleManager::ScheduleManager( Project &project, const QString name )
1518
: m_project( project),
1521
m_baselined( false ),
1522
m_allowOverbooking( false ),
1523
m_checkExternalAppointments( true ),
1525
m_recalculate( false ),
1526
m_schedulingDirection( false ),
1527
m_scheduling( false ),
1535
ScheduleManager::~ScheduleManager()
1537
qDeleteAll( m_children );
1538
setParentManager( 0 );
1541
void ScheduleManager::setParentManager( ScheduleManager *sm, int index )
1544
m_parent->removeChild( this );
1548
sm->insertChild( this, index );
1552
int ScheduleManager::removeChild( const ScheduleManager *sm )
1554
int i = m_children.indexOf( const_cast<ScheduleManager*>( sm ) );
1556
m_children.removeAt( i );
1561
void ScheduleManager::insertChild( ScheduleManager *sm, int index )
1563
//debugPlan<<m_name<<", insert"<<sm->name()<<","<<index;
1564
if ( index == -1 ) {
1565
m_children.append( sm );
1567
m_children.insert( index, sm );
1571
void ScheduleManager::createSchedules()
1573
setExpected( m_project.createSchedule( m_name, Schedule::Expected ) );
1576
int ScheduleManager::indexOf( const ScheduleManager *child ) const
1578
//debugPlan<<this<<","<<child;
1579
return m_children.indexOf( const_cast<ScheduleManager*>( child ) );
1582
ScheduleManager *ScheduleManager::findManager( const QString& name ) const
1584
if ( m_name == name ) {
1585
return const_cast<ScheduleManager*>( this );
1587
foreach ( ScheduleManager *sm, m_children ) {
1588
ScheduleManager *m = sm->findManager( name );
1596
QList<ScheduleManager*> ScheduleManager::allChildren() const
1598
QList<ScheduleManager*> lst;
1599
foreach ( ScheduleManager *sm, m_children ) {
1601
lst << sm->allChildren();
1606
bool ScheduleManager::isParentOf( const ScheduleManager *sm ) const
1608
if ( indexOf( sm ) >= 0 ) {
1611
foreach ( ScheduleManager *p, m_children ) {
1612
if ( p->isParentOf( sm ) ) {
1619
void ScheduleManager::setName( const QString& name )
1623
setObjectName( name );
1626
m_expected->setName( name );
1627
m_project.changed( m_expected );
1629
m_project.changed( this );
1632
bool ScheduleManager::isChildBaselined() const
1635
foreach ( ScheduleManager *sm, m_children ) {
1636
if ( sm->isBaselined() || sm->isChildBaselined() ) {
1643
void ScheduleManager::setBaselined( bool on )
1647
m_project.changed( this );
1650
void ScheduleManager::setAllowOverbooking( bool on )
1653
m_allowOverbooking = on;
1654
m_project.changed( this );
1657
bool ScheduleManager::allowOverbooking() const
1659
//debugPlan<<m_name<<"="<<m_allowOverbooking;
1660
return m_allowOverbooking;
1663
bool ScheduleManager::checkExternalAppointments() const
1665
//debugPlan<<m_name<<"="<<m_allowOverbooking;
1666
return m_checkExternalAppointments;
1669
void ScheduleManager::setCheckExternalAppointments( bool on )
1671
//debugPlan<<m_name<<"="<<m_checkExternalAppointments;
1672
m_checkExternalAppointments = on;
1675
void ScheduleManager::scheduleChanged( MainSchedule *sch )
1677
m_project.changed( sch );
1678
m_project.changed( this ); //hmmm, due to aggregated info
1681
void ScheduleManager::setUsePert( bool on )
1684
m_project.changed( this );
1687
void ScheduleManager::setSchedulingDirection( bool on )
1690
m_schedulingDirection = on;
1691
m_project.changed( this );
1694
void ScheduleManager::setScheduling( bool on )
1698
m_project.setProgress( 0, this );
1700
m_project.changed( this );
1703
const QList<SchedulerPlugin*> ScheduleManager::schedulerPlugins() const
1705
return m_project.schedulerPlugins().values();
1708
QString ScheduleManager::schedulerPluginId() const
1710
return m_schedulerPluginId;
1713
void ScheduleManager::setSchedulerPluginId( const QString &id )
1715
m_schedulerPluginId = id;
1716
m_project.changed( this );
1719
SchedulerPlugin *ScheduleManager::schedulerPlugin() const
1721
if ( m_schedulerPluginId.isEmpty() || !m_project.schedulerPlugins().contains( m_schedulerPluginId ) ) {
1722
// try to avoid crash
1723
return m_project.schedulerPlugins().value( m_project.schedulerPlugins().keys().value( 0 ) );
1725
return m_project.schedulerPlugins().value( m_schedulerPluginId );
1728
QStringList ScheduleManager::schedulerPluginNames() const
1731
QMap<QString, SchedulerPlugin*>::const_iterator it = m_project.schedulerPlugins().constBegin();
1732
QMap<QString, SchedulerPlugin*>::const_iterator end = m_project.schedulerPlugins().constEnd();
1733
for ( ; it != end; ++it ) {
1734
lst << it.value()->name();
1739
int ScheduleManager::schedulerPluginIndex() const
1741
if ( m_schedulerPluginId.isEmpty() ) {
1744
return m_project.schedulerPlugins().keys().indexOf( m_schedulerPluginId );
1747
void ScheduleManager::setSchedulerPlugin( int index )
1749
if ( schedulerPlugin() ) {
1750
schedulerPlugin()->stopCalculation( this ); // in case...
1753
m_schedulerPluginId = m_project.schedulerPlugins().keys().value( index );
1754
debugPlan<<index<<m_schedulerPluginId;
1755
m_project.changed( this );
1758
void ScheduleManager::calculateSchedule()
1760
m_calculationresult = CalculationRunning;
1761
if ( schedulerPlugin() ) {
1762
schedulerPlugin()->calculate( m_project, this );
1766
void ScheduleManager::stopCalculation()
1768
if ( schedulerPlugin() ) {
1769
schedulerPlugin()->stopCalculation( this );
1773
void ScheduleManager::haltCalculation()
1775
if ( schedulerPlugin() ) {
1776
schedulerPlugin()->haltCalculation( this );
1780
void ScheduleManager::setMaxProgress( int value )
1782
m_maxprogress = value;
1783
emit maxProgressChanged( value );
1784
m_project.changed( this );
1787
void ScheduleManager::setProgress( int value )
1790
emit progressChanged( value );
1791
m_project.changed( this );
1794
void ScheduleManager::setDeleted( bool on )
1797
m_expected->setDeleted( on );
1799
m_project.changed( this );
1802
void ScheduleManager::setExpected( MainSchedule *sch )
1804
//debugPlan<<m_expected<<","<<sch;
1806
m_project.sendScheduleToBeRemoved( m_expected );
1807
m_expected->setDeleted( true );
1808
m_project.sendScheduleRemoved( m_expected );
1812
m_project.sendScheduleToBeAdded( this, 0 );
1813
sch->setManager( this );
1814
m_expected->setDeleted( false );
1815
m_project.sendScheduleAdded( sch );
1817
m_project.changed( this );
1820
QStringList ScheduleManager::state() const
1823
if ( isBaselined() ) {
1824
return lst << i18n( "Baselined" );
1826
if ( m_scheduling ) {
1827
return lst << i18n( "Scheduling" );
1829
if ( m_expected == 0 ) {
1830
return lst << i18n( "Not scheduled" );
1832
if ( Schedule *s = m_expected ) {
1833
if ( s->resourceError || s->resourceOverbooked || s->resourceNotAvailable || s->constraintError || s->schedulingError ) {
1834
return lst << i18n( "Error" );
1841
QList<long unsigned int> ScheduleManager::supportedGranularities() const
1843
QList<long unsigned int> lst;
1844
if ( schedulerPlugin() ) {
1845
lst = schedulerPlugin()->granularities();
1850
int ScheduleManager::granularity() const
1852
if ( schedulerPlugin() ) {
1853
return schedulerPlugin()->granularity();
1858
void ScheduleManager::setGranularity( int duration )
1860
if ( schedulerPlugin() ) {
1861
schedulerPlugin()->setGranularity( duration );
1863
m_project.changed( this );
1866
void ScheduleManager::incProgress()
1868
m_project.incProgress();
1871
void ScheduleManager::logAdded( const Schedule::Log &log )
1873
emit sigLogAdded( log );
1874
int row = expected()->logs().count() - 1;
1875
emit logInserted( expected(), row, row );
1878
void ScheduleManager::slotAddLog( const QVector<KPlato::Schedule::Log> &log )
1880
if ( expected() && ! log.isEmpty() ) {
1881
int first = expected()->logs().count();
1882
int last = first + log.count() - 1;
1884
foreach ( const KPlato::Schedule::Log &l, log ) {
1885
expected()->addLog( l );
1890
QMap< int, QString > ScheduleManager::phaseNames() const
1893
return expected()->phaseNames();
1895
return QMap<int, QString>();
1898
void ScheduleManager::setPhaseNames( const QMap<int, QString> &phasenames )
1901
expected()->setPhaseNames( phasenames );
1906
bool ScheduleManager::loadXML( KoXmlElement &element, XMLLoaderObject &status )
1908
MainSchedule *sch = 0;
1909
if ( status.version() <= "0.5" ) {
1911
sch = loadMainSchedule( element, status );
1913
sch->setManager( this );
1914
switch ( sch->type() ) {
1915
case Schedule::Expected: setExpected( sch ); break;
1920
setName( element.attribute( "name" ) );
1921
m_id = element.attribute( "id" );
1922
m_usePert = (element.attribute( "distribution" ).toInt()) == 1;
1923
m_allowOverbooking = (bool)(element.attribute( "overbooking" ).toInt());
1924
m_checkExternalAppointments = (bool)(element.attribute( "check-external-appointments" ).toInt());
1925
m_schedulingDirection = (bool)(element.attribute( "scheduling-direction" ).toInt());
1926
m_baselined = (bool)(element.attribute( "baselined" ).toInt());
1927
m_schedulerPluginId = element.attribute( "scheduler-plugin-id" );
1928
if ( status.project().schedulerPlugins().contains( m_schedulerPluginId ) ) {
1929
// atm we only load for current plugin
1930
int g = element.attribute( "granularity", "0" ).toInt();
1931
status.project().schedulerPlugins().value( m_schedulerPluginId )->setGranularity( g );
1933
m_recalculate = (bool)(element.attribute( "recalculate" ).toInt());
1934
m_recalculateFrom = DateTime::fromString( element.attribute( "recalculate-from" ), status.projectTimeZone() );
1935
KoXmlNode n = element.firstChild();
1936
for ( ; ! n.isNull(); n = n.nextSibling() ) {
1937
if ( ! n.isElement() ) {
1940
KoXmlElement e = n.toElement();
1941
//debugPlan<<e.tagName();
1942
if ( e.tagName() == "schedule" ) {
1943
sch = loadMainSchedule( e, status );
1945
sch->setManager( this );
1946
switch ( sch->type() ) {
1947
case Schedule::Expected: setExpected( sch ); break;
1950
} else if ( e.tagName() == "plan" ) {
1951
ScheduleManager *sm = new ScheduleManager( status.project() );
1952
if ( sm->loadXML( e, status ) ) {
1953
m_project.addScheduleManager( sm, this );
1955
errorPlan<<"Failed to load schedule manager"<<endl;
1963
MainSchedule *ScheduleManager::loadMainSchedule( KoXmlElement &element, XMLLoaderObject &status ) {
1964
MainSchedule *sch = new MainSchedule();
1965
if ( sch->loadXML( element, status ) ) {
1966
status.project().addSchedule( sch );
1967
sch->setNode( &(status.project()) );
1968
status.project().setParentSchedule( sch );
1970
errorPlan << "Failed to load schedule" << endl;
1977
bool ScheduleManager::loadMainSchedule( MainSchedule *schedule, KoXmlElement &element, XMLLoaderObject &status ) {
1978
long sid = schedule->id();
1979
if ( schedule->loadXML( element, status ) ) {
1980
if ( sid != schedule->id() && status.project().findSchedule( sid ) ) {
1981
status.project().takeSchedule( schedule );
1983
if ( ! status.project().findSchedule( schedule->id() ) ) {
1984
status.project().addSchedule( schedule );
1986
schedule->setNode( &(status.project()) );
1987
status.project().setParentSchedule( schedule );
1993
void ScheduleManager::saveXML( QDomElement &element ) const
1995
QDomElement el = element.ownerDocument().createElement( "plan" );
1996
element.appendChild( el );
1997
el.setAttribute( "name", m_name );
1998
el.setAttribute( "id", m_id );
1999
el.setAttribute( "distribution", QString::number(m_usePert ? 1 : 0) );
2000
el.setAttribute( "overbooking", QString::number(m_allowOverbooking) );
2001
el.setAttribute( "check-external-appointments", QString::number(m_checkExternalAppointments) );
2002
el.setAttribute( "scheduling-direction", QString::number(m_schedulingDirection) );
2003
el.setAttribute( "baselined", QString::number(m_baselined) );
2004
el.setAttribute( "scheduler-plugin-id", m_schedulerPluginId );
2005
if ( schedulerPlugin() ) {
2006
// atm we only save for current plugin
2007
el.setAttribute( "granularity", QString::number(schedulerPlugin()->granularity()) );
2009
el.setAttribute( "recalculate", QString::number(m_recalculate) );
2010
el.setAttribute( "recalculate-from", m_recalculateFrom.toString( Qt::ISODate ) );
2011
if ( m_expected && ! m_expected->isDeleted() ) {
2012
QDomElement schs = el.ownerDocument().createElement( "schedule" );
2013
el.appendChild( schs );
2014
m_expected->saveXML( schs );
2015
m_project.saveAppointments( schs, m_expected->id() );
2017
foreach ( ScheduleManager *sm, m_children ) {
2023
void ScheduleManager::saveWorkPackageXML( QDomElement &element, const Node &node ) const
2025
QDomElement el = element.ownerDocument().createElement( "plan" );
2026
element.appendChild( el );
2027
el.setAttribute( "name", m_name );
2028
el.setAttribute( "id", m_id );
2029
el.setAttribute( "distribution", QString::number(m_usePert ? 1 : 0) );
2030
el.setAttribute( "overbooking", QString::number(m_allowOverbooking) );
2031
el.setAttribute( "check-external-appointments", QString::number(m_checkExternalAppointments) );
2032
el.setAttribute( "scheduling-direction", QString::number(m_schedulingDirection) );
2033
el.setAttribute( "baselined", QString::number(m_baselined) );
2034
if ( m_expected && ! m_expected->isDeleted() ) { // TODO: should we check isScheduled() ?
2035
QDomElement schs = el.ownerDocument().createElement( "schedule" );
2036
el.appendChild( schs );
2037
m_expected->saveXML( schs );
2038
Schedule *s = node.findSchedule( m_expected->id() );
2039
if ( s && ! s->isDeleted() ) {
2040
s->saveAppointments( schs );
2046
} //namespace KPlato
2048
QDebug operator<<( QDebug dbg, const KPlato::Schedule *s )
2053
return dbg<<"Schedule(0x0)";
2055
QDebug operator<<( QDebug dbg, const KPlato::Schedule &s )
2057
dbg.nospace()<<"Schedule["<<s.id();
2058
if (s.isDeleted()) {
2059
dbg.nospace()<<": Deleted";
2061
dbg.nospace()<<": "<<s.name();
2067
QDebug operator<<( QDebug dbg, const KPlato::Schedule::Log &log )
2069
dbg.nospace()<<"Schedule::Log: "<<log.formatMsg();