* $Id$
*/
+#include <config.h>
#include <stdio.h>
#include <qdict.h>
#include "Project.h"
#include "Utility.h"
+#define COL_DEFAULT "#fffadd"
+#define COL_WEEKEND "#ffec80"
+#define COL_BOOKED "#ffc0a3"
+#define COL_HEADER "a5c2ff"
+
Project::Project()
{
taskList.setAutoDelete(TRUE);
priority = 50;
start = 0;
- end = MAXTIME;
+ end = 0;
minEffort = 0.0;
maxEffort = 1.0;
rate = 0.0;
addAllowedFlag("closed");
// The 'hidden' flag may be used to hide the task in all reports.
addAllowedFlag("hidden");
- htmlResourceReport = "";
htmlTaskReport = "";
+ htmlTaskReportStart = 0;
+ htmlTaskReportEnd = 0;
+ htmlResourceReport = "";
+ htmlResourceReportStart = 0;
+ htmlResourceReportEnd = 0;
}
bool
sortedTasks.setSorting(TaskList::PrioDown);
sortedTasks.sort();
- int uc = 0, puc = -1;
- while ((uc = unscheduledTasks()) > 0 && uc != puc)
+ for (int day = start; day < end; day += 60 * 60 * 24)
{
- for (Task* t = sortedTasks.first(); t != 0; t = sortedTasks.next())
- t->schedule(start);
- puc = uc;
+ bool done;
+ do
+ {
+ done = TRUE;
+ for (Task* t = sortedTasks.first(); t != 0; t = sortedTasks.next())
+ if (!t->schedule(day))
+ done = FALSE;
+ } while (!done);
}
- if (uc > 0 && uc == puc)
+ if (unscheduledTasks() > 0)
{
fprintf(stderr, "Can't schedule some tasks. Giving up!\n");
}
Project::reportHTMLHeader(FILE* f)
{
fprintf(f, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n"
+ "<! Generated by TaskJuggler v"VERSION">"
"<html>\n"
"<head>\n"
"<title>Task Report</title>\n"
bool
Project::reportHTMLFooter(FILE* f)
{
- fprintf(f, "</body>\n"
- "</html>\n");
+ fprintf(f, "<br><font size=\"-2\">%s - TaskJuggler v"
+ VERSION"</font></body>\n"
+ "</html>\n", version.latin1());
return TRUE;
}
if (htmlTaskReport == "")
return TRUE;
+ if (htmlTaskReportStart == 0)
+ htmlTaskReportStart = start;
+ if (htmlTaskReportEnd == 0)
+ htmlTaskReportEnd = 0;
+
FILE* f;
if ((f = fopen(htmlTaskReport, "w")) == NULL)
{
return FALSE;
}
reportHTMLHeader(f);
- fprintf(f, "<table border=\"1\" cellpadding=\"3\">\n");
+ fprintf(f, "<table border=\"0\" cellpadding=\"1\">\n");
+ fprintf(f, "<tr>");
for (QStringList::Iterator it = htmlTaskReportColumns.begin();
it != htmlTaskReportColumns.end(); ++it )
{
if (*it == "no")
- fprintf(f, "<th><h2>No.</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>No.</h2></td>");
else if (*it == "taskId")
- fprintf(f, "<th><h2>Task ID</h2></th>");
- else if (*it == "task")
- fprintf(f, "<th><h2>Task</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Task ID</h2></td>");
+ else if (*it == "name")
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Task</h2></td>");
else if (*it == "start")
- fprintf(f, "<th><h2>Start</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Start</h2></td>");
else if (*it == "end")
- fprintf(f, "<th><h2>End</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>End</h2></td>");
else if (*it == "minStart")
- fprintf(f, "<th><h2>Min. Start</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Min. Start</h2></td>");
else if (*it == "maxStart")
- fprintf(f, "<th><h2>Max. Start</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Max. Start</h2></td>");
else if (*it == "resources")
- fprintf(f, "<th><h2>Resources</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Resources</h2></td>");
else if (*it == "depends")
- fprintf(f, "<th><h2>Dependencies</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Dependencies</h2></td>");
else if (*it == "follows")
- fprintf(f, "<th><h2>Following Tasks</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Following Tasks</h2></td>");
else if (*it == "note")
- fprintf(f, "<th><h2>Note</h2></th>");
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\">"
+ "<h2>Note</h2></td>");
+ else if (*it == "daily")
+ {
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" rowspan=\"2\"></td>");
+ htmlMonthHeader(f, htmlTaskReportStart, htmlTaskReportEnd);
+ }
else
{
fprintf(stderr, "Unknown Column '%s' for HTML Task Report\n",
return FALSE;
}
}
+ fprintf(f, "</tr>");
+ fprintf(f, "<tr>");
+ for (QStringList::Iterator it = htmlTaskReportColumns.begin();
+ it != htmlTaskReportColumns.end(); ++it )
+ {
+ if (*it == "daily")
+ htmlDayHeader(f, htmlTaskReportStart, htmlTaskReportEnd);
+ }
+ fprintf(f, "</tr>\n");
int i = 1;
QDict<int> idxDict;
it != htmlTaskReportColumns.end(); ++it )
{
if (*it == "no")
- fprintf(f, "<td>%d.</td>", i);
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "%d.</td>", i);
else if (*it == "taskId")
- fprintf(f, "<td nowrap>%s</td>", t->getId().latin1());
- else if (*it == "task")
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\""
+ " nowrap>%s</td>", t->getId().latin1());
+ else if (*it == "name")
{
int indent;
Task* tp = t->getParent();
spaces += " ";
tp = tp->getParent();
}
- fprintf(f, "<td nowrap>%s<font size=\"%c%d\">%s</font></td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\""
+ " nowrap>%s<font size=\"%c%d\">%s</font></td>\n",
spaces.latin1(), 2 - indent < 0 ? '-' : '+',
2 - indent < 0 ? -(2 - indent) : 2 - indent,
t->getName().latin1());
}
else if (*it == "start")
- fprintf(f, "<td %s>%s</td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\" %s>"
+ "%s</td>\n",
t->isStartOk() ? "" : "bgcolor=\"red\"",
t->getStartISO().latin1());
else if (*it == "end")
- fprintf(f, "<td %s>%s</td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\" %s>"
+ "%s</td>\n",
t->isEndOk() ? "" : "bgcolor=\"red\"",
t->getEndISO().latin1());
else if (*it == "minStart")
- fprintf(f, "<td>%s</td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "%s</td>\n",
time2ISO(t->getMinStart()).latin1());
else if (*it == "maxStart")
- fprintf(f, "<td>%s</td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "%s</td>\n",
time2ISO(t->getMaxStart()).latin1());
else if (*it == "resources")
{
- fprintf(f, "<td><font size=\"-2\">");
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "<font size=\"-2\">");
bool first = TRUE;
for (Resource* r = t->firstBookedResource(); r != 0;
r = t->nextBookedResource())
{
- fprintf(f, "%s%s,", first ? "" : ", ",
+ fprintf(f, "%s%s", first ? "" : ", ",
r->getName().latin1());
first = FALSE;
}
}
else if (*it == "depends")
{
- fprintf(f, "<td><font size=\"-2\">");
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "<font size=\"-2\">");
bool first = TRUE;
for (Task* d = t->firstPrevious(); d != 0;
d = t->nextPrevious())
}
else if (*it == "follows")
{
- fprintf(f, "<td><font size=\"-2\">");
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "<font size=\"-2\">");
bool first = TRUE;
for (Task* d = t->firstFollower(); d != 0;
d = t->nextFollower())
}
else if (*it == "note")
{
- fprintf(f, "<td><font size=\"-2\">%s</font></td>\n",
+ fprintf(f, "<td bgcolor=\""COL_DEFAULT"\" rowspan=\"2\">"
+ "<font size=\"-2\">%s</font></td>\n",
htmlFilter(t->getNote()).latin1());
}
+ else if (*it == "daily")
+ {
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\"><font size=\"-4\">"
+ "Plan</font></td>");
+ const int oneDay = 60 * 60 * 24;
+ for (time_t day = htmlTaskReportStart;
+ day < htmlTaskReportEnd; day += oneDay)
+ {
+ double load = t->getLoadOnDay(day);
+ QString bgCol = COL_DEFAULT;
+ if (isWeekend(day))
+ bgCol = COL_WEEKEND;
+ else if (load > 0.0)
+ bgCol = COL_BOOKED;
+ if (load > 0.0)
+ fprintf(f,
+ "<td bgcolor=\"%s\"><font size=\"-3\">%3.1f</font></td>",
+ bgCol.latin1(), load);
+ else
+ fprintf(f, "<td bgcolor=\"%s\"></td>",
+ bgCol.latin1());
+ }
+ }
}
fprintf(f, "</tr>");
+
+ fprintf(f, "<tr>\n");
+ for (QStringList::Iterator it = htmlTaskReportColumns.begin();
+ it != htmlTaskReportColumns.end(); ++it )
+ {
+ if (*it == "daily")
+ {
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\"><font size=\"-4\">"
+ "Actual</font></td>");
+ const int oneDay = 60 * 60 * 24;
+ for (time_t day = htmlTaskReportStart;
+ day < htmlTaskReportEnd; day += oneDay)
+ fprintf(f, "<td bgcolor=\"%s\"></td>",
+ isWeekend(day) ? COL_WEEKEND : COL_DEFAULT);
+ }
+ }
+ fprintf(f, "</tr>\n");
}
fprintf(f, "</table>");
reportHTMLFooter(f);
}
reportHTMLHeader(f);
fprintf(f, "<table border=\"1\" cellpadding=\"3\">\n");
- const int oneDay = 60 * 60 * 24;
fprintf(f, "<tr>");
fprintf(f, "<td rowspan=\"2\"></td>");
- for (time_t day = htmlResourceReportStart; day < htmlResourceReportEnd;
- day += oneDay * daysLeftInMonth(day))
- {
- int left = daysLeftInMonth(day);
- if (left > (htmlResourceReportEnd - day) / oneDay)
- left = (htmlResourceReportEnd - day) / oneDay;
- fprintf(f, "<td colspan=\"%d\" align=\"center\">%s</td>",
- left, monthAndYear(day));
- }
+ htmlMonthHeader(f, htmlResourceReportStart, htmlResourceReportEnd);
fprintf(f, "</tr>\n");
fprintf(f, "<tr>");
- for (time_t day = htmlResourceReportStart; day < htmlResourceReportEnd;
- day += oneDay)
- {
- fprintf(f, "<td>%d</td>", dayOfMonth(day));
- }
+ htmlDayHeader(f, htmlResourceReportStart, htmlResourceReportEnd);
fprintf(f, "</tr>\n");
+ const int oneDay = 60 * 60 * 24;
for (Resource* r = resourceList.first(); r != 0;
r = resourceList.next())
{
if (load > 0.0)
s.sprintf("%3.1f", load);
fprintf(f, "<td %s>%s</td>",
- isWeekend(day) ? "bgcolor=\"yellow\"" : "",
+ isWeekend(day) ? "bgcolor=\""COL_WEEKEND"\"" : "",
s.latin1());
}
fprintf(f, "</tr>\n");
if (load > 0.0)
s.sprintf("%3.1f", load);
fprintf(f, "<td %s><font size=\"-1\">%s</font></td>",
- isWeekend(day) ? "bgcolor=\"yellow\"" : "",
+ isWeekend(day) ? "bgcolor=\""COL_WEEKEND"\"" : "",
s.latin1());
}
fprintf(f, "</tr>\n");
}
void
+Project::htmlDayHeader(FILE* f, time_t s, time_t e)
+{
+ const int oneDay = 60 * 60 * 24;
+
+ for (time_t day = s; day < e; day += oneDay)
+ {
+ int dom = dayOfMonth(day);
+ fprintf(f, "<td bgcolor=\"%s\"><font size=\"-2\">"
+ " %s%d</font></td>",
+ isWeekend(day) ? COL_WEEKEND : COL_HEADER,
+ dom < 10 ? " " : "", dom);
+ }
+}
+
+void
+Project::htmlMonthHeader(FILE* f, time_t s, time_t e)
+{
+ const int oneDay = 60 * 60 * 24;
+
+ for (time_t day = s; day < e; day += oneDay * daysLeftInMonth(day))
+ {
+ int left = daysLeftInMonth(day);
+ if (left > (e - day) / oneDay)
+ left = (e - day) / oneDay;
+ fprintf(f, "<td bgcolor=\""COL_HEADER"\" colspan=\"%d\" "
+ "align=\"center\"><font size=\"+2\"><b>%s</b></font></td>",
+ left, monthAndYear(day));
+ }
+}
+
+void
Project::printText()
{
printf("ID Task Name Start End\n");
bool reportHTMLResourceList();
+ void setId(const QString& i) { id = i; }
+ const QString& getId() const { return id; }
+
+ void setName(const QString& n) { name = n; }
+ const QString& getName() const { return name; }
+
+ void setVersion(const QString& v) { version = v; }
+ const QString& getVersion() const { return version; }
+
void setPriority(int p) { priority = p; }
int getPriority() const { return priority; }
void setEnd(time_t e) { end = e; }
time_t getEnd() const { return end; }
- void setId(const QString& i) { id = i; }
- const QString& getId() const { return id; }
-
- void setName(const QString& n) { name = n; }
- const QString& getName() const { return name; }
-
- void setManager(const QString& m) { manager = m; }
- const QString& getManager() const { return manager; }
-
void addVacation(const QString& n, time_t s, time_t e)
{
vacationList.add(n, s, e);
{
htmlTaskReportColumns.append(c);
}
+ void setHtmlTaskReportStart(time_t s) { htmlTaskReportStart = s; }
+ void setHtmlTaskReportEnd(time_t e) { htmlTaskReportEnd = e; }
void setHtmlResourceReport(const QString& f) { htmlResourceReport = f; }
void setHtmlResourceReportStart(time_t t) { htmlResourceReportStart = t; }
private:
bool checkSchedule();
+ void htmlDayHeader(FILE* f, time_t s, time_t e);
+ void htmlMonthHeader(FILE* f, time_t s, time_t e);
QString htmlFilter(const QString& s);
int unscheduledTasks();
time_t start;
time_t end;
+ // A unique (with respect to the resource database) project id
QString id;
+ // The name of the Project
QString name;
- QString manager;
+ // The revision of the project description.
+ QString version;
/* The default priority that will be inherited by all tasks. Sub tasks
* will inherit the priority of its parent task. */
QString htmlTaskReport;
QStringList htmlTaskReportColumns;
+ time_t htmlTaskReportStart;
+ time_t htmlTaskReportEnd;
QString htmlResourceReport;
time_t htmlResourceReportStart;
return FALSE;
break;
}
- else if (token == "start")
- {
- if ((tt = nextToken(token)) != DATE)
- {
- fatalError("Date expected");
- return FALSE;
- }
- proj->setStart(date2time(token));
- break;
- }
- else if (token == "end")
- {
- if ((tt = nextToken(token)) != DATE)
- {
- fatalError("Date expected");
- return FALSE;
- }
- proj->setEnd(date2time(token));
- break;
- }
else if (token == "resource")
{
if (!readResource())
}
break;
}
+ else if (token == "project")
+ {
+ if (nextToken(token) != ID)
+ {
+ fatalError("Project ID expected");
+ return FALSE;
+ }
+ proj->setId(token);
+ if (nextToken(token) != STRING)
+ {
+ fatalError("Project name expected");
+ return FALSE;
+ }
+ proj->setName(token);
+ if (nextToken(token) != STRING)
+ {
+ fatalError("Version string expected");
+ return FALSE;
+ }
+ proj->setVersion(token);
+ time_t start, end;
+ if (nextToken(token) != DATE)
+ {
+ fatalError("Start date expected");
+ return FALSE;
+ }
+ start = date2time(token);
+ if (nextToken(token) != DATE)
+ {
+ fatalError("End date expected");
+ return FALSE;
+ }
+ end = date2time(token);
+ if (end < start)
+ {
+ fatalError("End date must be larger then start date");
+ return FALSE;
+ }
+ proj->setStart(start);
+ proj->setEnd(end);
+ break;
+ }
else if (token == "htmlTaskReport")
{
if (nextToken(token) != STRING)
return FALSE;
}
proj->setHtmlTaskReport(token);
- for ( ; ; )
+ if (nextToken(token) == LBRACKET)
{
- QString col;
- if ((tt = nextToken(col)) != ID)
+ for ( ; ; )
{
- fatalError("Column ID expected");
- return FALSE;
- }
- proj->addHtmlTaskReportColumn(col);
- if ((tt = nextToken(token)) != COMMA)
- {
- openFiles.last()->returnToken(tt, token);
- break;
+ if ((tt = nextToken(token)) == RBRACKET)
+ break;
+ else if (tt != ID)
+ {
+ fatalError("Attribute ID or '}' expected");
+ return FALSE;
+ }
+ if (token == "columns")
+ {
+ for ( ; ; )
+ {
+ QString col;
+ if ((tt = nextToken(col)) != ID)
+ {
+ fatalError("Column ID expected");
+ return FALSE;
+ }
+ proj->addHtmlTaskReportColumn(col);
+ if ((tt = nextToken(token)) != COMMA)
+ {
+ openFiles.last()->returnToken(tt, token);
+ break;
+ }
+ }
+ }
+ else if (token == "start")
+ {
+ if (nextToken(token) != DATE)
+ {
+ fatalError("Date expected");
+ return FALSE;
+ }
+ proj->setHtmlTaskReportStart(date2time(token));
+ }
+ else if (token == "end")
+ {
+ if (nextToken(token) != DATE)
+ {
+ fatalError("Date expected");
+ return FALSE;
+ }
+ proj->setHtmlTaskReportEnd(date2time(token));
+ }
+ else
+ {
+ fatalError("Illegal attribute");
+ return FALSE;
+ }
}
}
break;
TokenType tt;
QString token;
+ if (proj->getStart() == 0)
+ {
+ fatalError("Project start date must be specified first");
+ return FALSE;
+ }
+
QString id;
if ((tt = nextToken(id)) != ID)
{
fatalError("Unit expected");
return FALSE;
}
- if (unit == "md")
+ if (unit == "min")
+ task->setEffort(effort.toDouble() / (8 * 60));
+ else if (unit == "h")
+ task->setEffort(effort.toDouble() / 8);
+ else if (unit == "d")
task->setEffort(effort.toDouble());
- else if (unit == "mw")
+ else if (unit == "w")
task->setEffort(effort.toDouble() * 5);
- else if (unit == "mm")
+ else if (unit == "m")
task->setEffort(effort.toDouble() * 20);
+ else if (unit == "y")
+ task->setEffort(effort.toDouble() * 240);
else
{
fatalError("Unit expected");
}
bool
-Task::schedule(time_t reqStart)
+Task::schedule(time_t day)
{
// Task is already scheduled.
if (start != 0 && end != 0)
* start time is determined by the end date of the last previous
* task. */
if (previous.count() == 0 ||
- (earliestStart() > 0 && earliestStart() <= reqStart))
+ (earliestStart() > 0 && earliestStart() <= project->getStart()))
{
- start = reqStart;
+ start = project->getStart();
}
else
{
start = earliestStart();
}
+ done = 0.0;
+ costs = 0.0;
+ workStarted = FALSE;
if (start == 0)
- return FALSE; // Task cannot be scheduled yet.
+ return TRUE; // Task cannot be scheduled yet.
}
if (length > 0)
if (allocations.count() == 0)
{
fatalError("No allocations specified for effort based task");
- return FALSE;
+ return TRUE;
}
- double done = 0.0;
- const int oneDay = 60 * 60 * 24;
- int day;
- bool workStarted = FALSE;
- day = start;
- for ( ; ; )
+ double dailyCosts = 0.0;
+ if (isWorkingDay(day))
{
- double costs = 0.0;
- if (isWorkingDay(day))
- {
- if (!bookResources(day, workStarted, done, costs))
-// fprintf(stderr,
+ if (!bookResources(day, dailyCosts))
+// fprintf(stderr,
// "No resource available for task '%s' on %s\n",
// id.latin1(),
// time2ISO(day).latin1())
- ;
- }
- /* If an account has been specified load account with the
- * accumulated costs of this day. */
- if (account)
- account->book(new Transaction(day, -costs, this));
- if (done < effort)
- day += oneDay;
- else
- {
- end = day;
- break;
- }
+ ;
+ }
+ /* If an account has been specified load account with the
+ * accumulated costs of this day. */
+ if (account)
+ account->book(new Transaction(day, -costs, this));
+ if (done >= effort)
+ {
+ end = day;
+ return FALSE;
}
}
else
{
// Task is a milestone.
end = start;
+ return FALSE;
}
return TRUE;
}
time_t nstart = 0;
time_t nend = 0;
+ // Check that this is really a container task
if ((t = subTasks.first()) && (t != 0))
{
if (t->getStart() > 0)
{
start = nstart;
end = nend;
- return TRUE;
+ return FALSE;
}
- return FALSE;
+ return TRUE;
}
bool
-Task::bookResources(time_t day, bool& workStarted, double& done, double& costs)
+Task::bookResources(time_t day, double& dailyCosts)
{
bool allocFound = FALSE;
{
addBookedResource(a->getResource());
done += remaining;
- costs += a->getResource()->getRate() * remaining;
+ dailyCosts += a->getResource()->getRate() * remaining;
}
allocFound = TRUE;
}
{
addBookedResource(a->getResource());
done += remaining;
- costs += r->getRate() * remaining;
+ dailyCosts += r->getRate() * remaining;
}
allocFound = TRUE;
break;
return day;
}
+double
+Task::getLoadOnDay(time_t day)
+{
+ double load = 0.0;
+ for (Resource* r = bookedResources.first(); r != 0;
+ r = bookedResources.next())
+ {
+ load += r->getLoadOnDay(day, this);
+ }
+ return load;
+}
+
bool
Task::xRef(QDict<Task>& hash)
{
Allocation* firstAllocation() { return allocations.first(); }
Allocation* nextAllocation() { return allocations.next(); }
+ double getLoadOnDay(time_t day);
void addBookedResource(Resource* r)
{
if (bookedResources.find(r) == -1)
private:
bool scheduleContainer();
- bool bookResources(time_t day, bool& workStarted,
- double& done, double& costs);
+ bool bookResources(time_t day, double& costs);
bool isWorkingDay(time_t day) const;
time_t nextWorkingDay(time_t day) const;
time_t earliestStart();
// Percentage of completion of the task
int complete;
+ // The following 3 variables are used during scheduling.
+ double costs;
+ double done;
+ bool workStarted;
+
// Account where the costs of the task are credited to.
Account* account;
--- /dev/null
+Specification of the TaskJuggler input format
+=============================================
+
+Version: "$Id$"
+
+A project file contains a list of property declarations. Each property
+may have fixed and optional attributes. Attributes may be of the
+following types:
+
+ID: A string that may consist of the characters A-Z, a-z, 0-9 and _. It may
+not start with a number.
+
+GLOBAL_ID: A GLOBAL_ID may have the same characters as ID but
+additionally it may contain . and !. ! may only be used at the
+beginning and is used in relative IDs. A ! means one scope up.
+
+STRING: A string may contain any characters and is enclosed in ". A
+string may include line breaks.
+
+DATE: A DATE is an ISO compliant date YYYY-MM-DD[-hh[:mm[:ss]]]. Hour,
+minute and second are optional. If not specified the values are set to
+0.
+
+UNIT: May be
+h for hours,
+d for days,
+w for weeks,
+m for months,
+y for years.
+
+INTEGER: An integer number.
+
+REAL: A real number (e.g. 3.14).
+
+Optional attributes of a property must be enclosed by {}.
+
+===============================================================================
+===============================================================================
+
+This is a list of all properties:
+
+===============================================================================
+project <id> <name> <version> <start> <end>
+id: ID
+name: STRING
+version: STRING
+start: DATE
+end: DATE
+
+Optional attributes: none
+
+The project property is mandatory and should be the first property in
+a project file. <id> is a ID used to register resource allocations in
+a global database. <name> is the name of the project. <version> is the
+version of the project file. Typically this is the CVS id. <start> and
+<end> define the timeframe of the project. The end may be well after
+the end of the last task but must be specified to terminate the
+scheduling process.
+
+===============================================================================
+task <id> <name>
+id: ID
+name: STRING
+
+Optional attributes:
+
+-------------------------------------------------------------------------------
+task <id> <name>
+id: ID
+name: STRING
+
+A task may have sub tasks. In case sub tasks are specified many of the
+other attributes are illegal.
+
+-------------------------------------------------------------------------------
+note <text>
+text: STRING
+
+A longer description of the task.
+
+start <date>
+date: DATE
+
+The planned start date for the task. In case no start date is given,
+the task must depend on other tasks. If no dependency is given the
+project start date is used.
+
+-------------------------------------------------------------------------------
+minStart <date>
+date: DATE
+
+The earliest wanted start date for the task. In case this date can't
+be met the task is marked in the task list.
+
+This attribute is inherited by sub tasks.
+
+-------------------------------------------------------------------------------
+maxStart <date>
+date: DATE
+
+The latest wanted start date for the task. In case this date can't be
+met the task is marked in the task list.
+
+This attribute is inherited by sub tasks.
+
+-------------------------------------------------------------------------------
+actualStart <date>
+date: DATE
+
+The actual start date of the task. This can be specified to do
+plan/actual comparisons.
+
+-------------------------------------------------------------------------------
+minEnd <date>
+date: DATE
+
+The earliest wanted end date for the task. In case this date can't be
+met the task is marked in the task list.
+
+This attribute is inherited by sub tasks.
+
+-------------------------------------------------------------------------------
+maxEnd <date>
+date: DATE
+
+The latest wanted end date for the task. In case this date can't be
+met the task is marked in the task list.
+
+This attribute is inherited by sub tasks.
+
+-------------------------------------------------------------------------------
+actualEnd <date>
+date: DATE
+
+The actual end date of the task. This can be specified to do
+plan/actual comparisons.
+
+-------------------------------------------------------------------------------
+length <number> <unit>
+number: REAL
+unit: UNIT
+
+Specifies the time the task occupies the resources. This is working
+time, not calender time. 7d means 7 working days and not one week.
+
+-------------------------------------------------------------------------------
+effort <number> <unit>
+number: REAL
+unit: UNIT
+
+Specifies the effort needed to complete the task. An effort of 4d can
+be done with 2 full-time resources in 2 days.
+
+-------------------------------------------------------------------------------
+complete <percent>
+percent: INTEGER
+
+Specifies how many percent the task is already completed. This can be
+usefull for project tracking.
+
+-------------------------------------------------------------------------------
+allocate <id>
+id: ID
+
+Optional attributes:
+
+...............................................................................
+load <days>
+days: REAL
+
+Specifies how many days the resource can be used per day. A load of
+0.5 means that the resource will be used for half a working day.
+
+...............................................................................
+alternative <id>[,<id>]
+id: ID
+
+Specifies IDs of alternative resources. One of the alternatives will
+be used in case the main resource is not available. If multiple
+resources are used they must be seperated by a comma.
+
+...............................................................................
+
+Specifies a resource that can be used to fullfill the task. More than
+one resource can be specified for a task. All resources must be
+declared before they can be used. Ref. 'resource'.
+
+-------------------------------------------------------------------------------
+depends <id>[,<id>]
+id: GLOBAL_ID
+
+Specifies that the task cannot start before the task with the
+specified IDs have been finished. If multiple IDs are specified they
+must be seperated by a comma. ids must be either global or relative. A
+relative ID starts with a number of !. Each ! moves the scope to the
+parent task. Global IDs do not contain ! but have ID seperated by
+dots.
+
+ Example:
+ task foo1 {
+ task foo2 { start 2002-12-04 }
+ task foo3 { depends !foo2 }
+ }
+ task bar { depends foo1.foo2 }
+
+-------------------------------------------------------------------------------
+flags <id>[,<id>]
+id: ID
+
+Attaches flags to the task. Flags can be used to hide the information
+about the task in the output. Flags must be declared before they can
+be used. Ref. 'flags'. Some predefined flags exist for tasks:
+
+closed: Hides all sub-tasks in all reports.
+hidden: Hides this task in all reports.
+
+Flags are inherited by sub tasks from their parent tasks.
+
+-------------------------------------------------------------------------------
+priority <value>
+value: INTEGER
+
+Specifies a priority between 1 and 1000. A task with higher priority
+is more likely to get the requested resources.
+
+This attribute is inherited by sub tasks.
+
+-------------------------------------------------------------------------------
+account <id>
+id: ID
+
+Specifies the account that all costs associated with this task will be
+credited to.
+
+-------------------------------------------------------------------------------
+Tasks may be nested and some attributes are inherited by the sub tasks.
+
+===============================================================================
+account <id> <name>
+id: ID
+name: STRING
+
+Optional attributes:
+-------------------------------------------------------------------------------
+balance <amount>
+amount: REAL
+
+The initial balance of the account.
+
+-------------------------------------------------------------------------------
+kotrusId <id>
+id: STRING
+
+The KoTrus ID of the account (Kostentraeger).
+
+-------------------------------------------------------------------------------
+Declares an account. Accounts can be used to calculate costs of tasks
+or the whole project.
+
+===============================================================================
+resource <id> <name>
+id: ID
+name: STRING
+
+Optional attributes:
+-------------------------------------------------------------------------------
+minEffort <value>
+value: REAL
+
+The daily minimum effort for a resource. Resources that are
+used less than this value will be marked in the report.
+
+-------------------------------------------------------------------------------
+maxEffort <value>
+value: REAL
+
+The daily maximum effort for a resource. Resources will not be
+scheduled to be used more than this value. A value of 1.0 means a
+whole working day. 0.5 means half a working day.
+
+-------------------------------------------------------------------------------
+rate <value>
+value: REAL
+
+The daily costs of the resource.
+
+-------------------------------------------------------------------------------
+kotrusId <id>
+id: STRING
+
+The KoTrus ID of the resource (email address).
+
+-------------------------------------------------------------------------------
+vacation <from> [- <to>]
+from: DATE
+to: DATE
+
+Specifies a vacation for a resource. The to value is NOT included in
+the vacation.
+
+-------------------------------------------------------------------------------
+
+===============================================================================
+vacation name <start> [- <end>]
+name: STRING
+start: DATE
+end: DATE
+
+Defines a vacation period for all resources. The end value is NOT part
+of the vacation. So 2001-12-24 - 2001-12-25 specifies one day of
+vacation, not two days.
+
+===============================================================================
+priority <value>
+value: INTEGER
+
+The default scheduling priority for tasks. The value must be between 1
+and 1000 and is inherited by all tasks if no other priority is
+specified.
+
+===============================================================================
+minEffort <value> value: REAL
+
+The default daily minimum effort for a resource. Resources that are
+used less than this value will be marked in the report. This value
+will be used for all subsequent resource declarations unless specified
+otherwise.
+
+===============================================================================
+maxEffort <value> value: REAL
+
+The default daily maximum effort for a resource. Resources will not be
+scheduled more than this value. This value will be used for all
+subsequent resource declarations unless specified otherwise.
+
+===============================================================================
+rate <money>
+money: REAL
+
+The default daily rate for using a resource full-time. This value will
+be used for all subsequent resource declarations unless specified
+otherwise.
+
+===============================================================================
+currencyPrefix <prefix>
+prefix: STRING
+
+The prefix for money values in reports.
+
+===============================================================================
+currencyPostfix <postfix>
+postfix: STRING
+
+The postfix for money values in reports.
+
+===============================================================================
+include <filename>
+filename: STRING
+
+Includes the specified filename as if its contense would be written
+instead of the include propoperty.
+
+===============================================================================
+macro <id> [ body ]
+id: ID
+
+The body is not optional it must be enclosed in [ ]. Macros can be
+declared like this:
+
+macro foo [ This text ]
+
+If later ${foo} is found in the project file it is expanded to ' This
+text '. Macros may have arguments. Arguments are special macros with
+numbers as names. The number specifies the index of the argument.
+
+macro foo [ This ${1} text ]
+
+will expend to ' This stupid text ] if called as ${foo
+"stupid"}. Macros may call other macros.
+
+===============================================================================
+flags <id>[,<id>]
+id: ID
+
+Declares the specified flags. Flags can be assigned to tasks to be
+used as filters during report generation.
+
+===============================================================================
+htmlTaskReport <filename>
+filename: STRING
+
+Optional attributes:
+
+-------------------------------------------------------------------------------
+columns <id>[,<id>]
+id: STRING
+
+Specifies which columns should be included in the task report. The
+following values are available:
+
+no: The task index.
+taskId: The global ID of the task.
+task: The name of the task.
+start: The planned start date.
+end: The planned end date.
+minStart: The earliest wanted start date.
+maxStart: The latest wanted start date.
+aStart: The actual start date.
+minEnd: The earliest wanted end date.
+maxEnd: The latest wanted end date.
+aEnd: The actual end date.
+resources: The names of the used resources.
+depends: The task index of the tasks that this task depends on.
+follows: The task index of the tasks that depend on this task.
+note: The description of the task.
+daily: A calender view of the tasks.
+
+-------------------------------------------------------------------------------
+start <day>
+day: DATE
+
+The start date for the calender view.
+
+-------------------------------------------------------------------------------
+end <day>
+day: DATE
+
+The end date for the calender view.
+
+-------------------------------------------------------------------------------
+show <flag>[,flag]
+flag: ID
+
+List only tasks that have the listed flags. This attribute conflicts
+with 'hide'.
+
+-------------------------------------------------------------------------------
+hide <flag>[,flag]
+
+List only tasks that don't have the listed flags. This attribute
+conflicts with 'show'.
+
+-------------------------------------------------------------------------------
+Generates a report of all tasks (excluding hidden and filtered) in
+HTML format.
+
+===============================================================================
+htmlResourceReport <filename>
+filename: STRING
+
+Optional attributes:
+
+-------------------------------------------------------------------------------
+start <day>
+day: DATE
+
+The start date for the calender view.
+
+-------------------------------------------------------------------------------
+end <day>
+day: DATE
+
+The end date for the calender view.
+
+-------------------------------------------------------------------------------
+show <flag>[,flag]
+flag: ID
+
+List only resources that have the listed flags. This attribute conflicts
+with 'hide'.
+
+-------------------------------------------------------------------------------
+hide <flag>[,flag]
+
+List only resources that don't have the listed flags. This attribute
+conflicts with 'show'.
+
+-------------------------------------------------------------------------------
+Generates a report of all resources (excluding hidden and filtered) in
+HTML format.
+
+===============================================================================
+htmlAccountReport <filename>
+filename: STRING
+
+Optional attributes:
+
+-------------------------------------------------------------------------------
+start <day>
+day: DATE
+
+The start date for the calender view.
+
+-------------------------------------------------------------------------------
+end <day>
+day: DATE
+
+The end date for the calender view.
+
+-------------------------------------------------------------------------------
+show <flag>[,flag]
+flag: ID
+
+List only accounts that have the listed flags. This attribute
+conflicts with 'hide'.
+
+-------------------------------------------------------------------------------
+hide <flag>[,flag]
+
+List only accounts that don't have the listed flags. This attribute
+conflicts with 'show'.
+
+-------------------------------------------------------------------------------
+
+===============================================================================
+
+
# This is a test file for TaskJuggler
-start 2001-09-28 # The start Date.
+project sl80 "SuSE Linux 8.0" "$Id$" 2001-09-28 2002-04-01
+
+htmlTaskReport "test.html" {
+ columns no, name, start, end, daily
+ start 2001-10-01
+ end 2002-04-01
+}
+
+htmlResourceReport "resource.html" 2001-11-28 2002-03-06
macro version [SL 8.0]
macro build [
task build "SL 8.0 x86 build ${1}" {
- effort 2md
+ effort 2d
allocate ro { alternative kukuk }
- depends !work
+ depends !dl
}
]
macro burn [
task done "Burn SL 8.0 ${1}" {
- effort 1md
+ effort 1d
allocate mem
depends !build
flags media
task pre${1} "SL 8.0 preview ${1}" {
task work "SL 8.0 x86 make bootable system" {
- effort 15md
+ effort 15d
allocate yast
allocate dist
allocate packagers
task beta${1} "${version} beta${1}" {
task work "SL 8.0 finish all coding work" {
- effort 15md
+ effort 15d
allocate yast
allocate dist
allocate packagers
${build "beta ${1}"}
task ship "SL 8.0 x86 ship beta ${1} to external testers" {
- effort 2md
+ effort 2d
allocate mem
depends !build
}
task test "SL 8.0 x86 test beta ${1}" {
- effort 2md
+ effort 2d
allocate bg
depends !build
}
flags deadline, media
-vacation "Xmas" 2002-12-21 - 2003-01-04
-
-htmlTaskReport "test.html" no, task, start, end, depends, resources
-htmlResourceReport "resource.html" 2001-11-28 2002-03-06
+vacation "Xmas" 2001-12-21 - 2002-01-04
account acc1 "Work" { kotrusId "SuSE Linux" balance 1000.0 }
-resource ro "Ruediger Oertel"
+resource ro "Ruediger Oertel" # Dies ist ein Kommentar
resource kukuk "Thorsten Kukuk"
resource cs "Chris Schlaeger"
resource mem "Muhamed Memovic"
}
task yast "YaST2 development"{
- effort 56md
+ effort 56d
allocate yast
depends !sl80start
}
task pack "SL 8.0 package updates" {
- effort 56md
+ effort 56d
allocate packagers
depends !sl80start
}
task dist "SL 8.0 distribution modifications" {
- effort 56md
+ effort 56d
allocate dist
depends !sl80start
}
${beta "1" "pre4"}
${beta "2" "beta1"}
${beta "3" "beta2"}
-${beta "4" "beta2"}
+${beta "4" "beta3"}
}
\ No newline at end of file