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