OSDN Git Service

- Input format referenz added
authorcs <cs@e1914e07-63f8-0310-9059-d6d858d7cdca>
Wed, 5 Dec 2001 09:01:10 +0000 (09:01 +0000)
committercs <cs@e1914e07-63f8-0310-9059-d6d858d7cdca>
Wed, 5 Dec 2001 09:01:10 +0000 (09:01 +0000)
- HTML Task Report improved

git-svn-id: https://www.taskjuggler.org/svn/taskjuggler/trunk@9 e1914e07-63f8-0310-9059-d6d858d7cdca

taskjuggler/Project.cpp
taskjuggler/Project.h
taskjuggler/ProjectFile.cpp
taskjuggler/Task.cpp
taskjuggler/Task.h
taskjuggler/docs/en/Reference.txt [new file with mode: 0644]
taskjuggler/test.task

index 4c47185..4395580 100644 (file)
@@ -10,6 +10,7 @@
  * $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;
@@ -31,8 +37,12 @@ Project::Project()
        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
@@ -65,15 +75,19 @@ Project::pass2()
        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");
        }
@@ -87,6 +101,7 @@ bool
 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"
@@ -98,8 +113,9 @@ Project::reportHTMLHeader(FILE* f)
 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;
 }
 
@@ -111,6 +127,11 @@ Project::reportHTMLTaskList()
        if (htmlTaskReport == "")
                return TRUE;
 
+       if (htmlTaskReportStart == 0)
+               htmlTaskReportStart = start;
+       if (htmlTaskReportEnd == 0)
+               htmlTaskReportEnd = 0;
+
        FILE* f;
        if ((f = fopen(htmlTaskReport, "w")) == NULL)
        {
@@ -119,32 +140,49 @@ Project::reportHTMLTaskList()
                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",
@@ -152,6 +190,15 @@ Project::reportHTMLTaskList()
                        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;
@@ -170,10 +217,12 @@ Project::reportHTMLTaskList()
                         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();
@@ -183,33 +232,39 @@ Project::reportHTMLTaskList()
                                        spaces += "&nbsp;&nbsp;&nbsp;&nbsp;";
                                        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;
                                }
@@ -217,7 +272,8 @@ Project::reportHTMLTaskList()
                        }
                        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())
@@ -230,7 +286,8 @@ Project::reportHTMLTaskList()
                        }
                        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())
@@ -243,11 +300,52 @@ Project::reportHTMLTaskList()
                        }
                        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);
@@ -272,28 +370,16 @@ Project::reportHTMLResourceList()
        }
        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())
        {
@@ -307,7 +393,7 @@ Project::reportHTMLResourceList()
                        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");
@@ -326,7 +412,7 @@ Project::reportHTMLResourceList()
                                        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");
@@ -341,6 +427,37 @@ Project::reportHTMLResourceList()
 }
 
 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\">"
+                               "&nbsp;%s%d</font></td>",
+                               isWeekend(day) ? COL_WEEKEND : COL_HEADER,
+                               dom < 10 ? "&nbsp;" : "", 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");
index cd70a74..a846e2a 100644 (file)
@@ -40,6 +40,15 @@ public:
 
        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; }
 
@@ -49,15 +58,6 @@ public:
        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);
@@ -96,6 +96,8 @@ public:
        {
                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; }
@@ -113,15 +115,20 @@ public:
        
 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. */
@@ -145,6 +152,8 @@ private:
 
        QString htmlTaskReport;
        QStringList htmlTaskReportColumns;
+       time_t htmlTaskReportStart;
+       time_t htmlTaskReportEnd;
 
        QString htmlResourceReport;
     time_t htmlResourceReportStart;
index f1853bf..c6f5bde 100644 (file)
@@ -395,26 +395,6 @@ ProjectFile::parse()
                                        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())
@@ -522,6 +502,48 @@ ProjectFile::parse()
                                }
                                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)
@@ -530,19 +552,58 @@ ProjectFile::parse()
                                        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;
@@ -597,6 +658,12 @@ ProjectFile::readTask(Task* parent)
        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)
        {
@@ -1079,12 +1146,18 @@ ProjectFile::readEffort(Task* task)
                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");
index 3cbe2a8..888d07f 100644 (file)
@@ -56,7 +56,7 @@ Task::fatalError(const QString& msg) const
 }
 
 bool
-Task::schedule(time_t reqStart)
+Task::schedule(time_t day)
 {
        // Task is already scheduled.
        if (start != 0 && end != 0)
@@ -75,16 +75,19 @@ Task::schedule(time_t reqStart)
                 * 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)
@@ -109,42 +112,33 @@ Task::schedule(time_t reqStart)
                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;
 }
@@ -156,6 +150,7 @@ Task::scheduleContainer()
        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)
@@ -180,14 +175,14 @@ Task::scheduleContainer()
        {
                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;
 
@@ -210,7 +205,7 @@ Task::bookResources(time_t day, bool& workStarted, double& done, double& costs)
                        {
                                addBookedResource(a->getResource());
                                done += remaining;
-                               costs += a->getResource()->getRate() * remaining;
+                               dailyCosts += a->getResource()->getRate() * remaining;
                        }
                        allocFound = TRUE;
                }
@@ -232,7 +227,7 @@ Task::bookResources(time_t day, bool& workStarted, double& done, double& costs)
                                        {
                                                addBookedResource(a->getResource());
                                                done += remaining;
-                                               costs += r->getRate() * remaining;
+                                               dailyCosts += r->getRate() * remaining;
                                        }
                                        allocFound = TRUE;
                                        break;
@@ -269,6 +264,18 @@ Task::earliestStart()
        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)
 {
index d4daaad..f2fe0b1 100644 (file)
@@ -128,6 +128,7 @@ public:
        Allocation* firstAllocation() { return allocations.first(); }
        Allocation* nextAllocation() { return allocations.next(); }
 
+       double getLoadOnDay(time_t day);
        void addBookedResource(Resource* r)
        {
                if (bookedResources.find(r) == -1)
@@ -163,8 +164,7 @@ public:
 
 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();
@@ -215,6 +215,11 @@ private:
        // 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;
 
diff --git a/taskjuggler/docs/en/Reference.txt b/taskjuggler/docs/en/Reference.txt
new file mode 100644 (file)
index 0000000..f3452a0
--- /dev/null
@@ -0,0 +1,517 @@
+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'.
+
+-------------------------------------------------------------------------------
+
+===============================================================================
+
+
index 38d6272..b90428d 100644 (file)
@@ -1,6 +1,14 @@
 # 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]
 
@@ -13,15 +21,15 @@ macro deadline [
 
 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
@@ -32,7 +40,7 @@ macro preview [
 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
@@ -49,7 +57,7 @@ macro beta [
 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
@@ -60,13 +68,13 @@ task beta${1} "${version} beta${1}" {
   ${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
   }
@@ -75,14 +83,11 @@ task beta${1} "${version} beta${1}" {
 
 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"
@@ -98,19 +103,19 @@ task sl80start "Start of 8.0 development" {
 }
 
 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
 }
@@ -122,5 +127,5 @@ ${preview "4" "!!pre3.work"}
 ${beta "1" "pre4"}
 ${beta "2" "beta1"}
 ${beta "3" "beta2"}
-${beta "4" "beta2"}
+${beta "4" "beta3"}
 }
\ No newline at end of file