2 * Project.cpp - TaskJuggler
4 * Copyright (c) 2001, 2002 by Chris Schlaeger <cs@suse.de>
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.
24 int Project::debugLevel = 0;
28 taskList.setAutoDelete(TRUE);
29 resourceList.setAutoDelete(TRUE);
30 accountList.setAutoDelete(TRUE);
31 activeAsap.setSorting(CoreAttributesList::PrioDown);
32 activeAlap.setSorting(CoreAttributesList::PrioDown);
34 /* The following settings are country and culture dependent. Those
35 * defaults are probably true for many Western countries, but have to be
36 * changed in project files. */
37 dailyWorkingHours = 8.0;
38 yearlyWorkingDays = 252;
39 scheduleGranularity = ONEHOUR;
57 /* Initialize working hours with default values that match the Monday -
58 * Friday 9 - 6 (with 1 hour lunch break) pattern used by many western
61 workingHours[0] = new QPtrList<Interval>();
62 workingHours[0]->setAutoDelete(TRUE);
65 workingHours[1] = new QPtrList<Interval>();
66 workingHours[1]->setAutoDelete(TRUE);
67 workingHours[1]->append(new Interval(9 * ONEHOUR, 12 * ONEHOUR - 1));
68 workingHours[1]->append(new Interval(13 * ONEHOUR, 18 * ONEHOUR - 1));
70 workingHours[2] = new QPtrList<Interval>();
71 workingHours[2]->setAutoDelete(TRUE);
72 workingHours[2]->append(new Interval(9 * ONEHOUR, 12 * ONEHOUR - 1));
73 workingHours[2]->append(new Interval(13 * ONEHOUR, 18 * ONEHOUR - 1));
75 workingHours[3] = new QPtrList<Interval>();
76 workingHours[3]->setAutoDelete(TRUE);
77 workingHours[3]->append(new Interval(9 * ONEHOUR, 12 * ONEHOUR - 1));
78 workingHours[3]->append(new Interval(13 * ONEHOUR, 18 * ONEHOUR - 1));
80 workingHours[4] = new QPtrList<Interval>();
81 workingHours[4]->setAutoDelete(TRUE);
82 workingHours[4]->append(new Interval(9 * ONEHOUR, 12 * ONEHOUR - 1));
83 workingHours[4]->append(new Interval(13 * ONEHOUR, 18 * ONEHOUR - 1));
85 workingHours[5] = new QPtrList<Interval>();
86 workingHours[5]->setAutoDelete(TRUE);
87 workingHours[5]->append(new Interval(9 * ONEHOUR, 12 * ONEHOUR - 1));
88 workingHours[5]->append(new Interval(13 * ONEHOUR, 18 * ONEHOUR - 1));
91 workingHours[6] = new QPtrList<Interval>();
92 workingHours[6]->setAutoDelete(TRUE);
96 Project::addId(const QString& id)
98 if (projectIDs.findIndex(id) != -1)
101 projectIDs.append(id);
106 Project::getIdIndex(const QString& i) const
109 if ((idx = projectIDs.findIndex(i)) == -1)
114 idxStr = QChar('A' + idx % ('Z' - 'A')) + idxStr;
116 } while (idx > 'Z' - 'A');
122 Project::addTask(Task* t)
134 taskList.createIndex();
135 resourceList.createIndex();
136 accountList.createIndex();
138 // Initialize random generator.
141 // Create hash to map task IDs to pointers.
142 for (Task* t = taskList.first(); t != 0; t = taskList.next())
144 idHash.insert(t->getId(), t);
147 // Create cross links from dependency lists.
148 for (Task* t = taskList.first(); t != 0; t = taskList.next())
150 if (!t->xRef(idHash))
154 bool hasActualValues = FALSE;
155 for (Task* t = taskList.first(); t != 0; t = taskList.next())
157 if (!t->preScheduleOk())
159 if (t->hasActualValues())
160 hasActualValues = TRUE;
167 qWarning("Scheduling plan scenario...");
175 qWarning("Scheduling actual scenario...");
181 for (Task* t = taskList.first(); t != 0; t = taskList.next())
188 Project::preparePlan()
190 for (Task* t = taskList.first(); t != 0; t = taskList.next())
192 for (Task* t = taskList.first(); t != 0; t = taskList.next())
193 t->propagateInitialValues();
194 for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
199 Project::finishPlan()
201 for (Task* t = taskList.first(); t != 0; t = taskList.next())
203 for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
208 Project::prepareActual()
210 for (Task* t = taskList.first(); t != 0; t = taskList.next())
212 for (Task* t = taskList.first(); t != 0; t = taskList.next())
213 t->propagateInitialValues();
214 for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
219 Project::finishActual()
221 for (Task* t = taskList.first(); t != 0; t = taskList.next())
223 for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
232 TaskList sortedTasks(taskList);
233 sortedTasks.setSorting(CoreAttributesList::PrioDown);
236 time_t timeDelta = scheduleGranularity;
240 updateActiveTaskList(sortedTasks);
241 for (day = start; !(activeAsap.isEmpty() && activeAlap.isEmpty()) &&
242 day >= start && day < end; day += timeDelta)
244 timeDelta = scheduleGranularity;
248 for (Task* t = activeAlap.first(); t != 0; t = activeAlap.next())
250 if (!t->schedule(day, scheduleGranularity))
253 break; // Start with top priority tasks again.
255 if (t->needsEarlierTimeSlot(day + scheduleGranularity))
256 timeDelta = -scheduleGranularity;
267 for (Task* t = activeAsap.first(); t != 0; t = activeAsap.next())
270 if (!t->schedule(day, scheduleGranularity))
273 break; // Start with top priority tasks again.
277 if (i != activeAsap.count())
278 qFatal("activeAsap list corrupted");
281 if (!activeAsap.isEmpty() || !activeAlap.isEmpty())
283 for (Task* t = activeAsap.first(); t != 0; t = activeAsap.next())
284 qWarning("Task %s does not fit into the project time frame",
285 t->getId().latin1());
286 for (Task* t = activeAlap.first(); t != 0; t = activeAlap.next())
287 qWarning("Task %s does not fit into the project time frame",
288 t->getId().latin1());
292 if (!checkSchedule())
299 Project::updateActiveTaskList(TaskList& sortedTasks)
301 for (Task* t = sortedTasks.first(); t != 0; t = sortedTasks.next())
307 Project::checkSchedule()
309 TaskList tl = taskList;
310 tl.setSorting(CoreAttributesList::StartDown);
313 for (Task* t = tl.first(); t != 0; t = tl.next())
315 if (!t->scheduleOk())
325 Project::setKotrus(Kotrus* k)
333 Project::generateReports()
336 qWarning("Generating reports...");
338 // Generate task reports
339 for (HTMLTaskReport* h = htmlTaskReports.first(); h != 0;
340 h = htmlTaskReports.next())
343 // Generate resource reports
344 for (HTMLResourceReport* r = htmlResourceReports.first(); r != 0;
345 r = htmlResourceReports.next())
348 // Generate account reports
349 for (HTMLAccountReport* r = htmlAccountReports.first(); r != 0;
350 r = htmlAccountReports.next())
353 for (ExportReport* e = exportReports.first(); e != 0;
354 e = exportReports.next())
358 xmlreport->generate();
362 icalReport->generate();
369 Project::needsActualDataForReports()
371 bool needsActual = FALSE;
373 // Generate task reports
374 for (HTMLTaskReport* h = htmlTaskReports.first(); h != 0;
375 h = htmlTaskReports.next())
376 if (h->getShowActual())
378 // Generate resource reports
379 for (HTMLResourceReport* h = htmlResourceReports.first(); h != 0;
380 h = htmlResourceReports.next())
381 if (h->getShowActual())
384 // Generate account reports
385 for (HTMLAccountReport* h = htmlAccountReports.first(); h != 0;
386 h = htmlAccountReports.next())
387 if (h->getShowActual())
394 Project::removeActiveTask(Task* t)
399 qWarning("Deactivating %s", t->getId().latin1());
401 if (t->getScheduling() == Task::ASAP)
402 activeAsap.removeRef(t);
404 activeAlap.removeRef(t);
408 Project::addActiveTask(Task* t)
410 if (t->getScheduling() == Task::ASAP)
412 if (activeAsap.findRef(t) == -1)
415 qWarning("Activating %s", t->getId().latin1());
416 activeAsap.inSort(t);
421 if (activeAlap.findRef(t) == -1)
424 qWarning("Activating %s", t->getId().latin1());
425 activeAlap.inSort(t);
431 Project::readKotrus()
436 for (Resource* r = resourceList.first(); r != 0; r = resourceList.next())
437 r->dbLoadBookings(r->getKotrusId(), 0);
443 Project::updateKotrus()
450 Project::loadFromXML( const QString& inpFile )
453 QFile file( inpFile );
455 doc.setContent( &file );
456 qDebug( "Loading XML " + inpFile );
458 QDomElement elemProject = doc.documentElement();
460 if( !elemProject.isNull())
462 parseDomElem( elemProject );
472 void Project::parseDomElem( QDomElement& parentElem )
474 QDomElement elem = parentElem.firstChild().toElement();
476 for( ; !elem.isNull(); elem = elem.nextSibling().toElement() )
478 QString tagName = elem.tagName();
480 qDebug( "|| elemType: " + tagName );
482 if( tagName == "Task" )
484 QString tId = elem.attribute("Id");
485 Task *t = new Task( this, tId, QString(), 0, QString(), 0 );
487 t->loadFromXML( elem, this );
490 else if( tagName == "Name" )
492 setName( elem.text() );
494 else if( tagName == "Version" )
495 setVersion( elem.text() );
496 else if( tagName == "Priority" )
497 setPriority( elem.text().toInt());
498 else if( tagName == "start" )
499 setStart( elem.text().toLong());
500 else if( tagName == "end" )
501 setEnd( elem.text().toLong());
503 // parseDomElem( elem );