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.
25 #include "TaskScenario.h"
26 #include "ShiftSelectionList.h"
27 #include "LoopDetectorInfo.h"
28 #include "TaskDependency.h"
43 * This class stores all task related information and provides methods to
44 * manipulte them. It provides fundamental functions like the scheduler.
46 * @short The class that holds all task related information.
49 * @author Chris Schlaeger <cs@kde.org>
51 class Task : public CoreAttributes
53 friend int TaskList::compareItemsLevel(CoreAttributes*, CoreAttributes*,
57 Task(Project* prj, const QString& id_, const QString& n, Task* p,
58 const QString& f, int l);
61 virtual CAType getType() const { return CA_Task; }
63 Task* getParent() const { return static_cast<Task*>(parent); }
65 TaskListIterator getSubListIterator() const
67 return TaskListIterator(*sub);
70 enum SchedulingInfo { ASAP, ALAP };
74 void setProjectId(const QString& i) { projectId = i; }
75 const QString& getProjectId() const { return projectId; }
77 void setNote(const QString& d) { note = d; }
78 const QString& getNote() const { return note; }
80 void addJournalEntry(JournalEntry* entry);
82 bool hasJournal() const { return !journal.isEmpty(); }
84 Journal::Iterator getJournalIterator() const;
86 void setReference(const QString& r, const QString& l)
91 const QString& getReference() const { return ref; }
92 const QString& getReferenceLabel() const { return refLabel; }
94 void setScheduling(SchedulingInfo si) { scheduling = si; }
95 SchedulingInfo getScheduling() const { return scheduling; }
97 void setPriority(int p) { priority = p; }
98 int getPriority() const { return priority; }
100 void setResponsible(Resource* r) { responsible = r; }
101 Resource* getResponsible() const { return responsible; }
103 void setMilestone(bool ms = true) { milestone = ms; }
104 bool isMilestone() const { return milestone; }
106 void setAccount(Account* a) { account = a; }
107 Account* getAccount() const { return account; }
109 TaskDependency* addDepends(const QString& id);
110 QPtrListIterator<TaskDependency> getDependsIterator() const
112 return QPtrListIterator<TaskDependency>(depends);
114 TaskDependency* addPrecedes(const QString& id);
115 QPtrListIterator<TaskDependency> getPrecedesIterator() const
117 return QPtrListIterator<TaskDependency>(precedes);
119 bool addShift(const Interval& i, Shift* s);
121 void addAllocation(Allocation* a) { allocations.append(a); }
122 void purgeAllocations() { allocations.clear(); }
123 QPtrListIterator<Allocation> getAllocationIterator() const
125 return QPtrListIterator<Allocation>(allocations);
128 TaskListIterator getPreviousIterator() const
130 return TaskListIterator(previous);
132 bool hasPrevious() const { return !previous.isEmpty(); }
134 TaskListIterator getFollowersIterator() const
136 return TaskListIterator(followers);
138 bool hasFollowers() const { return !followers.isEmpty(); }
140 bool hasPrevious(const Task* t) { return previous.findRef(t) != -1; }
141 bool hasFollower(const Task* t) { return followers.findRef(t) != -1; }
143 void collectDependencies(TaskList& list, long depth) const;
145 // The following group of functions operates only on scenario variables.
146 void setSpecifiedStart(int sc, time_t s)
148 scenarios[sc].specifiedStart = s;
150 time_t getSpecifiedStart(int sc)
152 return scenarios[sc].specifiedStart;
154 void setStart(int sc, time_t s) { scenarios[sc].start = s; }
155 time_t getStart(int sc) const { return scenarios[sc].start; }
157 void setSpecifiedEnd(int sc, time_t s)
159 scenarios[sc].specifiedEnd = s;
161 time_t getSpecifiedEnd(int sc)
163 return scenarios[sc].specifiedEnd;
165 void setEnd(int sc, time_t s) { scenarios[sc].end = s; }
166 time_t getEnd(int sc) const { return scenarios[sc].end; }
168 void setSpecifiedPeriod(int sc, const Interval& iv)
170 scenarios[sc].specifiedStart = iv.getStart();
171 scenarios[sc].specifiedEnd = iv.getEnd();
174 time_t getStartBufferEnd(int sc) const
176 return scenarios[sc].startBufferEnd;
178 time_t getEndBufferStart(int sc) const
180 return scenarios[sc].endBufferStart;
183 void setMinStart(int sc, time_t s) { scenarios[sc].minStart = s; }
184 time_t getMinStart(int sc) const { return scenarios[sc].minStart; }
186 void setMaxStart(int sc, time_t s) { scenarios[sc].maxStart = s; }
187 time_t getMaxStart(int sc) const { return scenarios[sc].maxStart; }
189 void setMinEnd(int sc, time_t e) { scenarios[sc].minEnd = e; }
190 time_t getMinEnd(int sc) const { return scenarios[sc].minEnd; }
192 void setMaxEnd(int sc, time_t e) { scenarios[sc].maxEnd = e; }
193 time_t getMaxEnd(int sc) const { return scenarios[sc].maxEnd; }
195 void setLength(int sc, double days) { scenarios[sc].length = days; }
196 double getLength(int sc) const { return scenarios[sc].length; }
198 void setEffort(int sc, double e) { scenarios[sc].effort = e; }
199 double getEffort(int sc) const { return scenarios[sc].effort; }
201 void setDuration(int sc, double d) { scenarios[sc].duration = d; }
202 double getDuration(int sc) const { return scenarios[sc].duration; }
204 bool isStartOk(int sc) const
206 return scenarios[sc].isStartOk();
208 bool isEndOk(int sc) const
210 return scenarios[sc].isEndOk();
213 bool isBuffer(int sc, const Interval& iv) const;
215 void setComplete(int sc, double c) { scenarios[sc].reportedCompletion = c; }
216 double getComplete(int sc) const
218 return scenarios[sc].reportedCompletion;
221 void setStatusNote(int sc, const QString& d)
223 scenarios[sc].statusNote = d;
225 const QString& getStatusNote(int sc) const
227 return scenarios[sc].statusNote;
230 void setStartBuffer(int sc, double p) { scenarios[sc].startBuffer = p; }
231 double getStartBuffer(int sc) const { return scenarios[sc].startBuffer; }
233 void setEndBuffer(int sc, double p) { scenarios[sc]. endBuffer = p; }
234 double getEndBuffer(int sc) const { return scenarios[sc].endBuffer; }
236 void setStartCredit(int sc, double c) { scenarios[sc].startCredit = c; }
237 double getStartCredit(int sc) const { return scenarios[sc].startCredit; }
239 void setEndCredit(int sc, double c) { scenarios[sc].endCredit = c; }
240 double getEndCredit(int sc) const { return scenarios[sc].endCredit; }
242 double getCalcEffort(int sc) const;
243 double getCalcDuration(int sc) const;
245 double getCredits(int sc, const Interval& period, AccountType acctType,
246 const Resource* resource = 0, bool recursive = true)
249 bool isActive(int sc, const Interval& period) const;
250 TaskStatus getStatus(int sc) const { return scenarios[sc].status; }
251 QString getStatusText(int sc) const;
253 QString getSchedulingText() const;
255 bool isCompleted(int sc, time_t date) const;
256 void calcCompletionDegree(int sc);
257 void calcContainerCompletionDegree(int sc, time_t now);
258 double getCompletionDegree(int sc) const;
259 double getCalcedCompletionDegree(int sc) const;
260 TaskStatus getCompletionStatus(int sc) const
262 return scenarios[sc].status;
264 double getCompletedLoad(int sc) const;
265 double getRemainingLoad(int sc) const;
267 double getLoad(int sc, const Interval& period, const Resource* resource = 0)
269 long getAllocatedTime(int sc, const Interval& period,
270 const Resource* resource = 0) const;
271 double getAllocatedTimeLoad(int sc, const Interval& period,
272 const Resource* resource = 0) const;
274 void addBookedResource(int sc, Resource* r)
276 if (scenarios[sc].bookedResources.findRef((CoreAttributes*) r) == -1)
277 scenarios[sc].bookedResources.inSort((CoreAttributes*) r);
279 bool isBookedResource(int sc, const Resource* r) const
281 return scenarios[sc].bookedResources.find((CoreAttributes*) r) != -1;
283 ResourceListIterator getBookedResourcesIterator(int sc) const
285 return ResourceListIterator(scenarios[sc].bookedResources);
287 ResourceList getBookedResources(int sc) const
289 return scenarios[sc].bookedResources;
291 void setSpecifiedScheduled(int sc, bool ps)
293 scenarios[sc].specifiedScheduled = ps;
295 bool getSpecifiedScheduled(int sc) const
297 return scenarios[sc].specifiedScheduled;
299 void setScheduled(int sc, bool ps) { scenarios[sc].scheduled = ps; }
300 bool getScheduled(int sc) const { return scenarios[sc].scheduled; }
302 bool isDutyOf(int sc, const Resource* r) const
304 return scenarios[sc].isDutyOf(r);
307 void overlayScenario(int base, int sc);
308 void prepareScenario(int sc);
309 void finishScenario(int sc);
310 void computeCriticalness(int sc);
311 double getCriticalness(int sc) const { return scenarios[sc].criticalness; }
312 void checkAndMarkCriticalPath(int sc, double minSlack, time_t maxEnd);
314 double computePathCriticalness(int sc);
315 double getPathCriticalness(int sc) const
317 return scenarios[sc].pathCriticalness;
320 bool isOnCriticalPath(int sc, bool leavesOnly = true) const
322 if (!isLeaf() && leavesOnly)
325 return scenarios[sc].isOnCriticalPath;
328 bool hasCriticalLinkTo(int sc, const Task* t) const
330 return scenarios[sc].criticalLinks.containsRef(t);
334 * @retval true if itself or one of its subtasks (recursively) is on the critical path
335 * @retval false otherwise.
337 bool isOrHasDescendantOnCriticalPath(int sc) const;
339 bool isContainer() const { return !sub->isEmpty(); }
341 bool xRef(QDict<Task>& hash);
343 void sortAllocations();
344 void saveSpecifiedBookedResources();
345 QString resolveId(QString relId);
347 bool preScheduleOk(int sc);
348 bool scheduleOk(int sc) const;
350 * Checks for loops in task interdependencies starting with the current
352 * @param ckedTaskList The list of already checked tasks. Will be appended
354 * @retval true if a loop was detected.
355 * @retval false otherwise.
357 bool loopDetector(LDIList& chkedTaskList) const;
358 bool checkDetermination(int sc) const;
359 void computeBuffers();
360 time_t nextSlot(time_t slotDuration) const;
361 bool isReadyForScheduling() const;
362 bool schedule(int sc, time_t& reqStart, time_t duration);
363 void propagateInitialValues(int sc);
365 bool isRunaway() const;
367 bool isSubTask(const Task* t) const;
369 bool isSchedulingDone() const { return schedulingDone; }
371 void errorMessage(const QString& msg) const;
372 void warningMessage(const QString& msg) const;
374 QDomElement xmlElement( QDomDocument& doc, bool absId = true );
377 void propagateStart(int sc, time_t date);
378 void propagateEnd(int sc, time_t date);
380 * Checks for loops in task interdependencies starting with the current
381 * task under ASAP or ALAP scheduling.
382 * @param ckedTaskList The list of already checked tasks. Will be appended
384 * @retval true if a loop was detected.
385 * @retval false otherwise.
387 bool loopDetection(LDIList& list, LDIList& chkedTaskList, bool atEnd,
388 bool fromOutside) const;
389 bool checkPathForLoops(LDIList& list, bool atEnd) const;
390 bool scheduleContainer(int sc);
391 Task* subFirst() { return (Task*) sub->first(); }
392 Task* subNext() { return (Task*) sub->next(); }
393 bool bookResource(Resource* r, time_t day, time_t duration,
394 int& slotsToLimit, int& availability);
395 void bookResources(int sc, time_t day, time_t duration);
396 void addBookedResource(Resource* r)
398 if (bookedResources.findRef((CoreAttributes*) r) == -1)
399 bookedResources.inSort((CoreAttributes*) r);
401 QPtrList<Resource> createCandidateList(int sc, time_t date, Allocation* a);
402 time_t earliestStart(int sc) const;
403 time_t latestEnd(int sc) const;
405 bool startCanBeDetermined(LDIList& list, int sc) const;
406 bool endCanBeDetermined(LDIList& list, int sc) const;
408 bool hasStartDependency(int sc) const;
409 bool hasEndDependency(int sc) const;
411 bool hasStartDependency() const;
412 bool hasEndDependency() const;
414 bool analyzePath(int sc, double minSlack, time_t pathStart, long busyTime,
415 long worstMinSlackTime, long& checked, long& found);
416 void collectTransientFollowers(TaskList& list);
418 bool countMilestones(int sc, time_t now, int& totalMilestones,
419 int& completedMilestones,
420 int& reportedCompletedMilestones);
421 bool sumUpEffort(int sc, time_t now, double& totalEffort,
422 double& completedEffort,
423 double& reportedCompletedEffort);
425 /// A longer description of the task.
428 /// List of notes with a date attached.
431 /// A reference to an external document
434 /// A label used instead of the reference
438 * The dependencies of the task are stored twice. depends and precedes
439 * store the information specified in the project file. For convenience we
440 * also store the backward dependency together with the specified
441 * dependencies in predecessors and successors.
443 QPtrList<TaskDependency> depends;
446 QPtrList<TaskDependency> precedes;
449 * A list of tasks that must precede this task.
451 TaskList predecessors;
454 * A list of tasks that must follow this task.
459 * A list of all tasks that preceed this task. It's the combination of
460 * depends and predecessors. This is redundant information but stored for
461 * conveniance. Interdependent tasks are linked in a doubly linked list.
466 * A list of all tasks that follow this task. It's the combination of
467 * precedes and successors. This is redundant information but stored for
468 * conveniance. Interdependent tasks are linked in a doubly linked list.
473 * The ID of the project this task belongs to. This is only
474 * meaningful if multiple projects are joined to create a big
478 /// True if the task is a milestone.
482 * The priority is used during scheduling. The higher the priority
483 * the more likely the task will get the requested resources. */
486 /// The scheduling policy of the task.
487 SchedulingInfo scheduling;
489 /// ID of responsible resource.
490 Resource* responsible;
492 /// Tasks may only be worked on during the specified shifts.
493 ShiftSelectionList shifts;
495 /// List of resource allocations requested by the task
496 QPtrList<Allocation> allocations;
498 /// Account where the credits of the task are credited to.
501 TaskScenario* scenarios;
503 /* The following group of variables store values generated during a
504 * scheduler run. They might be initialized by other values and/or
505 * they might contain results of the scheduling run. But they should
506 * never be initialized directly or read out directly. They should have
507 * corresponding scenario variables. The get/set interface functions
508 * should only access the scenario variables. */
510 /// Day when the task should start
513 /// Day when the task should end
516 /// Length in working days
519 /// Effort (in man days) needed to complete the task
522 /// Duration in calender days
525 /// The already completed effort in a scheduler run.
528 /// The already completed length in a scheduler run.
531 /// The already completed duration in a scheduler run.
535 * Set to true when the first time slots have with resource usage
536 * have been allocated. */
540 * Since the full time slot might not be available we need to
541 * store the tentative start of a task in a seperate
542 * variable. Storing the information in 'start' would mark the
543 * task as fully scheduled which might not yet be the case. */
544 time_t tentativeStart;
547 * Since the full time slot might not be available we need to
548 * store the tentative end of a task in a seperate
549 * variable. Storing the information in 'end' would mark the task
550 * as fully scheduled which might not yet be the case. */
554 * Depending on the scheduling policy the tasks need to be scheduled
555 * from one end the other in a continuous way. No timeslot may be
556 * scheduled twice. This variable stores information about the last
557 * allocation, so we can make sure the next slot is exactly adjacent
558 * the the previous one. */
561 /// This variable is set to true when the task has been scheduled.
564 /** This flag is set when the task does not fit into the project time
568 /// A list of all the resources booked for this task.
569 ResourceList bookedResources;