OSDN Git Service

- Copyright 2002 added
[tjqt4port/tj2qt4.git] / taskjuggler / Project.cpp
1 /*
2  * Project.cpp - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002 by Chris Schlaeger <cs@suse.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of version 2 of the GNU General Public License as
8  * published by the Free Software Foundation.
9  *
10  * $Id$
11  */
12
13 #include <config.h>
14 #include <stdio.h>
15
16 #include <qdict.h>
17
18 #include "Project.h"
19 #include "Utility.h"
20
21 int Project::debugLevel = 0;
22
23 Project::Project()
24 {
25         taskList.setAutoDelete(TRUE);
26         resourceList.setAutoDelete(TRUE);
27         activeAsap.setSorting(CoreAttributesList::PrioDown);
28         activeAlap.setSorting(CoreAttributesList::PrioDown);
29         priority = 500;
30         dailyWorkingHours = 8.0;
31         scheduleGranularity = ONEHOUR;
32         start = 0;
33         end = 0;
34         now = time(0);
35         copyright = "";
36         minEffort = 0.0;
37         maxEffort = 1.0;
38         rate = 0.0;
39         currency = "";
40         currencyDigits = 3;
41         xmlreport = 0L;
42 }
43
44 bool
45 Project::addId(const QString& id)
46 {
47         if (projectIDs.findIndex(id) != -1)
48                 return FALSE;
49         else
50                 projectIDs.append(id);
51         return TRUE;
52 }
53
54 QString
55 Project::getIdIndex(const QString& i) const
56 {
57         int idx;
58         if ((idx = projectIDs.findIndex(i)) == -1)
59                 return QString("?");
60         QString idxStr;
61         do
62         {
63                 idxStr = QChar('A' + idx % ('Z' - 'A')) + idxStr;
64                 idx /= 'Z' - 'A';
65         } while (idx > 'Z' - 'A');
66
67         return idxStr;
68 }
69
70 bool
71 Project::addTask(Task* t)
72 {
73         taskList.append(t);
74         return TRUE;
75 }
76
77 bool
78 Project::pass2()
79 {
80         QDict<Task> idHash;
81         bool error = FALSE;
82
83         taskList.createIndex();
84         resourceList.createIndex();
85         accountList.createIndex();
86
87         // Create hash to map task IDs to pointers.
88         for (Task* t = taskList.first(); t != 0; t = taskList.next())
89         {
90                 idHash.insert(t->getId(), t);
91         }
92
93         // Create cross links from dependency lists.
94         for (Task* t = taskList.first(); t != 0; t = taskList.next())
95         {
96                 if (!t->xRef(idHash))
97                         error = TRUE;
98         }
99
100         bool hasActualValues = FALSE;
101         for (Task* t = taskList.first(); t != 0; t = taskList.next())
102         {
103                 if (!t->preScheduleOk())
104                         error = TRUE;
105                 if (t->hasActualValues())
106                         hasActualValues = TRUE;
107         }
108
109         if (error)
110                 return FALSE;
111
112         if (debugLevel > 0)
113                 qWarning("Scheduling plan scenario...");
114         preparePlan();
115         schedule();
116         finishPlan();
117
118         if (hasActualValues)
119         {
120                 if (debugLevel > 0)
121                         qWarning("Scheduling actual scenario...");
122                 prepareActual();
123                 schedule();
124                 finishActual();
125         }
126
127         return TRUE;
128 }
129
130 void
131 Project::preparePlan()
132 {
133         for (Task* t = taskList.first(); t != 0; t = taskList.next())
134                 t->preparePlan();
135         for (Task* t = taskList.first(); t != 0; t = taskList.next())
136                 t->propagateInitialValues();
137         for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
138                 r->preparePlan();
139 }
140
141 void
142 Project::finishPlan()
143 {
144         for (Task* t = taskList.first(); t != 0; t = taskList.next())
145                 t->finishPlan();
146         for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
147                 r->finishPlan();
148 }
149
150 void
151 Project::prepareActual()
152 {
153         for (Task* t = taskList.first(); t != 0; t = taskList.next())
154                 t->prepareActual();
155         for (Task* t = taskList.first(); t != 0; t = taskList.next())
156                 t->propagateInitialValues();
157         for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
158                 r->prepareActual();
159 }
160
161 void
162 Project::finishActual()
163 {
164         for (Task* t = taskList.first(); t != 0; t = taskList.next())
165                 t->finishActual();
166         for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
167                 r->finishActual();
168 }
169
170 bool
171 Project::schedule()
172 {
173         bool error = FALSE;
174
175         TaskList sortedTasks(taskList);
176         sortedTasks.setSorting(CoreAttributesList::PrioDown);
177         sortedTasks.sort();
178
179         time_t timeDelta = scheduleGranularity;
180         bool done = FALSE;
181         time_t day;
182
183         updateActiveTaskList(sortedTasks);
184         for (day = start; !(activeAsap.isEmpty() && activeAlap.isEmpty()) &&
185                          day >= start && day < end; day += timeDelta)
186         {
187                 timeDelta = scheduleGranularity;
188                 do
189                 {
190                         done = TRUE;
191                         for (Task* t = activeAlap.first(); t != 0; t = activeAlap.next())
192                         {
193                                 if (!t->schedule(day, scheduleGranularity))
194                                 {
195                                         done = FALSE;
196                                         break;  // Start with top priority tasks again.
197                                 }
198                                 if (t->needsEarlierTimeSlot(day + scheduleGranularity))
199                                         timeDelta = -scheduleGranularity;
200                         }
201                 } while (!done);
202
203                 if (timeDelta < 0)
204                         continue;
205                 uint i = 0;
206                 do
207                 {
208                         done = TRUE;
209                         i = 0;
210                         for (Task* t = activeAsap.first(); t != 0; t = activeAsap.next())
211                         {
212                                 i++;
213                                 if (!t->schedule(day, scheduleGranularity))
214                                 {
215                                         done = FALSE;
216                                         break;  // Start with top priority tasks again.
217                                 }
218                         }
219                 } while (!done);
220                 if (i != activeAsap.count())
221                         qFatal("activeAsap list corrupted");
222         }
223
224         if (!activeAsap.isEmpty() || !activeAlap.isEmpty())
225         {
226                 for (Task* t = activeAsap.first(); t != 0; t = activeAsap.next())
227                         qWarning("Task %s does not fit into the project time frame",
228                                          t->getId().latin1());
229                 for (Task* t = activeAlap.first(); t != 0; t = activeAlap.next())
230                         qWarning("Task %s does not fit into the project time frame",
231                                          t->getId().latin1());
232                 error = TRUE;
233         }
234
235         if (!checkSchedule())
236                 error = TRUE;
237
238         return !error;
239 }
240
241 void
242 Project::updateActiveTaskList(TaskList& sortedTasks)
243 {
244         for (Task* t = sortedTasks.first(); t != 0; t = sortedTasks.next())
245                 if (t->isActive())
246                         addActiveTask(t);
247 }
248
249 bool
250 Project::checkSchedule()
251 {
252         TaskList tl = taskList;
253         tl.setSorting(CoreAttributesList::StartDown);
254         tl.sort();
255         int errors = 0;
256         for (Task* t = tl.first(); t != 0; t = tl.next())
257         {
258                 if (!t->scheduleOk())
259                         errors++;
260                 if (errors >= 10)
261                         break;
262         }
263
264         return errors == 0;
265 }
266
267 void
268 Project::generateReports()
269 {
270         if (debugLevel > 0)
271                 qWarning("Generating reports...");
272
273         // Generate task reports
274         for (HTMLTaskReport* h = htmlTaskReports.first(); h != 0;
275                  h = htmlTaskReports.next())
276                 h->generate();
277
278         // Generate resource reports
279         for (HTMLResourceReport* r = htmlResourceReports.first(); r != 0;
280                  r = htmlResourceReports.next())
281                 r->generate();
282
283         // Generate account reports
284         for (HTMLAccountReport* r = htmlAccountReports.first(); r != 0;
285                  r = htmlAccountReports.next())
286                 r->generate();
287
288         for (ExportReport* e = exportReports.first(); e != 0;
289                  e = exportReports.next())
290                 e->generate();
291
292         if( xmlreport )
293            xmlreport->generate();
294 }
295
296 bool
297 Project::needsActualDataForReports()
298 {
299         bool needsActual = FALSE;
300
301         // Generate task reports
302         for (HTMLTaskReport* h = htmlTaskReports.first(); h != 0;
303                  h = htmlTaskReports.next())
304                 if (h->getShowActual())
305                         needsActual = TRUE;
306         // Generate resource reports
307         for (HTMLResourceReport* h = htmlResourceReports.first(); h != 0;
308                  h = htmlResourceReports.next())
309                 if (h->getShowActual())
310                         needsActual = TRUE;
311
312         // Generate account reports
313         for (HTMLAccountReport* h = htmlAccountReports.first(); h != 0;
314                  h = htmlAccountReports.next())
315                 if (h->getShowActual())
316                         needsActual = TRUE;
317
318         return needsActual;
319 }
320
321 void
322 Project::removeActiveTask(Task* t)
323 {
324         t->setScheduled();
325
326         if (debugLevel > 2)
327                 qWarning("Deactivating %s", t->getId().latin1());
328
329         if (t->getScheduling() == Task::ASAP)
330                 activeAsap.removeRef(t);
331         else
332                 activeAlap.removeRef(t);
333 }
334
335 void
336 Project::addActiveTask(Task* t)
337 {
338         if (t->getScheduling() == Task::ASAP)
339         {
340                 if (activeAsap.findRef(t) == -1)
341                 {
342                         if (debugLevel > 2)
343                                 qWarning("Activating %s", t->getId().latin1());
344                         activeAsap.inSort(t);
345                 }
346         }
347         else
348         {
349                 if (activeAlap.findRef(t) == -1)
350                 {
351                         if (debugLevel > 2)
352                                 qWarning("Activating %s", t->getId().latin1()); 
353                         activeAlap.inSort(t);
354                 }
355         }
356 }