OSDN Git Service

Merge branch 'post-2.4.2'
[tjqt4port/tj2qt4.git] / taskjuggler / Report.cpp
1 /*
2  * Report.cpp - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004 by Chris Schlaeger <cs@kde.org>
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 "Report.h"
14
15 #include "TjMessageHandler.h"
16 #include "tjlib-internal.h"
17 #include "Project.h"
18 #include "Resource.h"
19 #include "Account.h"
20 #include "ExpressionTree.h"
21 #include "TaskTreeIterator.h"
22 #include "ResourceTreeIterator.h"
23 #include "AccountTreeIterator.h"
24
25
26 Report::Report(Project* p, const QString& f, const QString& df, int dl) :
27     project(p),
28     fileName(f),
29     defFileName(df),
30     defFileLine(dl),
31     f(),
32     s(),
33     scenarios(),
34     weekStartsMonday(p->getWeekStartsMonday()),
35     headline(),
36     caption(),
37     maxDepthTaskList(1),
38     maxDepthResourceList(1),
39     maxDepthAccountList(1),
40     columns(),
41     start(p->getStart()),
42     end(p->getEnd()),
43     timeFormat(p->getTimeFormat()),
44     shortTimeFormat(p->getShortTimeFormat()),
45     numberFormat(p->getNumberFormat()),
46     currencyFormat(p->getCurrencyFormat()),
47     taskSortCriteria(),
48     resourceSortCriteria(),
49     accountSortCriteria(),
50     hideTask(0),
51     hideResource(0),
52     hideAccount(0),
53     rollUpTask(0),
54     rollUpResource(0),
55     rollUpAccount(0),
56     taskRoot()
57 {
58     for (int i = 0; i < CoreAttributesList::maxSortingLevel; ++i)
59     {
60         taskSortCriteria[i] = CoreAttributesList::SequenceUp;
61         resourceSortCriteria[i] = CoreAttributesList::SequenceUp;
62         accountSortCriteria[i] = CoreAttributesList::SequenceUp;
63     }
64
65     showPIDs = false;
66     loadUnit = days;
67     timeStamp = true;
68 }
69
70 Report::~Report()
71 {
72     delete hideTask;
73     delete rollUpTask;
74     delete hideResource;
75     delete rollUpResource;
76     delete hideAccount;
77     delete rollUpAccount;
78 }
79
80 bool
81 Report::open()
82 {
83     if (fileName == "--" || fileName == ".")
84     {
85         if (!f.open(IO_WriteOnly, stdout))
86         {
87             TJMH.errorMessage(i18n("Cannout open stdout"));
88             return false;
89         }
90     }
91     else
92     {
93         QString fullFileName = getFullFileName();
94         f.setName(fullFileName);
95
96         if (!f.open(IO_WriteOnly))
97         {
98             TJMH.errorMessage
99                 (QString(i18n("Cannot open report file %1!\n"))
100                  .arg(fullFileName.latin1()));
101             return false;
102         }
103     }
104     s.setDevice(&f);
105     return true;
106 }
107
108 bool
109 Report::close()
110 {
111     f.close();
112     return true;
113 }
114
115 QString
116 Report::getFullFileName() const
117 {
118     QString fullFileName = fileName;
119     // Check if the fileName is not an absolute file name.
120     if (fileName[0] != '/')
121     {
122         // Prepend the path of the file where the report was defined, so
123         // relative report file names are always interpreted relative to
124         // their definition.
125         QString path;
126         if (defFileName[0] == '/')
127             path = defFileName.left(defFileName.findRev('/', -1) + 1);
128         fullFileName = path + fileName;
129     }
130
131     return fullFileName;
132 }
133
134 bool
135 Report::setTaskSorting(int sc, int level)
136 {
137     if (level >= 0 && level < CoreAttributesList::maxSortingLevel)
138     {
139         if ((sc == CoreAttributesList::TreeMode && level > 0) ||
140             !TaskList::isSupportedSortingCriteria(sc & 0xFFFF))
141             return false;
142         taskSortCriteria[level] = sc;
143     }
144     else
145         return false;
146     return true;
147 }
148
149 bool
150 Report::setResourceSorting(int sc, int level)
151 {
152     if (level >= 0 && level < CoreAttributesList::maxSortingLevel)
153     {
154         if ((sc == CoreAttributesList::TreeMode && level > 0) ||
155             !ResourceList::isSupportedSortingCriteria(sc & 0xFFFF))
156             return false;
157         resourceSortCriteria[level] = sc;
158     }
159     else
160         return false;
161     return true;
162 }
163
164 bool
165 Report::setAccountSorting(int sc, int level)
166 {
167     if (level >= 0 && level < CoreAttributesList::maxSortingLevel)
168     {
169         if ((sc == CoreAttributesList::TreeMode && level > 0) ||
170             !AccountList::isSupportedSortingCriteria(sc & 0xFFFF))
171             return false;
172         accountSortCriteria[level] = sc;
173     }
174     else
175         return false;
176     return true;
177 }
178
179 bool
180 Report::isHidden(const CoreAttributes* c, ExpressionTree* et) const
181 {
182     if (!taskRoot.isEmpty() && c->getType() == CA_Task &&
183         taskRoot != c->getId().left(taskRoot.length()))
184     {
185         return true;
186     }
187
188     if (!et)
189         return false;
190
191     et->clearSymbolTable();
192     QStringList allFlags = project->getAllowedFlags();
193     for (QStringList::Iterator ait = allFlags.begin(); ait != allFlags.end();
194          ++ait)
195     {
196         bool found = false;
197         QStringList flags = c->getFlagList();
198         for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
199             if (*it == *ait)
200             {
201                 et->registerSymbol(*it, 1);
202                 found = true;
203                 break;
204             }
205         if (!found)
206             et->registerSymbol(*ait, 0);
207     }
208     return et->evalAsInt(c) != 0;
209 }
210
211 bool
212 Report::isRolledUp(const CoreAttributes* c, ExpressionTree* et) const
213 {
214     if (!et)
215         return false;
216
217     et->clearSymbolTable();
218     QStringList allFlags = project->getAllowedFlags();
219     for (QStringList::Iterator ait = allFlags.begin(); ait != allFlags.end();
220          ++ait)
221     {
222         bool found = false;
223         QStringList flags = c->getFlagList();
224         for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
225             if (*it == *ait)
226             {
227                 et->registerSymbol(*it, 1);
228                 found = true;
229                 break;
230             }
231         if (!found)
232             et->registerSymbol(*ait, 0);
233     }
234     return et->evalAsInt(c) != 0;
235 }
236
237 void
238 Report::setHideTask(ExpressionTree* et)
239 {
240     delete hideTask;
241     hideTask = et;
242 }
243
244 void
245 Report::setRollUpTask(ExpressionTree* et)
246 {
247     delete rollUpTask;
248     rollUpTask = et;
249 }
250
251 void
252 Report::setHideResource(ExpressionTree* et)
253 {
254     delete hideResource;
255     hideResource = et;
256 }
257
258 void
259 Report::setRollUpResource(ExpressionTree* et)
260 {
261     delete rollUpResource;
262     rollUpResource = et;
263 }
264
265 void
266 Report::setHideAccount(ExpressionTree* et)
267 {
268     delete hideAccount;
269     hideAccount = et;
270 }
271
272 void
273 Report::setRollUpAccount(ExpressionTree* et)
274 {
275     delete rollUpAccount;
276     rollUpAccount = et;
277 }
278
279 bool
280 Report::filterTaskList(TaskList& filteredList, const Resource* r,
281                        ExpressionTree* hideExp, ExpressionTree* rollUpExp)
282 const
283 {
284     /* Create a new list that contains only those tasks that were not
285      * hidden. */
286     filteredList.clear();
287     for (TaskListIterator tli(project->getTaskListIterator());
288          *tli != 0; ++tli)
289     {
290         bool resourceLoadedInAnyScenario = false;
291         if (r != 0 && (*tli)->isLeaf())
292         {
293             QValueList<int>::const_iterator it;
294             for (it = scenarios.begin(); it != scenarios.end(); ++it)
295                 if ((*tli)->isBookedResource(*it, r))
296                 {
297                     resourceLoadedInAnyScenario = true;
298                     break;
299                 }
300         }
301         bool taskOverlapsInAnyScenario = false;
302         Interval iv(start, end);
303         QValueList<int>::const_iterator it;
304         for (it = scenarios.begin(); it != scenarios.end(); ++it)
305             if (iv.overlaps(Interval((*tli)->getStart(*it),
306                                  (*tli)->getEnd(*it) ==
307                                  (*tli)->getStart(*it) - 1 ?
308                                  (*tli)->getStart(*it) :
309                                  (*tli)->getEnd(*it))))
310             {
311                 taskOverlapsInAnyScenario = true;
312                 break;
313             }
314         if (taskOverlapsInAnyScenario &&
315             (r == 0 || resourceLoadedInAnyScenario) &&
316             !isHidden(*tli, hideExp))
317         {
318             filteredList.append(tli);
319         }
320         if (hideExp && hideExp->getErrorFlag())
321             return false;
322     }
323
324     /* In tasktree sorting mode we need to make sure that we don't hide
325      * parents of shown tasks. */
326     TaskList list = filteredList;
327     if (taskSortCriteria[0] == CoreAttributesList::TreeMode)
328     {
329         for (TaskListIterator tli(filteredList); *tli != 0; ++tli)
330         {
331             // Do not add the taskRoot task or any of it's parents.
332             for (Task* p = (*tli)->getParent();
333                  p != 0 && (p->getId() + "." != taskRoot);
334                  p = p->getParent())
335                 if (list.containsRef(p) == 0)
336                     list.append(p);
337         }
338     }
339     filteredList = list;
340
341     if (!rollUpExp)
342         return true;
343
344     /* Now we have to remove all sub tasks of rolled-up tasks
345      * from the filtered list */
346     for (TaskListIterator tli(project->getTaskListIterator());
347          *tli != 0; ++tli)
348     {
349         if (isRolledUp(*tli, rollUpExp))
350             for (TaskTreeIterator tti(*tli, parentAfterLeaves);
351                  *tti != 0; ++tti)
352                 if (*tti != *tli)
353                     filteredList.removeRef(*tti);
354         if (rollUpExp && rollUpExp->getErrorFlag())
355             return false;
356     }
357
358     return true;
359 }
360
361 void
362 Report::sortTaskList(TaskList& filteredList)
363 {
364     /* The sorting can only honor the first scenario. Other scenarios are
365      * ignort for the sorting. */
366     filteredList.setSortScenario(scenarios[0]);
367
368     for (int i = 0; i < CoreAttributesList::maxSortingLevel; i++)
369         filteredList.setSorting(taskSortCriteria[i], i);
370     filteredList.sort();
371 }
372
373 bool
374 Report::filterResourceList(ResourceList& filteredList, const Task* t,
375                            ExpressionTree* hideExp, ExpressionTree* rollUpExp)
376 const
377 {
378     /* Create a new list that contains only those resources that were
379      * not hidden. */
380     filteredList.clear();
381     for (ResourceListIterator rli(project->getResourceListIterator());
382          *rli != 0; ++rli)
383     {
384         bool taskLoadedInAnyScenario = false;
385         if (t != 0 && t->isLeaf())
386         {
387             QValueList<int>::const_iterator it;
388             for (it = scenarios.begin(); it != scenarios.end();
389                  ++it)
390                 if ((*rli)->getEffectiveLoad(*it, Interval(start, end),
391                                              AllAccounts, t) > 0.0)
392                 {
393                     taskLoadedInAnyScenario = true;
394                     break;
395                 }
396         }
397         if (!isHidden(*rli, hideExp) &&
398             (t == 0 || taskLoadedInAnyScenario))
399         {
400             filteredList.append(*rli);
401         }
402         if (hideExp && hideExp->getErrorFlag())
403             return false;
404     }
405
406     /* In resourcetree sorting mode we need to make sure that we don't
407      * hide parents of shown resources. */
408     ResourceList list = filteredList;
409     if (resourceSortCriteria[0] == CoreAttributesList::TreeMode)
410     {
411         for (ResourceListIterator rli(filteredList); *rli != 0; ++rli)
412         {
413             for (Resource* p = (*rli)->getParent(); p != 0; p = p->getParent())
414                 if (list.containsRef(p) == 0)
415                     list.append(p);
416         }
417     }
418     filteredList = list;
419
420     if (!rollUpExp)
421         return true;
422
423     /* Now we have to remove all sub resources of resource in the
424      * roll-up list from the filtered list */
425     for (ResourceListIterator rli(project->getResourceListIterator());
426          *rli != 0; ++rli)
427     {
428         if (isRolledUp(*rli, rollUpExp))
429             for (ResourceTreeIterator rti(*rli, parentAfterLeaves);
430                  *rti != 0; ++rti)
431                 if (*rti != *rli)
432                     filteredList.removeRef(*rti);
433         if (rollUpExp && rollUpExp->getErrorFlag())
434             return false;
435     }
436
437     return true;
438 }
439
440 void
441 Report::sortResourceList(ResourceList& filteredList)
442 {
443     for (int i = 0; i < CoreAttributesList::maxSortingLevel; i++)
444         filteredList.setSorting(resourceSortCriteria[i], i);
445     filteredList.sort();
446 }
447
448 bool
449 Report::filterAccountList(AccountList& filteredList, AccountType at,
450                           ExpressionTree* hideExp, ExpressionTree* rollUpExp)
451 const
452 {
453     /* Create a new list that contains only those accounts that were not
454      * hidden. */
455     filteredList.clear();
456     for (AccountListIterator ali(project->getAccountListIterator());
457          *ali != 0; ++ali)
458     {
459         if (!isHidden(*ali, hideExp) &&
460             (at == AllAccounts || (*ali)->getAcctType() == at))
461             filteredList.append(*ali);
462         if (hideExp && hideExp->getErrorFlag())
463             return false;
464     }
465
466     /* In accounttree sorting mode we need to make sure that we don't hide
467      * parents of shown accounts. */
468     AccountList list = filteredList;
469     if (accountSortCriteria[0] == CoreAttributesList::TreeMode)
470     {
471         for (AccountListIterator ali(filteredList); *ali != 0; ++ali)
472         {
473             for (Account* p = (*ali)->getParent(); p != 0; p = p->getParent())
474                 if (list.containsRef(p) == 0)
475                     list.append(p);
476         }
477     }
478     filteredList = list;
479
480     if (!rollUpExp)
481         return true;
482
483     /* Now we have to remove all sub accounts of account in the roll-up list
484      * from the filtered list */
485     for (AccountListIterator ali(project->getAccountListIterator());
486          *ali != 0; ++ali)
487     {
488         if (isRolledUp(*ali, rollUpExp))
489             for (AccountTreeIterator ati(*ali, parentAfterLeaves);
490                  *ati != 0; ++ati)
491                 if (*ati != *ali)
492                     filteredList.removeRef(*ati);
493         if (rollUpExp && rollUpExp->getErrorFlag())
494             return false;
495     }
496
497     return true;
498 }
499
500 void
501 Report::sortAccountList(AccountList& filteredList)
502 {
503     for (int i = 0; i < CoreAttributesList::maxSortingLevel; i++)
504         filteredList.setSorting(accountSortCriteria[i], i);
505     filteredList.sort();
506
507     maxDepthAccountList = filteredList.maxDepth();
508 }
509
510 bool
511 Report::setLoadUnit(const QString& u)
512 {
513     if (u == KW("minutes"))
514         loadUnit = minutes;
515     else if (u == KW("hours"))
516         loadUnit = hours;
517     else if (u == KW("days"))
518         loadUnit = days;
519     else if (u == KW("weeks"))
520         loadUnit = weeks;
521     else if (u == KW("months"))
522         loadUnit = months;
523     else if (u == KW("years"))
524         loadUnit = years;
525     else if (u == KW("shortauto"))
526         loadUnit = shortAuto;
527     else if (u == KW("longauto"))
528         loadUnit = longAuto;
529     else
530         return false;
531
532     return true;
533 }
534
535 void
536 Report::errorMessage(const QString& msg)
537 {
538     TJMH.errorMessage(msg, defFileName, defFileLine);
539 }
540
541 QString
542 Report::stripTaskRoot(QString taskId) const
543 {
544     if (taskRoot == taskId.left(taskRoot.length()))
545         return taskId.right(taskId.length() - taskRoot.length());
546     else
547         return taskId;
548 }
549