OSDN Git Service

- Improved error checking and reporting for logical expressions.
[tjqt4port/tj2qt4.git] / taskjuggler / ExpressionTreeFunction.cpp
1 /*
2  * ExpressionTreeFunction.cpp - TaskJuggler
3  *
4  * Copyright (c) 2001, 2002, 2003, 2004 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 "Interval.h"
14 #include "ExpressionTreeFunction.h"
15 #include "ExpressionTree.h"
16 #include "Operation.h"
17 #include "CoreAttributes.h"
18 #include "Project.h"
19 #include "Task.h"
20 #include "Resource.h"
21 #include "Account.h"
22 #include "Shift.h"
23 #include "debug.h"
24 #include "tjlib-internal.h"
25
26 #define KW(a) (a)
27
28 bool
29 ExpressionTreeFunction::checkCoreAttributesType(ExpressionTree* et)
30 {
31     if (supportedCoreAttributes.isEmpty())
32         return TRUE;
33
34     QValueList<CAType>::iterator it;
35     for (it = supportedCoreAttributes.begin(); it !=
36          supportedCoreAttributes.end(); ++it)
37        if (et->getCoreAttributes()->getType() == *it)
38            return TRUE;
39
40     return FALSE;
41 }
42
43 long
44 ExpressionTreeFunction::longCall(ExpressionTree* et,
45                                  Operation* const ops[]) const
46 {
47     if (DEBUGEX(15))
48         qDebug("Resolving %s as long", name.latin1());
49     return ((*this).*(longFunc))(et, ops);
50 }
51
52 const CoreAttributes*
53 ExpressionTreeFunction::findCoreAttributes(const CoreAttributes* ca,
54                                            const QString& id) const
55 {
56     const CoreAttributes* p;
57
58     switch (ca->getType())
59     {
60         case CA_Task:
61             p = ca->getProject()->getTask(id);
62             break;
63         case CA_Resource:
64             p = ca->getProject()->getResource(id);
65             break;
66         case CA_Account:
67             p = ca->getProject()->getAccount(id);
68             break;
69         case CA_Shift:
70             p = ca->getProject()->getShift(id);
71             break;
72         default:
73             p = 0;
74     }
75
76     return p;
77 }
78
79 long
80 ExpressionTreeFunction::isChildOf(ExpressionTree* et,
81                                   Operation* const ops[]) const
82 {
83     const CoreAttributes* p;
84     if ((p = findCoreAttributes(et->getCoreAttributes(),
85                                 ops[0]->evalAsString(et))) == 0)
86     {
87         et->errorMessage(i18n("isChildOf: '%1' is unknown and not a "
88                               "child of '%2'")
89                          .arg(et->getCoreAttributes()->getFullId())
90                          .arg(ops[0]->evalAsString(et)));
91         return 0;
92     }
93
94     if (et->getCoreAttributes()->getType() != p->getType())
95     {
96         et->errorMessage(i18n
97                          ("isChildOf: '%1' and '%2' must be of same type")
98                          .arg(et->getCoreAttributes()->getFullId())
99                          .arg(ops[0]->evalAsString(et)));
100         return 0;
101     }
102
103     return et->getCoreAttributes()->isDescendentOf(p);
104 }
105
106 long
107 ExpressionTreeFunction::isParentOf(ExpressionTree* et,
108                                    Operation* const ops[]) const
109 {
110     const CoreAttributes* p;
111     if ((p = findCoreAttributes(et->getCoreAttributes(),
112                                 ops[0]->evalAsString(et))) == 0)
113     {
114         et->errorMessage(i18n("isParentOf: '%1' is unknown and not a "
115                               "child of '%2'")
116                          .arg(et->getCoreAttributes()->getFullId())
117                          .arg(ops[0]->evalAsString(et)));
118         return 0;
119     }
120  
121     if (et->getCoreAttributes()->getType() != p->getType())
122     {
123         et->errorMessage(i18n
124                          ("isParentOf: '%1' and '%2' must be of same type")
125                          .arg(et->getCoreAttributes()->getFullId())
126                          .arg(ops[0]->evalAsString(et)));
127         return 0;
128     }
129
130     return et->getCoreAttributes()->isParentOf(p);
131 }
132
133 long
134 ExpressionTreeFunction::isLeaf(ExpressionTree* et,
135                                Operation* const []) const
136 {
137     if (DEBUGEX(15))
138     {
139         qDebug("isLeaf() called for (%d) %s => %d",
140                et->getCoreAttributes()->getType(),
141                et->getCoreAttributes()->getId().latin1(),
142                et->getCoreAttributes()->isLeaf());
143     }
144     return et->getCoreAttributes()->isLeaf();
145 }
146
147 long
148 ExpressionTreeFunction::treeLevel(ExpressionTree* et,
149                                   Operation* const []) const
150 {
151     return et->getCoreAttributes()->treeLevel() + 1;
152 }
153
154 long
155 ExpressionTreeFunction::isTask(ExpressionTree* et,
156                                Operation* const ops[]) const
157 {
158     if (!ops[0]->isValid())
159     {
160         if (!et->getCoreAttributes()->getProject()->
161             getTask(ops[0]->evalAsString(et)))
162         {
163             et->errorMessage(i18n("isTask: task '%1' is unknown").
164                 arg(ops[0]->evalAsString(et)));
165             return 0;
166         }
167         ops[0]->setValid();
168     }
169
170     return et->getCoreAttributes()->getType() == CA_Task &&
171         et->getCoreAttributes()->getId() == ops[0]->evalAsString(et);
172 }
173
174 long
175 ExpressionTreeFunction::isATask(ExpressionTree* et,
176                                 Operation* const []) const
177 {
178     return et->getCoreAttributes()->getType() == CA_Task;
179 }
180
181 long
182 ExpressionTreeFunction::isMilestone(ExpressionTree* et,
183                                     Operation* const[]) const
184 {
185     if (et->getCoreAttributes()->getType() != CA_Task)
186         return 0;
187
188     return ((Task*) et->getCoreAttributes())->isMilestone();
189 }
190
191 long
192 ExpressionTreeFunction::isResource(ExpressionTree* et,
193                                    Operation* const ops[]) const
194 {
195     if (!ops[0]->isValid())
196     {
197         if (!et->getCoreAttributes()->getProject()->
198             getResource(ops[0]->evalAsString(et)))
199         {
200             et->errorMessage(i18n("isResource: resource '%1' is unknown").
201                 arg(ops[0]->evalAsString(et)));
202             return 0;
203         }
204         ops[0]->setValid(TRUE);
205     }
206
207     return et->getCoreAttributes()->getType() == CA_Resource &&
208         et->getCoreAttributes()->getId() == ops[0]->evalAsString(et);
209 }
210
211 long
212 ExpressionTreeFunction::isAResource(ExpressionTree* et,
213                                     Operation* const []) const
214 {
215     return et->getCoreAttributes()->getType() == CA_Resource;
216 }
217
218 long
219 ExpressionTreeFunction::isAccount(ExpressionTree* et,
220                                   Operation* const ops[]) const
221 {
222     if (!ops[0]->isValid())
223     {
224         if (!et->getCoreAttributes()->getProject()->
225             getAccount(ops[0]->evalAsString(et)))
226         {
227             et->errorMessage(i18n("isAccount: account '%1' is unknown").
228                 arg(ops[0]->evalAsString(et)));
229             return 0;
230         }
231         ops[0]->setValid(TRUE);
232     }
233
234     return et->getCoreAttributes()->getType() == CA_Account &&
235         et->getCoreAttributes()->getId() == ops[0]->evalAsString(et);
236 }
237
238 long
239 ExpressionTreeFunction::isAnAccount(ExpressionTree* et,
240                                     Operation* const []) const
241 {
242     return et->getCoreAttributes()->getType() == CA_Account;
243 }
244
245 long
246 ExpressionTreeFunction::isTaskStatus(ExpressionTree* et,
247                                      Operation* const ops[]) const
248 {
249     if (et->getCoreAttributes()->getType() != CA_Task)
250         return 0;
251
252     int scenario;
253     if ((scenario = et->getCoreAttributes()->
254          getProject()->getScenarioIndex(ops[0]->evalAsString(et)) - 1) < 0)
255     {
256         et->errorMessage(i18n("isTaskStatus: Unknown scenario '%1")
257                          .arg(ops[0]->evalAsString(et)));
258         return 0;
259     }
260
261     static const char* stati[] = {
262         KW("undefined"), KW("notstarted"), KW("inprogresslate"),
263         KW("inprogress"), KW("ontime"), KW("inprogressearly"),
264         KW("finished")
265     };
266     if (!ops[1]->isValid())
267     {
268         bool ok = FALSE;
269         for (uint i = 0; i < (sizeof(stati) / sizeof(char*)); i++)
270             if (ops[1]->evalAsString(et) == stati[i])
271             {
272                 ok = TRUE;
273                 break;
274             }
275         if (!ok)
276         {
277             et->errorMessage(i18n("isTaskStatus: Unknown task status '%1'")
278                              .arg(ops[1]->evalAsString(et)));
279             return 0;
280         }
281         ops[1]->setValid();
282     }
283
284     return strcmp(stati[((Task*) et->getCoreAttributes())
285                   ->getStatus(scenario)], ops[1]->evalAsString(et)) == 0;
286 }
287
288 long
289 ExpressionTreeFunction::startsBefore(ExpressionTree* et,
290                                      Operation* const ops[]) const
291 {
292     if (et->getCoreAttributes()->getType() != CA_Task)
293         return 0;
294
295     int scenario;
296     if ((scenario = et->getCoreAttributes()->
297          getProject()->getScenarioIndex(ops[0]->evalAsString(et)) - 1) < 0)
298     {
299         et->errorMessage(i18n("startsBefore: Unknown scenario '%1'")
300                          .arg(ops[0]->evalAsString(et).latin1()));
301         return 0;
302     }
303
304     return ((Task*) et->getCoreAttributes())->getStart(scenario) <
305         ops[1]->evalAsTime(et);
306 }
307
308 long
309 ExpressionTreeFunction::startsAfter(ExpressionTree* et,
310                                      Operation* const ops[]) const
311 {
312     if (et->getCoreAttributes()->getType() != CA_Task)
313         return 0;
314
315     int scenario;
316     if ((scenario = et->getCoreAttributes()->
317          getProject()->getScenarioIndex(ops[0]->evalAsString(et)) - 1) < 0)
318     {
319         et->errorMessage(i18n("startsAfter: Unknown scenario '%1'")
320                          .arg(ops[0]->evalAsString(et)));
321         return 0;
322     }
323
324     return ((Task*) et->getCoreAttributes())->getStart(scenario) >=
325         ops[1]->evalAsTime(et);
326 }
327
328 long
329 ExpressionTreeFunction::endsBefore(ExpressionTree* et,
330                                      Operation* const ops[]) const
331 {
332     if (et->getCoreAttributes()->getType() != CA_Task)
333         return 0;
334
335     int scenario;
336     if ((scenario = et->getCoreAttributes()->
337          getProject()->getScenarioIndex(ops[0]->evalAsString(et)) - 1) < 0)
338     {
339         et->errorMessage(i18n("endsBefore: Unknown scenario '%s'")
340                          .arg(ops[0]->evalAsString(et)));
341         return 0;
342     }
343
344     return ((Task*) et->getCoreAttributes())->getEnd(scenario) <
345         ops[1]->evalAsTime(et);
346 }
347
348 long
349 ExpressionTreeFunction::endsAfter(ExpressionTree* et,
350                                      Operation* const ops[]) const
351 {
352     if (et->getCoreAttributes()->getType() != CA_Task)
353         return 0;
354
355     int scenario;
356     if ((scenario = et->getCoreAttributes()->
357          getProject()->getScenarioIndex(ops[0]->evalAsString(et)) - 1) < 0)
358     {
359         et->errorMessage(i18n("endsAfter: Unknown scenario '%1'")
360                          .arg(ops[0]->evalAsString(et)));
361         return 0;
362     }
363
364     return ((Task*) et->getCoreAttributes())->getEnd(scenario) >
365         ops[1]->evalAsTime(et);
366 }
367
368 long
369 ExpressionTreeFunction::isSubTaskOf(ExpressionTree* et,
370                                     Operation* const ops[]) const
371 {
372     if (et->getCoreAttributes()->getType() != CA_Task)
373         return 0;
374
375     Task* p;
376     if ((p = et->getCoreAttributes()->getProject()->getTask
377          (ops[0]->evalAsString(et))) == 0)
378     {
379         et->errorMessage(i18n("isSubTaskOf: task '%1' is unknown")
380                          .arg(ops[0]->evalAsString(et)));
381         return 0;
382     }
383
384     return p->isSubTask((Task*) et->getCoreAttributes());
385 }
386
387 long
388 ExpressionTreeFunction::containsTask(ExpressionTree* et,
389                                      Operation* const ops[]) const
390 {
391     if (et->getCoreAttributes()->getType() != CA_Task)
392         return 0;
393
394     Task* st;
395     if ((st = et->getCoreAttributes()->getProject()->getTask
396          (ops[0]->evalAsString(et))) == 0)
397     {
398         et->errorMessage(i18n("containsTask: task '%1' is unknown")
399                          .arg(et->getCoreAttributes()->getFullId()));
400         return 0;
401     }
402
403     return ((Task*) et->getCoreAttributes())->isSubTask(st);
404 }
405
406 long
407 ExpressionTreeFunction::isTaskOfProject(ExpressionTree* et,
408                                         Operation* const ops[]) const
409 {
410     if (et->getCoreAttributes()->getType() != CA_Task)
411         return 0;
412
413     if (!ops[0]->isValid())
414     {
415         if (!et->getCoreAttributes()->getProject()->isValidId
416             (ops[0]->evalAsString(et)))
417         {
418             et->errorMessage(i18n("isTaskOfProject: project ID '%1' is unkown")
419                 .arg(ops[0]->evalAsString(et)));
420             return 0;
421         }
422         ops[0]->setValid();
423     }
424
425     return ops[0]->evalAsString(et) ==
426         ((Task*) (et->getCoreAttributes()))->getProjectId();
427 }
428
429 long
430 ExpressionTreeFunction::isAllocated(ExpressionTree* et,
431                                     Operation* const ops[]) const
432 {
433     /* Arguments:
434        0 : scenario id
435        1 : interval start
436        2 : interval end */
437     if (et->getCoreAttributes()->getType() != CA_Resource)
438     {
439         et->errorMessage(i18n("isAllocated: '%1' is not a resource")
440                          .arg(et->getCoreAttributes()->getFullId()));
441         return 0;
442     }
443
444     int scenarioId = et->getCoreAttributes()->getProject()->
445         getScenarioIndex(ops[0]->evalAsString(et)) - 1;
446     if (scenarioId < 0)
447     {
448         et->errorMessage(i18n("isAllocated: unknown scenario '%1'")
449                          .arg(ops[0]->evalAsString(et)));
450         return 0;
451     }
452
453     time_t start = ops[1]->evalAsTime(et);
454     time_t end = ops[2]->evalAsTime(et);
455     if (start > end)
456     {
457         et->errorMessage(i18n("isAllocated: start date is larger than end "
458                               "date"));
459         return 0;
460     }
461     if (et->getCoreAttributes()->getProject()->getStart() > start)
462         start = et->getCoreAttributes()->getProject()->getStart();
463     if (et->getCoreAttributes()->getProject()->getEnd() < end)
464         end = et->getCoreAttributes()->getProject()->getEnd();
465
466     return ((Resource*) et->getCoreAttributes())->isAllocated
467         (scenarioId, Interval(start, end),
468          QString::null);
469 }
470
471 long
472 ExpressionTreeFunction::isDutyOf(ExpressionTree* et,
473                                  Operation* const ops[]) const
474 {
475     /* Arguments:
476        0 : resource id
477        1 : scenario id */
478     if (et->getCoreAttributes()->getType() != CA_Task)
479         return 0;
480
481     Resource* resource = et->getCoreAttributes()->getProject()->
482         getResource(ops[0]->evalAsString(et));
483     if (!resource)
484     {
485         et->errorMessage(i18n("isDutyOf: resource '%1' is unknown")
486                          .arg(ops[0]->evalAsString(et)));
487         return 0;
488     }
489
490     int scenarioId = et->getCoreAttributes()->getProject()->
491         getScenarioIndex(ops[1]->evalAsString(et)) - 1;
492     if (scenarioId < 0)
493     {
494         et->errorMessage(i18n("isDutyOf: unknown scenario '%1'")
495                          .arg(ops[1]->evalAsString(et)));
496         return 0;
497     }
498
499     return ((Task*) et->getCoreAttributes())->isDutyOf(scenarioId, resource);
500 }
501
502 long
503 ExpressionTreeFunction::isAllocatedToProject(ExpressionTree* et,
504                                              Operation* const ops[]) const
505 {
506     /* Arguments:
507        0 : project id
508        1 : scenario id
509        2 : interval start
510        3 : interval end */
511     if (et->getCoreAttributes()->getType() != CA_Resource)
512         return 0;
513
514     if (!ops[0]->isValid())
515     {
516         if (!et->getCoreAttributes()->getProject()->isValidId
517             (ops[0]->evalAsString(et)))
518         {
519             et->errorMessage(i18n("isAllocatedToProject: project ID '%1'"
520                                   "is unknown")
521                              .arg(ops[0]->evalAsString(et)));
522             return 0;
523         }
524         ops[0]->setValid();
525     }
526
527     int scenarioId = et->getCoreAttributes()->getProject()->
528         getScenarioIndex(ops[1]->evalAsString(et)) - 1;
529     if (scenarioId < 0)
530     {
531         et->errorMessage(i18n("isAllocatedToProject: unknown scenario '%1'")
532                          .arg(ops[1]->evalAsString(et)));
533         return 0;
534     }
535     time_t start = ops[2]->evalAsTime(et);
536     time_t end = ops[3]->evalAsTime(et);
537     if (start > end)
538     {
539         et->errorMessage(i18n("isAllocatedToProject: start date is larger "
540                               "than end date"));
541         return 0;
542     }
543     if (et->getCoreAttributes()->getProject()->getStart() > start)
544         start = et->getCoreAttributes()->getProject()->getStart();
545     if (et->getCoreAttributes()->getProject()->getEnd() < end)
546         end = et->getCoreAttributes()->getProject()->getEnd();
547
548     return ((Resource*) et->getCoreAttributes())->isAllocated
549         (scenarioId, Interval(start, end),
550          ops[0]->evalAsString(et));
551 }
552
553 long
554 ExpressionTreeFunction::isPlanAllocated(ExpressionTree* et,
555                                         Operation* const ops[]) const
556 {
557     if (et->getCoreAttributes()->getType() != CA_Resource)
558     {
559         et->errorMessage(i18n("isplanallocated: called for "
560                               "non-resource '%1'")
561                .arg(et->getCoreAttributes()->getFullId()));
562         return 0;
563     }
564     int scenarioId = et->getCoreAttributes()->getProject()->
565         getScenarioIndex("plan") - 1;
566     if (scenarioId < 0)
567     {
568         et->errorMessage(i18n("isplanallocated: there is no "
569                               "'plan' scenario."));
570         return 0;
571     }
572     time_t start = ops[1]->evalAsTime(et);
573     time_t end = ops[2]->evalAsTime(et);
574     if (et->getCoreAttributes()->getProject()->getStart() > start)
575         start = et->getCoreAttributes()->getProject()->getStart();
576     if (et->getCoreAttributes()->getProject()->getEnd() < end)
577         end = et->getCoreAttributes()->getProject()->getEnd();
578     if (start > end)
579     {
580         et->errorMessage(i18n("isPlanAllocated: start date "
581                               "is larger than end date"));
582         return 0;
583     }
584
585     return ((Resource*) et->getCoreAttributes())->isAllocated
586         (scenarioId, Interval(start, end),
587          ops[0]->evalAsString(et));
588 }
589
590 long
591 ExpressionTreeFunction::isActualAllocated(ExpressionTree* et,
592                                           Operation* const ops[]) const
593 {
594     if (et->getCoreAttributes()->getType() != CA_Resource)
595     {
596         et->errorMessage(i18n("isactualallocated: called for non-resource"));
597         return 0;
598     }
599     int scenarioId = et->getCoreAttributes()->getProject()->
600         getScenarioIndex("actual") - 1;
601     if (scenarioId < 0)
602     {
603         et->errorMessage(i18n("isactualallocated: there is no 'actual'"
604                              " scenario."));
605         return 0;
606     }
607     time_t start = ops[1]->evalAsTime(et);
608     time_t end = ops[2]->evalAsTime(et);
609     if (et->getCoreAttributes()->getProject()->getStart() > start)
610         start = et->getCoreAttributes()->getProject()->getStart();
611     if (et->getCoreAttributes()->getProject()->getEnd() < end)
612         end = et->getCoreAttributes()->getProject()->getEnd();
613     if (start > end)
614     {
615         et->errorMessage(i18n("isActualAllocated: start date "
616                               "is larger than end date"));
617         return 0;
618     }
619
620     return ((Resource*) et->getCoreAttributes())->isAllocated
621         (scenarioId, Interval(start, end),
622          ops[0]->evalAsString(et));
623 }
624