OSDN Git Service

Automatically align underspecified tasks boundaries on project boundaries when possible.
[tjqt4port/tj2qt4.git] / taskjuggler / Task.h
1 /*
2  * task.h - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006
5  * Chris Schlaeger <cs@kde.org>
6  *
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.
10  *
11  * $Id$
12  */
13
14 #ifndef _Task_h_
15 #define _Task_h_
16
17 #include <config.h>
18
19 #include <stdarg.h>
20
21 #include <qdom.h>
22
23 #include "debug.h"
24 #include "TaskList.h"
25 #include "TaskScenario.h"
26 #include "ShiftSelectionList.h"
27 #include "LoopDetectorInfo.h"
28 #include "TaskDependency.h"
29 #include "Journal.h"
30
31 class Project;
32 class Resource;
33 class Account;
34 class Shift;
35 class TaskList;
36 class QDomElement;
37 class QDomDocument;
38 class Allocation;
39 class Interval;
40 class UsageLimits;
41
42 /**
43  * This class stores all task related information and provides methods to
44  * manipulte them. It provides fundamental functions like the scheduler.
45  *
46  * @short The class that holds all task related information.
47  * @see Resource
48  * @see CoreAttributes
49  * @author Chris Schlaeger <cs@kde.org>
50  */
51 class Task : public CoreAttributes
52 {
53     friend int TaskList::compareItemsLevel(CoreAttributes*, CoreAttributes*,
54                                            int);
55
56 public:
57     Task(Project* prj, const QString& id_, const QString& n, Task* p,
58          const QString& f, int l);
59     virtual ~Task();
60
61     virtual CAType getType() const { return CA_Task; }
62
63     Task* getParent() const { return static_cast<Task*>(parent); }
64
65     TaskListIterator getSubListIterator() const
66     {
67         return TaskListIterator(*sub);
68     }
69
70     enum SchedulingInfo { ASAP, ALAP };
71
72     void inheritValues();
73
74     void setProjectId(const QString& i) { projectId = i; }
75     const QString& getProjectId() const { return projectId; }
76
77     void setNote(const QString& d) { note = d; }
78     const QString& getNote() const { return note; }
79
80     void addJournalEntry(JournalEntry* entry);
81
82     bool hasJournal() const { return !journal.isEmpty(); }
83
84     Journal::Iterator getJournalIterator() const;
85
86     void setReference(const QString& r, const QString& l)
87     {
88         ref = r;
89         refLabel = l;
90     }
91     const QString& getReference() const { return ref; }
92     const QString& getReferenceLabel() const { return refLabel; }
93
94     void setScheduling(SchedulingInfo si) { scheduling = si; }
95     SchedulingInfo getScheduling() const { return scheduling; }
96
97     void setPriority(int p) { priority = p; }
98     int getPriority() const { return priority; }
99
100     void setResponsible(Resource* r) { responsible = r; }
101     Resource* getResponsible() const { return responsible; }
102
103     void setMilestone(bool ms = true) { milestone = ms; }
104     bool isMilestone() const { return milestone; }
105
106     void setAccount(Account* a) { account = a; }
107     Account* getAccount() const { return account; }
108
109     TaskDependency* addDepends(const QString& id);
110     QPtrListIterator<TaskDependency> getDependsIterator() const
111     {
112         return QPtrListIterator<TaskDependency>(depends);
113     }
114     TaskDependency* addPrecedes(const QString& id);
115     QPtrListIterator<TaskDependency> getPrecedesIterator() const
116     {
117         return QPtrListIterator<TaskDependency>(precedes);
118     }
119     bool addShift(const Interval& i, Shift* s);
120
121     void addAllocation(Allocation* a) { allocations.append(a); }
122     void purgeAllocations() { allocations.clear(); }
123     QPtrListIterator<Allocation> getAllocationIterator() const
124     {
125         return QPtrListIterator<Allocation>(allocations);
126     }
127
128     TaskListIterator getPreviousIterator() const
129     {
130         return TaskListIterator(previous);
131     }
132     bool hasPrevious() const { return !previous.isEmpty(); }
133
134     TaskListIterator getFollowersIterator() const
135     {
136         return TaskListIterator(followers);
137     }
138     bool hasFollowers() const { return !followers.isEmpty(); }
139
140     bool hasPrevious(const Task* t) { return previous.findRef(t) != -1; }
141     bool hasFollower(const Task* t) { return followers.findRef(t) != -1; }
142
143     void collectDependencies(TaskList& list, long depth) const;
144
145     // The following group of functions operates only on scenario variables.
146     void setSpecifiedStart(int sc, time_t s)
147     {
148         scenarios[sc].specifiedStart = s;
149     }
150     time_t getSpecifiedStart(int sc)
151     {
152         return scenarios[sc].specifiedStart;
153     }
154     void setStart(int sc, time_t s) { scenarios[sc].start = s; }
155     time_t getStart(int sc) const { return scenarios[sc].start; }
156
157     void setSpecifiedEnd(int sc, time_t s)
158     {
159         scenarios[sc].specifiedEnd = s;
160     }
161     time_t getSpecifiedEnd(int sc)
162     {
163         return scenarios[sc].specifiedEnd;
164     }
165     void setEnd(int sc, time_t s) { scenarios[sc].end = s; }
166     time_t getEnd(int sc) const { return scenarios[sc].end; }
167
168     void setSpecifiedPeriod(int sc, const Interval& iv)
169     {
170         scenarios[sc].specifiedStart = iv.getStart();
171         scenarios[sc].specifiedEnd = iv.getEnd();
172     }
173
174     time_t getStartBufferEnd(int sc) const
175     {
176         return scenarios[sc].startBufferEnd;
177     }
178     time_t getEndBufferStart(int sc) const
179     {
180         return scenarios[sc].endBufferStart;
181     }
182
183     void setMinStart(int sc, time_t s) { scenarios[sc].minStart = s; }
184     time_t getMinStart(int sc) const { return scenarios[sc].minStart; }
185
186     void setMaxStart(int sc, time_t s) { scenarios[sc].maxStart = s; }
187     time_t getMaxStart(int sc) const { return scenarios[sc].maxStart; }
188
189     void setMinEnd(int sc, time_t e) { scenarios[sc].minEnd = e; }
190     time_t getMinEnd(int sc) const { return scenarios[sc].minEnd; }
191
192     void setMaxEnd(int sc, time_t e) { scenarios[sc].maxEnd = e; }
193     time_t getMaxEnd(int sc) const { return scenarios[sc].maxEnd; }
194
195     void setLength(int sc, double days) { scenarios[sc].length = days; }
196     double getLength(int sc) const { return scenarios[sc].length; }
197
198     void setEffort(int sc, double e) { scenarios[sc].effort = e; }
199     double getEffort(int sc) const { return scenarios[sc].effort; }
200
201     void setDuration(int sc, double d) { scenarios[sc].duration = d; }
202     double getDuration(int sc) const { return scenarios[sc].duration; }
203
204     bool isStartOk(int sc) const
205     {
206         return scenarios[sc].isStartOk();
207     }
208     bool isEndOk(int sc) const
209     {
210         return scenarios[sc].isEndOk();
211     }
212
213     bool isBuffer(int sc, const Interval& iv) const;
214
215     void setComplete(int sc, double c) { scenarios[sc].reportedCompletion = c; }
216     double getComplete(int sc) const
217     {
218         return scenarios[sc].reportedCompletion;
219     }
220
221     void setStatusNote(int sc, const QString& d)
222     {
223         scenarios[sc].statusNote = d;
224     }
225     const QString& getStatusNote(int sc) const
226     {
227         return scenarios[sc].statusNote;
228     }
229
230     void setStartBuffer(int sc, double p) { scenarios[sc].startBuffer = p; }
231     double getStartBuffer(int sc) const { return scenarios[sc].startBuffer; }
232
233     void setEndBuffer(int sc, double p) { scenarios[sc]. endBuffer = p; }
234     double getEndBuffer(int sc) const { return scenarios[sc].endBuffer; }
235
236     void setStartCredit(int sc, double c) { scenarios[sc].startCredit = c; }
237     double getStartCredit(int sc) const { return scenarios[sc].startCredit; }
238
239     void setEndCredit(int sc, double c) { scenarios[sc].endCredit = c; }
240     double getEndCredit(int sc) const { return scenarios[sc].endCredit; }
241
242     double getCalcEffort(int sc) const;
243     double getCalcDuration(int sc) const;
244
245     double getCredits(int sc, const Interval& period, AccountType acctType,
246                       const Resource* resource = 0, bool recursive = true)
247         const;
248
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;
252
253     QString getSchedulingText() const;
254
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
261     {
262         return scenarios[sc].status;
263     }
264     double getCompletedLoad(int sc) const;
265     double getRemainingLoad(int sc) const;
266
267     double getLoad(int sc, const Interval& period, const Resource* resource = 0)
268         const;
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;
273
274     void addBookedResource(int sc, Resource* r)
275     {
276         if (scenarios[sc].bookedResources.findRef((CoreAttributes*) r) == -1)
277             scenarios[sc].bookedResources.inSort((CoreAttributes*) r);
278     }
279     bool isBookedResource(int sc, const Resource* r) const
280     {
281         return scenarios[sc].bookedResources.find((CoreAttributes*) r) != -1;
282     }
283     ResourceListIterator getBookedResourcesIterator(int sc) const
284     {
285         return ResourceListIterator(scenarios[sc].bookedResources);
286     }
287     ResourceList getBookedResources(int sc) const
288     {
289         return scenarios[sc].bookedResources;
290     }
291     void setSpecifiedScheduled(int sc, bool ps)
292     {
293         scenarios[sc].specifiedScheduled = ps;
294     }
295     bool getSpecifiedScheduled(int sc) const
296     {
297         return scenarios[sc].specifiedScheduled;
298     } 
299     void setScheduled(int sc, bool ps) { scenarios[sc].scheduled = ps; }
300     bool getScheduled(int sc) const { return scenarios[sc].scheduled; }
301
302     bool isDutyOf(int sc, const Resource* r) const
303     {
304         return scenarios[sc].isDutyOf(r);
305     }
306
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);
313
314     double computePathCriticalness(int sc);
315     double getPathCriticalness(int sc) const
316     {
317         return scenarios[sc].pathCriticalness;
318     }
319
320     bool isOnCriticalPath(int sc, bool leavesOnly = true) const
321     {
322         if (!isLeaf() && leavesOnly)
323             return false;
324
325         return scenarios[sc].isOnCriticalPath;
326     }
327
328     bool hasCriticalLinkTo(int sc, const Task* t) const
329     {
330         return scenarios[sc].criticalLinks.containsRef(t);
331     }
332
333     /**
334      * @retval true if itself or one of its subtasks (recursively) is on the critical path
335      * @retval false otherwise.
336      */
337     bool isOrHasDescendantOnCriticalPath(int sc) const;
338
339     bool isContainer() const { return !sub->isEmpty(); }
340
341     bool xRef(QDict<Task>& hash);
342     void implicitXRef();
343     void sortAllocations();
344     void saveSpecifiedBookedResources();
345     QString resolveId(QString relId);
346
347     bool preScheduleOk(int sc);
348     bool scheduleOk(int sc) const;
349     /**
350      * Checks for loops in task interdependencies starting with the current
351      * task.
352      * @param ckedTaskList The list of already checked tasks. Will be appended
353      * to.
354      * @retval true if a loop was detected.
355      * @retval false otherwise.
356      */
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);
364     void setRunaway();
365     bool isRunaway() const;
366
367     bool isSubTask(const Task* t) const;
368
369     bool isSchedulingDone() const { return schedulingDone; }
370
371     void errorMessage(const QString& msg) const;
372     void warningMessage(const QString& msg) const;
373
374     QDomElement xmlElement( QDomDocument& doc, bool absId = true );
375
376 private:
377     void propagateStart(int sc, time_t date);
378     void propagateEnd(int sc, time_t date);
379     /**
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
383      * to.
384      * @retval true if a loop was detected.
385      * @retval false otherwise.
386      */
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)
397     {
398         if (bookedResources.findRef((CoreAttributes*) r) == -1)
399             bookedResources.inSort((CoreAttributes*) r);
400     }
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;
404
405     bool startCanBeDetermined(LDIList& list, int sc) const;
406     bool endCanBeDetermined(LDIList& list, int sc) const;
407
408     bool hasStartDependency(int sc) const;
409     bool hasEndDependency(int sc) const;
410
411     bool hasStartDependency() const;
412     bool hasEndDependency() const;
413
414     bool analyzePath(int sc, double minSlack, time_t pathStart, long busyTime,
415                      long worstMinSlackTime, long& checked, long& found);
416     void collectTransientFollowers(TaskList& list);
417
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);
424
425     /// A longer description of the task.
426     QString note;
427
428     /// List of notes with a date attached.
429     Journal journal;
430
431     /// A reference to an external document
432     QString ref;
433
434     /// A label used instead of the reference
435     QString refLabel;
436
437     /**
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.
442      */
443     QPtrList<TaskDependency> depends;
444
445     /// @see depends
446     QPtrList<TaskDependency> precedes;
447
448     /**
449      * A list of tasks that must precede this task.
450      */
451     TaskList predecessors;
452
453     /**
454      * A list of tasks that must follow this task.
455      */
456     TaskList successors;
457
458     /**
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.
462      */
463     TaskList previous;
464
465     /**
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.
469      */
470     TaskList followers;
471
472     /**
473      * The ID of the project this task belongs to. This is only
474      * meaningful if multiple projects are joined to create a big
475      * project. */
476     QString projectId;
477
478     /// True if the task is a milestone.
479     bool milestone;
480
481     /**
482      * The priority is used during scheduling. The higher the priority
483      * the more likely the task will get the requested resources. */
484     int priority;
485
486     /// The scheduling policy of the task.
487     SchedulingInfo scheduling;
488
489     /// ID of responsible resource.
490     Resource* responsible;
491
492     /// Tasks may only be worked on during the specified shifts.
493     ShiftSelectionList shifts;
494
495     /// List of resource allocations requested by the task
496     QPtrList<Allocation> allocations;
497
498     /// Account where the credits of the task are credited to.
499     Account* account;
500
501     TaskScenario* scenarios;
502
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. */
509
510     /// Day when the task should start
511     time_t start;
512
513     /// Day when the task should end
514     time_t end;
515
516     /// Length in working days
517     double length;
518
519     /// Effort (in man days) needed to complete the task
520     double effort;
521
522     /// Duration in calender days
523     double duration;
524
525     /// The already completed effort in a scheduler run.
526     double doneEffort;
527
528     /// The already completed length in a scheduler run.
529     double doneLength;
530
531     /// The already completed duration in a scheduler run.
532     double doneDuration;
533
534     /**
535      * Set to true when the first time slots have with resource usage
536      * have been allocated. */
537     bool workStarted;
538
539     /**
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;
545
546     /**
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. */
551     time_t tentativeEnd;
552
553     /**
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. */
559     time_t lastSlot;
560
561     /// This variable is set to true when the task has been scheduled.
562     bool schedulingDone;
563
564     /** This flag is set when the task does not fit into the project time
565      * frame. */
566     bool runAway;
567
568     /// A list of all the resources booked for this task.
569     ResourceList bookedResources;
570 } ;
571
572 #endif