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