1 | /* This file is part of the KDE project |
2 | Copyright (C) 2001 Thomas Zander zander@kde.org |
3 | Copyright (C) 2004-2007 Dag Andersen <danders@get2net.dk> |
4 | Copyright (C) 2011 Dag Andersen <danders@get2net.dk> |
5 | |
6 | This library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Library General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2 of the License, or (at your option) any later version. |
10 | |
11 | This library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Library General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Library General Public License |
17 | along with this library; see the file COPYING.LIB. If not, write to |
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #ifndef KPTRESOURCE_H |
23 | #define KPTRESOURCE_H |
24 | |
25 | #include "kplatokernel_export.h" |
26 | |
27 | #include "kptglobal.h" |
28 | #include "kptduration.h" |
29 | #include "kptdatetime.h" |
30 | #include "kptappointment.h" |
31 | #include "kptcalendar.h" |
32 | |
33 | #include <QDomDocument> |
34 | #include <QHash> |
35 | #include <QString> |
36 | #include <QList> |
37 | |
38 | #include <kdebug.h> |
39 | |
40 | #include <KoXmlReader.h> |
41 | |
42 | class QTime; |
43 | |
44 | |
45 | /// The main namespace. |
46 | namespace KPlato |
47 | { |
48 | |
49 | class Account; |
50 | class Risk; |
51 | class Effort; |
52 | class Appointment; |
53 | class Task; |
54 | class Node; |
55 | class Project; |
56 | class Resource; |
57 | class ResourceRequest; |
58 | class ResourceGroupRequest; |
59 | class ResourceRequestCollection; |
60 | class Schedule; |
61 | class NodeSchedule; |
62 | class ResourceSchedule; |
63 | class Schedule; |
64 | class XMLLoaderObject; |
65 | class DateTimeInterval; |
66 | |
67 | /** |
68 | * This class represents a group of similar resources to be assigned to a task |
69 | * e.g. The list of employees, computer resources, etc |
70 | */ |
71 | |
72 | /* IDEA; lets create a resourceGroup that has the intelligence to import PIM schedules |
73 | * from the kroupware project and use the schedules to use the factory pattern to build |
74 | * Resources (probably a derived class) which returns values on getFirstAvailableTime |
75 | * and friends based on the schedules we got from the PIM projects. |
76 | * (Thomas Zander mrt-2003 by suggestion of Shaheed) |
77 | */ |
78 | |
79 | class KPLATOKERNEL_EXPORT ResourceGroup : public QObject |
80 | { |
81 | Q_OBJECT |
82 | public: |
83 | /// Default constructor |
84 | explicit ResourceGroup(); |
85 | explicit ResourceGroup( const ResourceGroup *group ); |
86 | ~ResourceGroup(); |
87 | |
88 | enum Type { Type_Work, Type_Material }; |
89 | |
90 | QString id() const { return m_id; } |
91 | void setId( const QString& id ); |
92 | |
93 | Project *project() { return m_project; } |
94 | |
95 | void setName( const QString& n ); |
96 | const QString &name() const { return m_name;} |
97 | void setType( Type type ); |
98 | void setType(const QString &type); |
99 | Type type() const { return m_type; } |
100 | QString typeToString( bool trans = false ) const; |
101 | static QStringList typeToStringList( bool trans = false ); |
102 | |
103 | bool isScheduled() const; |
104 | |
105 | /// Return true if any resource in this group is baselined |
106 | bool isBaselined( long id = BASELINESCHEDULE ) const; |
107 | |
108 | /** Manage the resources in this list |
109 | * <p>At some point we will have to look at not mixing types of resources |
110 | * (e.g. you can't add a person to a list of computers |
111 | * |
112 | * <p>Risks must always be associated with a resource, so there is no option |
113 | * to manipulate risks (@ref Risk) separately |
114 | */ |
115 | void addResource( int index, Resource*, Risk* ); |
116 | Resource *takeResource( Resource *resource ); |
117 | QList<Resource*> resources() const { return m_resources; } |
118 | int indexOf( const Resource *resource ) const; |
119 | Resource *resourceAt( int pos ) const { return m_resources.value( pos ); } |
120 | int numResources() const { return m_resources.count(); } |
121 | |
122 | Risk* getRisk( int ); |
123 | |
124 | /** Get the "num" resources which is available in the time frame |
125 | * defined by "start" and "duration". |
126 | * @param start todo |
127 | * @param duration todo |
128 | * @param num todo |
129 | */ |
130 | QList<Resource> availableResources( const DateTime start, const Duration duration, int num ); |
131 | /** Manage the dependent resources. This is a list of the resource |
132 | * groups that must have available resources for this resource to |
133 | * perform the work |
134 | * <p>see also @ref getRequiredResource, @ref getRequiredResource |
135 | */ |
136 | void addRequiredResource( ResourceGroup* ); |
137 | /** Manage the dependent resources. This is a list of the resource |
138 | * groups that must have available resources for this resource to |
139 | * perform the work |
140 | * <p>see also @ref addRequiredResource, @ref getRequiredResource |
141 | */ |
142 | ResourceGroup* getRequiredResource( int ); |
143 | /** Manage the dependent resources. This is a list of the resource |
144 | * groups that must have available resources for this resource to |
145 | * perform the work |
146 | * <p>see also @ref getRequiredResource, @ref addRequiredResource |
147 | */ |
148 | void deleteRequiredResource( int ); |
149 | |
150 | bool load( KoXmlElement &element, XMLLoaderObject &status ); |
151 | void save( QDomElement &element ) const; |
152 | |
153 | /// Save workpackage document. Include only resources listed in @p lst |
154 | void saveWorkPackageXML( QDomElement &element, const QList<Resource*> lst ) const; |
155 | |
156 | void initiateCalculation( Schedule &sch ); |
157 | |
158 | void addNode( Node *node ) { m_nodes.append( node ); } |
159 | void clearNodes() { m_nodes.clear(); } |
160 | |
161 | Calendar *defaultCalendar() { return m_defaultCalendar; } |
162 | |
163 | int units() const; |
164 | |
165 | void registerRequest( ResourceGroupRequest *request ) |
166 | { m_requests.append( request ); } |
167 | void unregisterRequest( ResourceGroupRequest *request ) |
168 | { |
169 | int i = m_requests.indexOf( request ); |
170 | if ( i != -1 ) |
171 | m_requests.removeAt( i ); |
172 | } |
173 | const QList<ResourceGroupRequest*> &requests() const |
174 | { return m_requests; } |
175 | |
176 | ResourceGroup *findId() const { return findId( m_id ); } |
177 | ResourceGroup *findId( const QString &id ) const; |
178 | bool removeId() { return removeId( m_id ); } |
179 | bool removeId( const QString &id ); |
180 | void insertId( const QString &id ); |
181 | |
182 | Appointment appointmentIntervals() const; |
183 | |
184 | // m_project is set when the resourcegroup is added to the project, |
185 | // and reset when the resourcegroup is removed from the project |
186 | void setProject( Project *project ); |
187 | |
188 | void copy( const ResourceGroup *group ); |
189 | |
190 | DateTime startTime( long id ) const; |
191 | DateTime endTime( long id ) const; |
192 | |
193 | #ifndef NDEBUG |
194 | |
195 | void printDebug( const QString& ident ); |
196 | #endif |
197 | |
198 | protected: |
199 | virtual void changed(); |
200 | |
201 | private: |
202 | Project *m_project; |
203 | QString m_id; // unique id |
204 | QString m_name; |
205 | QList<Resource*> m_resources; |
206 | QList<Risk*> m_risks; |
207 | QList<ResourceGroup*> m_requires; |
208 | |
209 | QList<Node*> m_nodes; //The nodes that want resources from us |
210 | |
211 | Calendar *m_defaultCalendar; |
212 | Type m_type; |
213 | |
214 | QList<ResourceGroupRequest*> m_requests; |
215 | |
216 | }; |
217 | |
218 | /** |
219 | * Any resource that is used by a task. A resource can be a worker, or maybe wood. |
220 | * If the resources is a worker or a piece of equiment which can be reused but |
221 | * can only be used by one node in time, then we can use the scheduling methods of the |
222 | * resource to schedule the resource available time for the project. |
223 | * The Idea is that all nodes which need this resource point to it and the scheduling |
224 | * code (partly implemented here) schedules the actual usage. |
225 | * See also @ref ResourceGroup |
226 | */ |
227 | |
228 | class KPLATOKERNEL_EXPORT Resource : public QObject |
229 | { |
230 | Q_OBJECT |
231 | public: |
232 | |
233 | Resource(); |
234 | explicit Resource(Resource *resource); |
235 | virtual ~Resource(); |
236 | |
237 | QString id() const { return m_id; } |
238 | void setId( const QString& id ); |
239 | |
240 | enum Type { Type_Work, Type_Material, Type_Team }; |
241 | void setType( Type type ); |
242 | void setType( const QString &type ); |
243 | Type type() const { return m_type; } |
244 | QString typeToString( bool trans = false ) const; |
245 | static QStringList typeToStringList( bool trans = false ); |
246 | |
247 | void setName( const QString &n ); |
248 | const QString &name() const { return m_name;} |
249 | |
250 | void setInitials( const QString &initials ); |
251 | const QString &initials() const { return m_initials;} |
252 | |
253 | void setEmail( const QString &email ); |
254 | const QString &email() const { return m_email;} |
255 | |
256 | /// Returns true if this resource will be allocated by default to new tasks |
257 | bool autoAllocate() const; |
258 | /// Set if this resource will be allocated by default to new tasks |
259 | void setAutoAllocate( bool on ); |
260 | |
261 | void copy( Resource *resource ); |
262 | |
263 | void setParentGroup( ResourceGroup *parent ) { m_parent = parent; } |
264 | ResourceGroup *parentGroup() const { return m_parent; } |
265 | |
266 | /// Set the time from when the resource is available to this project |
267 | void setAvailableFrom( const QDateTime &af ) { m_availableFrom = af; changed();} |
268 | /// Set the time from when the resource is available to this project |
269 | void setAvailableFrom( const DateTime &af ) { m_availableFrom = af; changed(); } |
270 | /// Return the time when the resource is available to this project |
271 | const DateTime &availableFrom() const { return m_availableFrom;} |
272 | /// Set the time when the resource is no longer available to this project |
273 | void setAvailableUntil( const QDateTime &au ) { m_availableUntil = au; changed(); } |
274 | /// Set the time when the resource is no longer available to this project |
275 | void setAvailableUntil( const DateTime &au ) { m_availableUntil = au; changed(); } |
276 | /// Return the time when the resource is no longer available to this project. |
277 | const DateTime &availableUntil() const { return m_availableUntil;} |
278 | |
279 | DateTime firstAvailableAfter( const DateTime &time, const DateTime &limit ) const; |
280 | |
281 | DateTime getBestAvailableTime( const Duration &duration ); |
282 | DateTime getBestAvailableTime( const DateTime &after, const Duration &duration ); |
283 | |
284 | bool load( KoXmlElement &element, XMLLoaderObject &status ); |
285 | void save( QDomElement &element ) const; |
286 | |
287 | /// Return the list of appointments for schedule @p id. |
288 | QList<Appointment*> appointments( long id = -1 ) const; |
289 | /// Return the number of appointments (nodes) |
290 | int numAppointments( long id = -1 ) const { return appointments( id ).count(); } |
291 | /// Return the appointment at @p index for schedule @p id |
292 | Appointment *appointmentAt( int index, long id = -1 ) const { return appointments( id ).value( index ); } |
293 | int indexOf( Appointment *a, long id = -1 ) const { return appointments( id ).indexOf( a ); } |
294 | |
295 | /// Adds appointment to current schedule |
296 | virtual bool addAppointment( Appointment *appointment ); |
297 | /// Adds appointment to schedule sch |
298 | virtual bool addAppointment( Appointment *appointment, Schedule &main ); |
299 | /// Adds appointment to both this resource and node |
300 | virtual void addAppointment( Schedule *node, const DateTime &start, const DateTime &end, double load = 100 ); |
301 | |
302 | void initiateCalculation( Schedule &sch ); |
303 | bool isAvailable( Task *task ); |
304 | void makeAppointment( Schedule *schedule, int load, const QList<Resource*> &required = QList<Resource*>() ); |
305 | |
306 | bool isOverbooked() const; |
307 | /// check if overbooked on date. |
308 | bool isOverbooked( const QDate &date ) const; |
309 | /// check if overbooked within the interval start, end. |
310 | bool isOverbooked( const DateTime &start, const DateTime &end ) const; |
311 | |
312 | double normalRate() const { return cost.normalRate; } |
313 | void setNormalRate( double rate ) { cost.normalRate = rate; changed(); } |
314 | double overtimeRate() const { return cost.overtimeRate; } |
315 | void setOvertimeRate( double rate ) { cost.overtimeRate = rate; changed(); } |
316 | |
317 | /** |
318 | * Return available units in percent |
319 | */ |
320 | int units() const { return m_units; } |
321 | /** |
322 | * Set available units in percent |
323 | */ |
324 | void setUnits( int units ); |
325 | |
326 | Project *project() const { return m_project; } |
327 | /// Return the resources timespec. Defaults to local. |
328 | KDateTime::Spec timeSpec() const; |
329 | |
330 | /** |
331 | * Get the calendar for this resource. |
332 | * Working resources may have a default calendar if the a calendar is marked as default, |
333 | * this is checked if local=false. |
334 | * If no calendar can be found for a working resource, the resource is not available. |
335 | * |
336 | * Material resources must have calendar explicitly set. |
337 | * If there is no calendar set for a material resource, the resource is always available. |
338 | */ |
339 | Calendar *calendar( bool local = false ) const; |
340 | //Calendar *calendar( const QString& id ) const; |
341 | void setCalendar( Calendar *calendar ); |
342 | |
343 | /// Delete all requests for me |
344 | void removeRequests(); |
345 | /** |
346 | * Used to clean up requests when the resource is deleted. |
347 | */ |
348 | void registerRequest( ResourceRequest *request ) |
349 | { m_requests.append( request ); } |
350 | void unregisterRequest( ResourceRequest *request ) |
351 | { |
352 | int i = m_requests.indexOf( request ); |
353 | if ( i != -1 ) |
354 | m_requests.removeAt( i ); |
355 | } |
356 | const QList<ResourceRequest*> &requests() const |
357 | { return m_requests; } |
358 | |
359 | /// Returns a list of work intervals in the interval @p from, @p until. |
360 | /// Appointments are subtracted if @p schedule is not 0 and overbooking is not allowed. |
361 | AppointmentIntervalList workIntervals( const DateTime &from, const DateTime &until, Schedule *schedule ) const; |
362 | |
363 | /// Returns a list of work intervals in the interval @p from, @p until. |
364 | AppointmentIntervalList workIntervals( const DateTime &from, const DateTime &until ) const; |
365 | |
366 | /// Updates work interval cache a list of work intervals extracted from the resource calendar |
367 | /// with @p load in the interval @p from, @p until. |
368 | /// The load of the intervals is set to m_units |
369 | /// Note: The list may contain intervals outside @p from, @p until |
370 | void calendarIntervals( const DateTime &from, const DateTime &until ) const; |
371 | /// Load cache from @p element |
372 | bool loadCalendarIntervalsCache( const KoXmlElement& element, KPlato::XMLLoaderObject& status ); |
373 | /// Save cache to @p element |
374 | void saveCalendarIntervalsCache( QDomElement &element ) const; |
375 | |
376 | /// Returns the effort that can be done starting at @p start within @p duration. |
377 | /// The current schedule is used to check for appointments. |
378 | /// If @p backward is true, checks backward in time. |
379 | Duration effort( const DateTime &start, const Duration &duration, int units = 100, bool backward = false, const QList<Resource*> &required = QList<Resource*>() ) const; |
380 | |
381 | /// Returns the effort that can be done starting at @p start within @p duration. |
382 | /// The schedule @p sch is used to check for appointments. |
383 | /// If @p backward is true, checks backward in time. |
384 | /// Status is returned in @p ok |
385 | Duration effort( KPlato::Schedule* sch, const DateTime &start, const Duration& duration, int units = 100, bool backward = false, const QList< Resource* >& required = QList<Resource*>() ) const; |
386 | |
387 | |
388 | /** |
389 | * Find the first available time after @p time, within @p limit. |
390 | * Returns invalid DateTime if not available. |
391 | * Uses the current schedule to check for appointments. |
392 | */ |
393 | DateTime availableAfter( const DateTime &time, const DateTime limit = DateTime() ) const; |
394 | /** |
395 | * Find the first available time before @p time, within @p limit. |
396 | * Returns invalid DateTime if not available. |
397 | * Uses the current schedule to check for appointments. |
398 | */ |
399 | DateTime availableBefore( const DateTime &time, const DateTime limit = DateTime()) const; |
400 | |
401 | /** |
402 | * Find the first available time after @p time, within @p limit. |
403 | * Returns invalid DateTime if not available. |
404 | * If @p sch == 0, Appointments are not checked. |
405 | */ |
406 | DateTime availableAfter( const DateTime &time, const DateTime limit, Schedule *sch ) const; |
407 | /** |
408 | * Find the first available time before @p time, within @p limit. |
409 | * Returns invalid DateTime if not available. |
410 | * If @p sch == 0, Appointments are not checked. |
411 | */ |
412 | DateTime availableBefore( const DateTime &time, const DateTime limit, Schedule *sch ) const; |
413 | |
414 | Resource *findId() const { return findId( m_id ); } |
415 | Resource *findId( const QString &id ) const; |
416 | bool removeId() { return removeId( m_id ); } |
417 | bool removeId( const QString &id ); |
418 | void insertId( const QString &id ); |
419 | |
420 | Calendar *findCalendar( const QString &id ) const; |
421 | |
422 | Appointment appointmentIntervals( long id ) const; |
423 | Appointment appointmentIntervals() const; |
424 | |
425 | EffortCostMap plannedEffortCostPrDay( const QDate &start, const QDate &end, long id, EffortCostCalculationType = ECCT_All ); |
426 | Duration plannedEffort( const QDate &date, EffortCostCalculationType = ECCT_All ) const; |
427 | |
428 | void setCurrentSchedulePtr( Schedule *schedule ) { m_currentSchedule = schedule; } |
429 | void setCurrentSchedule( long id ) { m_currentSchedule = findSchedule( id ); } |
430 | Schedule *currentSchedule() const { return m_currentSchedule; } |
431 | |
432 | bool isScheduled() const; |
433 | QHash<long, Schedule*> schedules() const { return m_schedules; } |
434 | /** |
435 | * Return schedule with @id |
436 | * If @p id == CURRENTSCHEDULE, return m_currentSchedule |
437 | * Return 0 if schedule with @p id doesn't exist. |
438 | */ |
439 | Schedule *schedule( long id = CURRENTSCHEDULE ) const; |
440 | /// Returns true if schedule with @p id is baselined. |
441 | /// if Team resource, if any of the team members is baselined |
442 | /// By default returns true if any schedule is baselined |
443 | bool isBaselined( long id = BASELINESCHEDULE ) const; |
444 | /** |
445 | * Return schedule with @id |
446 | * Return 0 if schedule with @id doesn't exist. |
447 | */ |
448 | Schedule *findSchedule( long id ) const; |
449 | /// Take, and delete. |
450 | void deleteSchedule( Schedule *schedule ); |
451 | /// Take, don't delete. |
452 | void takeSchedule( const Schedule *schedule ); |
453 | void addSchedule( Schedule *schedule ); |
454 | ResourceSchedule *createSchedule( const QString& name, int type, long id ); |
455 | ResourceSchedule *createSchedule( Schedule *parent ); |
456 | |
457 | // m_project is set when the resource (or the parent) is added to the project, |
458 | // and reset when the resource is removed from the project |
459 | void setProject( Project *project ); |
460 | |
461 | void addExternalAppointment( const QString &id, Appointment *a ); |
462 | |
463 | void addExternalAppointment( const QString &id, const QString &name, const DateTime &from, const DateTime &end, double load = 100 ); |
464 | void subtractExternalAppointment( const QString &id, const DateTime &from, const DateTime &end, double load ); |
465 | |
466 | void clearExternalAppointments(); |
467 | void clearExternalAppointments( const QString id ); |
468 | /// Take the external appointments with identity @p id from the list of external appointments |
469 | Appointment *takeExternalAppointment( const QString &id ); |
470 | /// Return external appointments with identity @p id |
471 | AppointmentIntervalList externalAppointments( const QString &id ); |
472 | AppointmentIntervalList externalAppointments( const DateTimeInterval &interval = DateTimeInterval() ) const; |
473 | |
474 | int numExternalAppointments() const { return m_externalAppointments.count(); } |
475 | QList<Appointment*> externalAppointmentList() const { return m_externalAppointments.values(); } |
476 | /// return a map of project id, project name |
477 | QMap<QString, QString> externalProjects() const; |
478 | |
479 | /// Return a measure of how suitable the resource is for allocation |
480 | long allocationSuitability( const DateTime &time, const Duration &duration, bool backward ); |
481 | |
482 | DateTime startTime( long id ) const; |
483 | DateTime endTime( long id ) const; |
484 | |
485 | /// Returns the list of requiered resources. |
486 | /// Note: This list is used as default for allocation dialog, not for scheduling. |
487 | QList<Resource*> requiredResources() const; |
488 | /// Set the list of the required resources's ids so they can be resolved when used |
489 | /// A required resource may not exist in the project yet |
490 | void setRequiredIds( const QStringList &lst ); |
491 | /// Add a resource id to the required ids list |
492 | void addRequiredId( const QString &id ); |
493 | /// Returns the list of requiered resource ids. |
494 | QStringList requiredIds() const { return m_requiredIds; } |
495 | |
496 | /// Return the list of team members. |
497 | QList<Resource*> teamMembers() const; |
498 | /// Return the list of team members. |
499 | QStringList teamMemberIds() const; |
500 | /// Clear the list of team members. |
501 | void clearTeamMembers() { m_teamMembers.clear(); } |
502 | /// Add resource @p id to the list of team members. |
503 | void addTeamMemberId( const QString &id ); |
504 | /// Remove resource @p id from the list of team members. |
505 | void removeTeamMemberId( const QString &id ); |
506 | |
507 | /// Return the account |
508 | Account *account() const { return cost.account; } |
509 | /// Set the @p account |
510 | void setAccount( Account *account ); |
511 | |
512 | // for xml loading code |
513 | |
514 | class WorkInfoCache |
515 | { |
516 | public: |
517 | WorkInfoCache() { clear(); } |
518 | void clear() { start = end = DateTime(); effort = Duration::zeroDuration; intervals.clear(); version = -1; } |
519 | bool isValid() const { return start.isValid() && end.isValid(); } |
520 | DateTime firstAvailableAfter( const DateTime &time, const DateTime &limit, Calendar *cal, Schedule *sch ) const; |
521 | DateTime firstAvailableBefore( const DateTime &time, const DateTime &limit, Calendar *cal, Schedule *sch ) const; |
522 | |
523 | DateTime start; |
524 | DateTime end; |
525 | Duration effort; |
526 | AppointmentIntervalList intervals; |
527 | int version; |
528 | |
529 | bool load( const KoXmlElement& element, KPlato::XMLLoaderObject& status ); |
530 | void save( QDomElement &element ) const; |
531 | }; |
532 | const WorkInfoCache &workInfoCache() const { return m_workinfocache; } |
533 | |
534 | signals: |
535 | void externalAppointmentToBeAdded( Resource *r, int row ); |
536 | void externalAppointmentAdded( Resource*, Appointment* ); |
537 | void externalAppointmentToBeRemoved( Resource *r, int row ); |
538 | void externalAppointmentRemoved(); |
539 | void externalAppointmentChanged( Resource *r, Appointment *a ); |
540 | |
541 | protected: |
542 | DateTimeInterval requiredAvailable(Schedule *node, const DateTime &start, const DateTime &end ) const; |
543 | void makeAppointment( Schedule *node, const DateTime &from, const DateTime &end, int load, const QList<Resource*> &required = QList<Resource*>() ); |
544 | virtual void changed(); |
545 | |
546 | private: |
547 | Project *m_project; |
548 | ResourceGroup *m_parent; |
549 | QHash<long, Schedule*> m_schedules; |
550 | QString m_id; // unique id |
551 | QString m_name; |
552 | QString m_initials; |
553 | QString m_email; |
554 | bool m_autoAllocate; |
555 | DateTime m_availableFrom; |
556 | DateTime m_availableUntil; |
557 | QMap<QString, Appointment*> m_externalAppointments; |
558 | |
559 | int m_units; // avalable units in percent |
560 | |
561 | Type m_type; |
562 | |
563 | struct Cost |
564 | { |
565 | double normalRate; |
566 | double overtimeRate; |
567 | double fixed ; |
568 | Account *account; |
569 | } |
570 | cost; |
571 | |
572 | Calendar *m_calendar; |
573 | QList<ResourceRequest*> m_requests; |
574 | QStringList m_requiredIds; |
575 | |
576 | QStringList m_teamMembers; |
577 | |
578 | Schedule *m_currentSchedule; |
579 | |
580 | mutable WorkInfoCache m_workinfocache; |
581 | |
582 | // return this if resource has no calendar and is a material resource |
583 | Calendar m_materialCalendar; |
584 | |
585 | #ifndef NDEBUG |
586 | public: |
587 | void printDebug( const QString& ident ); |
588 | #endif |
589 | }; |
590 | |
591 | KPLATOKERNEL_EXPORT QDebug operator<<( QDebug dbg, const KPlato::Resource::WorkInfoCache &c ); |
592 | |
593 | /** |
594 | * Risk is associated with a resource/task pairing to indicate the planner's confidence in the |
595 | * estimated effort. Risk can be one of none, low, or high. Some factors that may be taken into |
596 | * account for risk are the experience of the person and the reliability of equipment. |
597 | */ |
598 | class Risk |
599 | { |
600 | public: |
601 | |
602 | enum RiskType { |
603 | NONE = 0, |
604 | LOW = 1, |
605 | HIGH = 2 |
606 | }; |
607 | |
608 | Risk( Node *n, Resource *r, RiskType rt = NONE ); |
609 | ~Risk(); |
610 | |
611 | RiskType riskType() { return m_riskType; } |
612 | |
613 | Node *node() { return m_node; } |
614 | Resource *resource() { return m_resource; } |
615 | |
616 | private: |
617 | Node *m_node; |
618 | Resource *m_resource; |
619 | RiskType m_riskType; |
620 | }; |
621 | |
622 | class KPLATOKERNEL_EXPORT ResourceRequest |
623 | { |
624 | public: |
625 | explicit ResourceRequest( Resource *resource = 0, int units = 1 ); |
626 | explicit ResourceRequest( const ResourceRequest &r ); |
627 | |
628 | ~ResourceRequest(); |
629 | |
630 | ResourceGroupRequest *parent() const { return m_parent; } |
631 | void setParent( ResourceGroupRequest *parent ) { m_parent = parent; } |
632 | |
633 | Resource *resource() const { return m_resource; } |
634 | void setResource( Resource* resource ) { m_resource = resource; } |
635 | |
636 | bool load( KoXmlElement &element, Project &project ); |
637 | void save( QDomElement &element ) const; |
638 | |
639 | /** |
640 | * Get amount of requested resource units in percent |
641 | */ |
642 | int units() const; |
643 | void setUnits( int value ); |
644 | |
645 | void registerRequest() |
646 | { |
647 | if ( m_resource ) |
648 | m_resource->registerRequest( this ); |
649 | } |
650 | void unregisterRequest() |
651 | { |
652 | if ( m_resource ) |
653 | m_resource->unregisterRequest( this ); |
654 | } |
655 | |
656 | void makeAppointment( Schedule *schedule, int amount ); |
657 | void makeAppointment( Schedule *schedule ); |
658 | Task *task() const; |
659 | |
660 | /// Return the datetime from when the resource is available. |
661 | /// If it is not valid, the project constraint start time is used. |
662 | /// For teams the earliest time for any team member is used. |
663 | DateTime availableFrom(); |
664 | /// Return the datetime until when the resource is available. |
665 | /// If it is not valid, the project constraint end time is used. |
666 | /// For teams the latest time for any team member is used. |
667 | DateTime availableUntil(); |
668 | |
669 | Schedule *resourceSchedule( Schedule *ns, Resource *resource = 0 ); |
670 | DateTime availableAfter(const DateTime &time, Schedule *ns); |
671 | DateTime availableBefore(const DateTime &time, Schedule *ns); |
672 | Duration effort( const DateTime &time, const Duration &duration, Schedule *ns, bool backward ); |
673 | DateTime workTimeAfter(const DateTime &dt, Schedule *ns = 0); |
674 | DateTime workTimeBefore(const DateTime &dt, Schedule *ns = 0); |
675 | |
676 | /// Resource is allocated dynamically by the group request |
677 | bool isDynamicallyAllocated() const { return m_dynamic; } |
678 | /// Set resource is allocated dynamically |
679 | void setAllocatedDynaically( bool dyn ) { m_dynamic = dyn; } |
680 | |
681 | /// Return a measure of how suitable the resource is for allocation |
682 | long allocationSuitability( const DateTime &time, const Duration &duration, Schedule *ns, bool backward ); |
683 | |
684 | /// Returns a list of all the required resources that will be used in scheduling. |
685 | /// Note: This list overrides the resources own list which is just used as default for allocation dialog. |
686 | QList<Resource*> requiredResources() const { return m_required; } |
687 | /// Set the list of required resources that will be used in scheduling. |
688 | void setRequiredResources( const QList<Resource*> &lst ) { m_required = lst; } |
689 | |
690 | private: |
691 | friend class ResourceGroupRequest; |
692 | QList<ResourceRequest*> teamMembers() const; |
693 | |
694 | protected: |
695 | void changed(); |
696 | |
697 | void setCurrentSchedulePtr( Schedule *ns ); |
698 | void setCurrentSchedulePtr( Resource *resource, Schedule *ns ); |
699 | |
700 | private: |
701 | Resource *m_resource; |
702 | int m_units; |
703 | ResourceGroupRequest *m_parent; |
704 | bool m_dynamic; |
705 | QList<Resource*> m_required; |
706 | mutable QList<ResourceRequest*> m_teamMembers; |
707 | |
708 | #ifndef NDEBUG |
709 | public: |
710 | void printDebug( const QString& ident ); |
711 | #endif |
712 | }; |
713 | QDebug &operator<<( QDebug &dbg, const KPlato::ResourceRequest *r ); |
714 | QDebug &operator<<( QDebug &dbg, const KPlato::ResourceRequest &r ); |
715 | |
716 | class KPLATOKERNEL_EXPORT ResourceGroupRequest |
717 | { |
718 | public: |
719 | explicit ResourceGroupRequest( ResourceGroup *group = 0, int units = 0 ); |
720 | explicit ResourceGroupRequest( const ResourceGroupRequest &group ); |
721 | ~ResourceGroupRequest(); |
722 | |
723 | void setParent( ResourceRequestCollection *parent ) { m_parent = parent;} |
724 | ResourceRequestCollection *parent() const { return m_parent; } |
725 | |
726 | ResourceGroup *group() const { return m_group; } |
727 | void setGroup( ResourceGroup *group ) { m_group = group; } |
728 | void unregister( const ResourceGroup *group ) { if ( group == m_group ) m_group = 0; } |
729 | /// Return a list of resource requests. |
730 | /// If @p resolveTeam is true, include the team members, |
731 | /// if @p resolveTeam is false, include the team resource itself. |
732 | QList<ResourceRequest*> resourceRequests( bool resolveTeam=true ) const; |
733 | void addResourceRequest( ResourceRequest *request ); |
734 | void deleteResourceRequest( ResourceRequest *request ); |
735 | int count() const { return m_resourceRequests.count(); } |
736 | ResourceRequest *requestAt( int idx ) const { return m_resourceRequests.value( idx ); } |
737 | |
738 | ResourceRequest *takeResourceRequest( ResourceRequest *request ); |
739 | ResourceRequest *find( const Resource *resource ) const; |
740 | ResourceRequest *resourceRequest( const QString &name ); |
741 | /// Return a list of allocated resources, allocation to group is not included by default. |
742 | QStringList requestNameList( bool includeGroup = false ) const; |
743 | /// Return a list of allocated resources. |
744 | /// Allocations to groups are not included. |
745 | /// Team resources are included but *not* the team members. |
746 | /// Any dynamically allocated resource is not included. |
747 | QList<Resource*> requestedResources() const; |
748 | bool load( KoXmlElement &element, XMLLoaderObject &status ); |
749 | void save( QDomElement &element ) const; |
750 | |
751 | /// The number of requested resources |
752 | int units() const; |
753 | void setUnits( int value ) { m_units = value; changed(); } |
754 | |
755 | /** |
756 | * Returns the duration needed to do the @p effort starting at @p start. |
757 | */ |
758 | Duration duration( const DateTime &start, const Duration &effort, Schedule *ns, bool backward = false ); |
759 | |
760 | DateTime availableAfter( const DateTime &time, Schedule *ns ); |
761 | DateTime availableBefore( const DateTime &time, Schedule *ns ); |
762 | DateTime workTimeAfter(const DateTime &dt, Schedule *ns = 0); |
763 | DateTime workTimeBefore(const DateTime &dt, Schedule *ns = 0); |
764 | |
765 | /** |
766 | * Makes appointments for task @param task to the |
767 | * requested resources for the duration found in @ref duration(). |
768 | */ |
769 | void makeAppointments( Schedule *schedule ); |
770 | |
771 | /** |
772 | * Reserves the requested resources for the specified interval |
773 | */ |
774 | void reserve( const DateTime &start, const Duration &duration ); |
775 | |
776 | bool isEmpty() const; |
777 | |
778 | Task *task() const; |
779 | |
780 | void changed(); |
781 | |
782 | /// Reset dynamic resource allocations |
783 | void resetDynamicAllocations(); |
784 | /// Allocate dynamic requests. Do nothing if already allocated. |
785 | void allocateDynamicRequests( const DateTime &time, const Duration &effort, Schedule *ns, bool backward ); |
786 | |
787 | private: |
788 | ResourceGroup *m_group; |
789 | int m_units; |
790 | ResourceRequestCollection *m_parent; |
791 | |
792 | QList<ResourceRequest*> m_resourceRequests; |
793 | DateTime m_start; |
794 | Duration m_duration; |
795 | |
796 | #ifndef NDEBUG |
797 | public: |
798 | void printDebug( const QString& ident ); |
799 | #endif |
800 | }; |
801 | |
802 | class KPLATOKERNEL_EXPORT ResourceRequestCollection |
803 | { |
804 | public: |
805 | explicit ResourceRequestCollection( Task *task = 0 ); |
806 | ~ResourceRequestCollection(); |
807 | |
808 | QList<ResourceGroupRequest*> requests() const { return m_requests; } |
809 | void addRequest( ResourceGroupRequest *request ); |
810 | void deleteRequest( ResourceGroupRequest *request ) |
811 | { |
812 | int i = m_requests.indexOf( request ); |
813 | if ( i != -1 ) |
814 | m_requests.removeAt( i ); |
815 | delete request; |
816 | changed(); |
817 | } |
818 | |
819 | int takeRequest( ResourceGroupRequest *request ) |
820 | { |
821 | int i = m_requests.indexOf( request ); |
822 | if ( i != -1 ) { |
823 | m_requests.removeAt( i ); |
824 | changed(); |
825 | } |
826 | return i; |
827 | } |
828 | |
829 | ResourceGroupRequest *find( const ResourceGroup *resource ) const; |
830 | ResourceRequest *find( const Resource *resource ) const; |
831 | ResourceRequest *resourceRequest( const QString &name ) const; |
832 | /// The ResourceRequestCollection has no requests |
833 | bool isEmpty() const; |
834 | /// Empty the ResourceRequestCollection of all requets |
835 | void clear() { m_requests.clear(); } |
836 | /// Reset dynamic resource allocations |
837 | void resetDynamicAllocations(); |
838 | |
839 | bool contains( const QString &identity ) const; |
840 | ResourceGroupRequest *findGroupRequestById( const QString &id ) const; |
841 | /// Return a list of names of allocated resources. |
842 | /// Allocations to groups are not included by default. |
843 | /// Team resources are included but *not* the team members. |
844 | /// Any dynamically allocated resource is not included. |
845 | QStringList requestNameList( bool includeGroup = false ) const; |
846 | /// Return a list of allocated resources. |
847 | /// Allocations to groups are not included. |
848 | /// Team resources are included but *not* the team members. |
849 | /// Any dynamically allocated resource is not included. |
850 | QList<Resource*> requestedResources() const; |
851 | |
852 | /// Return a list of all resource requests. |
853 | /// If @p resolveTeam is true, include the team members, |
854 | /// if @p resolveTeam is false, include the team resource itself. |
855 | QList<ResourceRequest*> resourceRequests( bool resolveTeam=true ) const; |
856 | |
857 | //bool load(KoXmlElement &element, Project &project); |
858 | void save( QDomElement &element ) const; |
859 | |
860 | /** |
861 | * Returns the duration needed to do the @p effort starting at @p time. |
862 | */ |
863 | Duration duration( const DateTime &time, const Duration &effort, Schedule *sch, bool backward = false ); |
864 | |
865 | DateTime availableAfter( const DateTime &time, Schedule *ns ); |
866 | DateTime availableBefore( const DateTime &time, Schedule *ns ); |
867 | DateTime workTimeAfter(const DateTime &dt, Schedule *ns = 0) const; |
868 | DateTime workTimeBefore(const DateTime &dt, Schedule *ns = 0) const; |
869 | DateTime workStartAfter(const DateTime &time, Schedule *ns); |
870 | DateTime workFinishBefore(const DateTime &time, Schedule *ns); |
871 | |
872 | /** |
873 | * Makes appointments for the task @param task to the requested resources. |
874 | * Assumes that @ref duration() has been run. |
875 | */ |
876 | void makeAppointments( Schedule *schedule ); |
877 | /** |
878 | * Reserves the requested resources for the specified interval |
879 | */ |
880 | void reserve( const DateTime &start, const Duration &duration ); |
881 | |
882 | Task *task() const { return m_task; } |
883 | void setTask( Task *t ) { m_task = t; } |
884 | |
885 | void changed(); |
886 | |
887 | Duration effort( const QList<ResourceRequest*> &lst, const DateTime &time, const Duration &duration, Schedule *ns, bool backward ) const; |
888 | int numDays(const QList<ResourceRequest*> &lst, const DateTime &time, bool backward) const; |
889 | Duration duration(const QList<ResourceRequest*> &lst, const DateTime &time, const Duration &_effort, Schedule *ns, bool backward); |
890 | |
891 | private: |
892 | Task *m_task; |
893 | QList<ResourceGroupRequest*> m_requests; |
894 | }; |
895 | |
896 | } //KPlato namespace |
897 | |
898 | #endif |
899 | |