4 * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
5 * Chris Schlaeger <cs@kde.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
27 #include "TaskScenario.h"
28 #include "ShiftSelectionList.h"
29 #include "LoopDetectorInfo.h"
30 #include "TaskDependency.h"
45 * This class stores all task related information and provides methods to
46 * manipulte them. It provides fundamental functions like the scheduler.
48 * @short The class that holds all task related information.
51 * @author Chris Schlaeger <cs@kde.org>
53 class Task : public CoreAttributes
55 friend int TaskList::compareItemsLevel(CoreAttributes*, CoreAttributes*,
59 Task(Project* prj, const QString& id_, const QString& n, Task* p,
60 const QString& f, int l);
63 virtual CAType getType() const { return CA_Task; }
65 Task* getParent() const { return static_cast<Task*>(parent); }
67 TaskListIterator getSubListIterator() const
69 return TaskListIterator(*sub);
72 enum SchedulingInfo { ASAP, ALAP };
76 void setProjectId(const QString& i) { projectId = i; }
77 const QString& getProjectId() const { return projectId; }
79 void setNote(const QString& d) { note = d; }
80 const QString& getNote() const { return note; }
82 void addJournalEntry(JournalEntry* entry);
84 bool hasJournal() const { return !journal.isEmpty(); }
86 Journal::Iterator getJournalIterator() const;
88 void setReference(const QString& r, const QString& l)
93 const QString& getReference() const { return ref; }
94 const QString& getReferenceLabel() const { return refLabel; }
96 void setScheduling(SchedulingInfo si) { scheduling = si; }
97 SchedulingInfo getScheduling() const { return scheduling; }
99 void setPriority(int p) { priority = p; }
100 int getPriority() const { return priority; }
102 void setResponsible(Resource* r) { responsible = r; }
103 Resource* getResponsible() const { return responsible; }
105 void setMilestone(bool ms = true) { milestone = ms; }
106 bool isMilestone() const { return milestone; }
108 void setAccount(Account* a) { account = a; }
109 Account* getAccount() const { return account; }
111 TaskDependency* addDepends(const QString& id);
112 Q3PtrListIterator<TaskDependency> getDependsIterator() const
114 return Q3PtrListIterator<TaskDependency>(depends);
116 TaskDependency* addPrecedes(const QString& id);
117 Q3PtrListIterator<TaskDependency> getPrecedesIterator() const
119 return Q3PtrListIterator<TaskDependency>(precedes);
121 bool addShift(const Interval& i, Shift* s);
123 void addAllocation(Allocation* a) { allocations.append(a); }
124 void purgeAllocations() { allocations.clear(); }
125 Q3PtrListIterator<Allocation> getAllocationIterator() const
127 return Q3PtrListIterator<Allocation>(allocations);
130 TaskListIterator getPreviousIterator() const
132 return TaskListIterator(previous);
134 bool hasPrevious() const { return !previous.isEmpty(); }
136 TaskListIterator getFollowersIterator() const
138 return TaskListIterator(followers);
140 bool hasFollowers() const { return !followers.isEmpty(); }
142 bool hasPrevious(const Task* t) { return previous.findRef(t) != -1; }
143 bool hasFollower(const Task* t) { return followers.findRef(t) != -1; }
145 void collectDependencies(TaskList& list, long depth) const;
147 // The following group of functions operates only on scenario variables.
148 void setSpecifiedStart(int sc, time_t s)
150 scenarios[sc].specifiedStart = s;
152 time_t getSpecifiedStart(int sc)
154 return scenarios[sc].specifiedStart;
156 void setStart(int sc, time_t s) { scenarios[sc].start = s; }
157 time_t getStart(int sc) const { return scenarios[sc].start; }
159 void setSpecifiedEnd(int sc, time_t s)
161 scenarios[sc].specifiedEnd = s;
163 time_t getSpecifiedEnd(int sc)
165 return scenarios[sc].specifiedEnd;
167 void setEnd(int sc, time_t s) { scenarios[sc].end = s; }
168 time_t getEnd(int sc) const { return scenarios[sc].end; }
170 void setSpecifiedPeriod(int sc, const Interval& iv)
172 scenarios[sc].specifiedStart = iv.getStart();
173 scenarios[sc].specifiedEnd = iv.getEnd();
176 time_t getStartBufferEnd(int sc) const
178 return scenarios[sc].startBufferEnd;
180 time_t getEndBufferStart(int sc) const
182 return scenarios[sc].endBufferStart;
185 void setMinStart(int sc, time_t s) { scenarios[sc].minStart = s; }
186 time_t getMinStart(int sc) const { return scenarios[sc].minStart; }
188 void setMaxStart(int sc, time_t s) { scenarios[sc].maxStart = s; }
189 time_t getMaxStart(int sc) const { return scenarios[sc].maxStart; }
191 void setMinEnd(int sc, time_t e) { scenarios[sc].minEnd = e; }
192 time_t getMinEnd(int sc) const { return scenarios[sc].minEnd; }
194 void setMaxEnd(int sc, time_t e) { scenarios[sc].maxEnd = e; }
195 time_t getMaxEnd(int sc) const { return scenarios[sc].maxEnd; }
197 void setLength(int sc, double days) { scenarios[sc].length = days; }
198 double getLength(int sc) const { return scenarios[sc].length; }
200 void setEffort(int sc, double e) { scenarios[sc].effort = e; }
201 double getEffort(int sc) const { return scenarios[sc].effort; }
203 void setDuration(int sc, double d) { scenarios[sc].duration = d; }
204 double getDuration(int sc) const { return scenarios[sc].duration; }
206 bool isStartOk(int sc) const
208 return scenarios[sc].isStartOk();
210 bool isEndOk(int sc) const
212 return scenarios[sc].isEndOk();
215 bool isBuffer(int sc, const Interval& iv) const;
217 void setComplete(int sc, double c) { scenarios[sc].reportedCompletion = c; }
218 double getComplete(int sc) const
220 return scenarios[sc].reportedCompletion;
223 void setStatusNote(int sc, const QString& d)
225 scenarios[sc].statusNote = d;
227 const QString& getStatusNote(int sc) const
229 return scenarios[sc].statusNote;
232 void setStartBuffer(int sc, double p) { scenarios[sc].startBuffer = p; }
233 double getStartBuffer(int sc) const { return scenarios[sc].startBuffer; }
235 void setEndBuffer(int sc, double p) { scenarios[sc]. endBuffer = p; }
236 double getEndBuffer(int sc) const { return scenarios[sc].endBuffer; }
238 void setStartCredit(int sc, double c) { scenarios[sc].startCredit = c; }
239 double getStartCredit(int sc) const { return scenarios[sc].startCredit; }
241 void setEndCredit(int sc, double c) { scenarios[sc].endCredit = c; }
242 double getEndCredit(int sc) const { return scenarios[sc].endCredit; }
244 double getCalcEffort(int sc) const;
245 double getCalcDuration(int sc) const;
247 double getCredits(int sc, const Interval& period, AccountType acctType,
248 const Resource* resource = 0, bool recursive = true)
251 bool isActive(int sc, const Interval& period) const;
252 TaskStatus getStatus(int sc) const { return scenarios[sc].status; }
253 QString getStatusText(int sc) const;
255 QString getSchedulingText() const;
257 bool isCompleted(int sc, time_t date) const;
258 void calcCompletionDegree(int sc);
259 void calcContainerCompletionDegree(int sc, time_t now);
260 double getCompletionDegree(int sc) const;
261 double getCalcedCompletionDegree(int sc) const;
262 TaskStatus getCompletionStatus(int sc) const
264 return scenarios[sc].status;
266 double getCompletedLoad(int sc) const;
267 double getRemainingLoad(int sc) const;
269 double getLoad(int sc, const Interval& period, const Resource* resource = 0)
271 long getAllocatedTime(int sc, const Interval& period,
272 const Resource* resource = 0) const;
273 double getAllocatedTimeLoad(int sc, const Interval& period,
274 const Resource* resource = 0) const;
276 void addBookedResource(int sc, Resource* r)
278 if (scenarios[sc].bookedResources.findRef((CoreAttributes*) r) == -1)
279 scenarios[sc].bookedResources.inSort((CoreAttributes*) r);
281 bool isBookedResource(int sc, const Resource* r) const
283 return scenarios[sc].bookedResources.find((CoreAttributes*) r) != -1;
285 ResourceListIterator getBookedResourcesIterator(int sc) const
287 return ResourceListIterator(scenarios[sc].bookedResources);
289 ResourceList getBookedResources(int sc) const
291 return scenarios[sc].bookedResources;
293 void setSpecifiedScheduled(int sc, bool ps)
295 scenarios[sc].specifiedScheduled = ps;
297 bool getSpecifiedScheduled(int sc) const
299 return scenarios[sc].specifiedScheduled;
301 void setScheduled(int sc, bool ps) { scenarios[sc].scheduled = ps; }
302 bool getScheduled(int sc) const { return scenarios[sc].scheduled; }
304 bool isDutyOf(int sc, const Resource* r) const
306 return scenarios[sc].isDutyOf(r);
309 void overlayScenario(int base, int sc);
310 void prepareScenario(int sc);
311 void finishScenario(int sc);
312 void computeCriticalness(int sc);
313 double getCriticalness(int sc) const { return scenarios[sc].criticalness; }
314 void checkAndMarkCriticalPath(int sc, double minSlack, time_t maxEnd);
316 double computePathCriticalness(int sc);
317 double getPathCriticalness(int sc) const
319 return scenarios[sc].pathCriticalness;
322 bool isOnCriticalPath(int sc, bool leavesOnly = true) const
324 if (!isLeaf() && leavesOnly)
327 return scenarios[sc].isOnCriticalPath;
330 bool hasCriticalLinkTo(int sc, const Task* t) const
332 return scenarios[sc].criticalLinks.containsRef(t);
336 * @retval true if itself or one of its subtasks (recursively) is on the critical path
337 * @retval false otherwise.
339 bool isOrHasDescendantOnCriticalPath(int sc) const;
341 bool isContainer() const { return !sub->isEmpty(); }
343 bool xRef(Q3Dict<Task>& hash);
345 void sortAllocations();
346 void saveSpecifiedBookedResources();
347 QString resolveId(QString relId);
349 bool preScheduleOk(int sc);
350 bool scheduleOk(int sc) const;
352 * Checks for loops in task interdependencies starting with the current
354 * @param ckedTaskList The list of already checked tasks. Will be appended
356 * @retval true if a loop was detected.
357 * @retval false otherwise.
359 bool loopDetector(LDIList& chkedTaskList) const;
360 bool checkDetermination(int sc) const;
361 void computeBuffers();
362 time_t nextSlot(time_t slotDuration) const;
363 bool isReadyForScheduling() const;
364 bool schedule(int sc, time_t& reqStart, time_t duration);
365 void propagateInitialValues(int sc);
367 bool isRunaway() const;
369 bool isSubTask(const Task* t) const;
371 bool isSchedulingDone() const { return schedulingDone; }
373 void errorMessage(const QString& msg) const;
374 void warningMessage(const QString& msg) const;
376 QDomElement xmlElement( QDomDocument& doc, bool absId = true );
378 void setSvgGanttReportIndex(int sc, int i) { scenarios[sc].svgGanttReportIndex = i; }
379 int getSvgGanttReportIndex(int sc) { return scenarios[sc].svgGanttReportIndex; }
382 void propagateStart(int sc, time_t date);
383 void propagateEnd(int sc, time_t date);
385 * Checks for loops in task interdependencies starting with the current
386 * task under ASAP or ALAP scheduling.
387 * @param ckedTaskList The list of already checked tasks. Will be appended
389 * @retval true if a loop was detected.
390 * @retval false otherwise.
392 bool loopDetection(LDIList& list, LDIList& chkedTaskList, bool atEnd,
393 bool fromOutside) const;
394 bool checkPathForLoops(LDIList& list, bool atEnd) const;
395 bool scheduleContainer(int sc);
396 Task* subFirst() { return (Task*) sub->first(); }
397 Task* subNext() { return (Task*) sub->next(); }
398 bool bookResource(Resource* r, time_t day, time_t duration,
399 int& slotsToLimit, bool& encounteredBooked);
400 void bookResources(int sc, time_t day, time_t duration);
401 void addBookedResource(Resource* r)
403 if (bookedResources.findRef((CoreAttributes*) r) == -1)
404 bookedResources.inSort((CoreAttributes*) r);
406 Q3PtrList<Resource> createCandidateList(int sc, time_t date, Allocation* a);
407 time_t earliestStart(int sc) const;
408 time_t latestEnd(int sc) const;
410 bool startCanBeDetermined(LDIList& list, int sc) const;
411 bool endCanBeDetermined(LDIList& list, int sc) const;
413 bool hasStartDependency(int sc) const;
414 bool hasEndDependency(int sc) const;
416 bool hasStartDependency() const;
417 bool hasEndDependency() const;
419 bool analyzePath(int sc, double minSlack, time_t pathStart, long busyTime,
420 long worstMinSlackTime, long& checked, long& found);
421 void collectTransientFollowers(TaskList& list);
423 bool countMilestones(int sc, time_t now, int& totalMilestones,
424 int& completedMilestones,
425 int& reportedCompletedMilestones);
426 bool sumUpEffort(int sc, time_t now, double& totalEffort,
427 double& completedEffort,
428 double& reportedCompletedEffort);
430 /// A longer description of the task.
433 /// List of notes with a date attached.
436 /// A reference to an external document
439 /// A label used instead of the reference
443 * The dependencies of the task are stored twice. depends and precedes
444 * store the information specified in the project file. For convenience we
445 * also store the backward dependency together with the specified
446 * dependencies in predecessors and successors.
448 Q3PtrList<TaskDependency> depends;
451 Q3PtrList<TaskDependency> precedes;
454 * A list of tasks that must precede this task.
456 TaskList predecessors;
459 * A list of tasks that must follow this task.
464 * A list of all tasks that preceed this task. It's the combination of
465 * depends and predecessors. This is redundant information but stored for
466 * conveniance. Interdependent tasks are linked in a doubly linked list.
471 * A list of all tasks that follow this task. It's the combination of
472 * precedes and successors. This is redundant information but stored for
473 * conveniance. Interdependent tasks are linked in a doubly linked list.
478 * The ID of the project this task belongs to. This is only
479 * meaningful if multiple projects are joined to create a big
483 /// True if the task is a milestone.
487 * The priority is used during scheduling. The higher the priority
488 * the more likely the task will get the requested resources. */
491 /// The scheduling policy of the task.
492 SchedulingInfo scheduling;
494 /// ID of responsible resource.
495 Resource* responsible;
497 /// Tasks may only be worked on during the specified shifts.
498 ShiftSelectionList shifts;
500 /// List of resource allocations requested by the task
501 Q3PtrList<Allocation> allocations;
503 /// Account where the credits of the task are credited to.
506 TaskScenario* scenarios;
508 /* The following group of variables store values generated during a
509 * scheduler run. They might be initialized by other values and/or
510 * they might contain results of the scheduling run. But they should
511 * never be initialized directly or read out directly. They should have
512 * corresponding scenario variables. The get/set interface functions
513 * should only access the scenario variables. */
515 /// Day when the task should start
518 /// Day when the task should end
521 /// Length in working days
524 /// Effort (in man days) needed to complete the task
527 /// Duration in calender days
530 /// The already completed effort in a scheduler run.
533 /// The already completed length in a scheduler run.
536 /// The already completed duration in a scheduler run.
540 * Set to true when the first time slots have with resource usage
541 * have been allocated. */
545 * Since the full time slot might not be available we need to
546 * store the tentative start of a task in a seperate
547 * variable. Storing the information in 'start' would mark the
548 * task as fully scheduled which might not yet be the case. */
549 time_t tentativeStart;
552 * Since the full time slot might not be available we need to
553 * store the tentative end of a task in a seperate
554 * variable. Storing the information in 'end' would mark the task
555 * as fully scheduled which might not yet be the case. */
559 * Depending on the scheduling policy the tasks need to be scheduled
560 * from one end the other in a continuous way. No timeslot may be
561 * scheduled twice. This variable stores information about the last
562 * allocation, so we can make sure the next slot is exactly adjacent
563 * the the previous one. */
566 /// This variable is set to true when the task has been scheduled.
569 /** This flag is set when the task does not fit into the project time
573 /// A list of all the resources booked for this task.
574 ResourceList bookedResources;