OSDN Git Service

* Support for later completion of task and resources added. By
[tjqt4port/tj2qt4.git] / taskjuggler / ProjectFile.cpp
index 5031871..470a066 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 2001, 2002 by Chris Schlaeger <cs@suse.de>
  *
  * This program is free software; you can redistribute it and/or modify
- * it under the terms version 2 of the GNU General Public License as
+ * it under the terms of version 2 of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * $Id$
@@ -12,6 +12,7 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <stream.h>
 #include <unistd.h>
 
@@ -23,7 +24,8 @@
 #include "ExpressionTree.h"
 #include "kotrus.h"
 
-extern Kotrus *kotrus;
+// Dummy marco to mark all keywords of taskjuggler syntax
+#define KW(a) a
 
 #define READ_DATE(a, b) \
 (token == a) \
@@ -135,7 +137,7 @@ FileInfo::getDateFragment(QString& token, int& c)
 QString
 FileInfo::getPath() const
 {
-       if (file.find('/'))
+       if (file.find('/') >= 0)
                return file.left(file.findRev('/') + 1);
        else
                return "";
@@ -165,6 +167,32 @@ FileInfo::nextToken(QString& token)
                case ' ':
                case '\t':
                        break;
+               case '/':
+                       /* This code skips c-style comments like the one you are just
+                        * reading. */
+                       if ((c = getC(FALSE)) == '*')
+                       {
+                               do
+                               {
+                                       while ((c = getC(FALSE)) != '*')
+                                       {
+                                               if (c == '\n')
+                                                       currLine++;
+                                               else if (c == EOF)
+                                               {
+                                                       fatalError("Unterminated comment");
+                                                       return EndOfFile;
+                                               }
+                                       }
+                               } while ((c = getC(FALSE)) != '/');
+                       }
+                       else
+                       {
+                               ungetC(c);
+                               ungetC('/');
+                               goto BLANKS_DONE;
+                       }
+                       break;
                case '#':       // Comments start with '#' and reach towards end of line
                        while ((c = getC(FALSE)) != '\n' && c != EOF)
                                ;
@@ -213,7 +241,7 @@ FileInfo::nextToken(QString& token)
                                token += c;
                        if (c == '-')
                        {
-                               // this must be a ISO date yyyy-mm-dd[-hh:mm]
+                               // this must be a ISO date yyyy-mm-dd[[-hh:mm]-TZ]
                                getDateFragment(token, c);
                                if (c != '-')
                                {
@@ -231,6 +259,13 @@ FileInfo::nextToken(QString& token)
                                        }
                                        getDateFragment(token, c);
                                }
+                               int i = 0;
+                               if (c == '-')
+                               {
+                                       token += c;
+                                       while ((c = getC()) != EOF && isalnum(c) && i++ < 12)
+                                               token += c;
+                               }
                                ungetC(c);
                                return DATE;
                        }
@@ -423,20 +458,36 @@ ProjectFile::open(const QString& file)
                        char buf[1024];
                        if (getcwd(buf, 1023) != 0)
                                absFileName = QString(buf) + "/" + absFileName;
+                       else
+                               qFatal("ProjectFile::open(): getcwd failed");
                }
                else
                        absFileName = openFiles.last()->getPath() + absFileName;
+               if (debugLevel > 2)
+                       qWarning("Expanded filename to %s", absFileName.latin1());
        }
-       while (absFileName.find("/../") >= 0)
+       int end = 0;
+       while (absFileName.find("/../", end) >= 0)
        {
-               int end = absFileName.find("/../");
+               end = absFileName.find("/../");
                int start = absFileName.findRev('/', end - 1);
-               absFileName.replace(start, end + strlen("/../") - start, "/");
+               if (start < 0)
+                       start = 0;
+               else
+                       start++;        // move after '/'
+               if (start < end && absFileName.mid(start, end - start) != "..")
+                       absFileName.remove(start, end + strlen("/../") - start);
+               end += strlen("/..");
        }
 
        // Make sure that we include each file only once.
        if (includedFiles.findIndex(absFileName) != -1)
+       {
+               if (debugLevel > 2)
+                       qWarning("Ignoring already read file %s",
+                                        absFileName.latin1());
                return TRUE;
+       }
                
        FileInfo* fi = new FileInfo(this, absFileName);
 
@@ -446,6 +497,9 @@ ProjectFile::open(const QString& file)
                return FALSE;
        }
 
+       if (debugLevel > 2)
+               qWarning("Reading %s", absFileName.latin1());
+
        openFiles.append(fi);
        includedFiles.append(absFileName);
        return TRUE;
@@ -478,34 +532,45 @@ ProjectFile::parse()
                case EndOfFile:
                        return TRUE;
                case ID:
-                       if (token == "task")
+                       if (token == KW("task"))
                        {
                                if (!readTask(0))
                                        return FALSE;
                                break;
                        }
-                       if (token == "account")
+                       if (token == KW("account"))
                        {
                                if (!readAccount(0))
                                        return FALSE;
                                break;
                        }
-                       else if (token == "resource")
+                       else if (token == KW("resource"))
                        {
                                if (!readResource(0))
                                        return FALSE;
                                break;
                        }
-                       else if (token == "vacation")
+                       else if (token == KW("shift"))
+                       {
+                               if (!readShift(0))
+                                       return FALSE;
+                               break;  
+                       }
+                       else if (token == KW("vacation"))
                        {
                                time_t from, to;
+                               bool isResourceVacation;
                                QString name;
-                               if (!readVacation(from, to, TRUE, &name))
+                               if (!readVacation(from, to, TRUE, &name,
+                                                                 &isResourceVacation))
                                        return FALSE;
+                               if (isResourceVacation)
+                                       proj->getResource(name)->addVacation(
+                                               new Interval(from, to));
                                proj->addVacation(name, from, to);
                                break;
                        }
-                       else if (token == "priority")
+                       else if (token == KW("priority"))
                        {
                                int priority;
                                if (!readPriority(priority))
@@ -513,7 +578,7 @@ ProjectFile::parse()
                                proj->setPriority(priority);
                                break;
                        }
-                       else if (token == "now")
+                       else if (token == KW("now"))
                        {
                                if (nextToken(token) != DATE)
                                {
@@ -523,7 +588,7 @@ ProjectFile::parse()
                                proj->setNow(date2time(token));
                                break;
                        }
-                       else if (token == "mineffort")
+                       else if (token == KW("mineffort"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -533,7 +598,7 @@ ProjectFile::parse()
                                proj->setMinEffort(token.toDouble());
                                break;
                        }
-                       else if (token == "maxeffort")
+                       else if (token == KW("maxeffort"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -543,7 +608,7 @@ ProjectFile::parse()
                                proj->setMaxEffort(token.toDouble());
                                break;
                        }
-                       else if (token == "rate")
+                       else if (token == KW("rate"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -553,7 +618,7 @@ ProjectFile::parse()
                                proj->setRate(token.toDouble());
                                break;
                        }
-                       else if (token == "currency")
+                       else if (token == KW("currency"))
                        {
                                if (nextToken(token) != STRING)
                                {
@@ -563,7 +628,7 @@ ProjectFile::parse()
                                proj->setCurrency(token);
                                break;
                        }
-                       else if (token == "currencydigits")
+                       else if (token == KW("currencydigits"))
                        {
                                if (nextToken(token) != INTEGER)
                                {
@@ -573,20 +638,26 @@ ProjectFile::parse()
                                proj->setCurrencyDigits(token.toInt());
                                break;
                        }
-                       else if (token == "timingresolution")
+                       else if (token == KW("timingresolution"))
                        {
                                ulong resolution;
                                if (!readTimeValue(resolution))
                                        return FALSE;
+                               if (proj->resourceCount() > 0)
+                               {
+                                       fatalError("The timing resolution cannot be changed after "
+                                                          "resources have been declared.");
+                                       return FALSE;
+                               }
                                if (resolution < 60 * 5)
                                {
-                                       fatalError("scheduleGranularity must be at least 5 min");
+                                       fatalError("timing resolution must be at least 5 min");
                                        return FALSE;
                                }
                                proj->setScheduleGranularity(resolution);
                                break;
                        }
-                       else if (token == "copyright")
+                       else if (token == KW("copyright"))
                        {
                                if (nextToken(token) != STRING)
                                {
@@ -596,13 +667,13 @@ ProjectFile::parse()
                                proj->setCopyright(token);
                                break;
                        }
-                       else if (token == "include")
+                       else if (token == KW("include"))
                        {
                                if (!readInclude())
                                        return FALSE;
                                break;
                        }
-                       else if (token == "macro")
+                       else if (token == KW("macro"))
                        {
                                QString id;
                                if (nextToken(id) != ID)
@@ -626,7 +697,7 @@ ProjectFile::parse()
                                }
                                break;
                        }
-                       else if (token == "flags")
+                       else if (token == KW("flags"))
                        {
                                for ( ; ; )
                                {
@@ -650,7 +721,7 @@ ProjectFile::parse()
                                }
                                break;
                        }
-                       else if (token == "project")
+                       else if (token == KW("project"))
                        {
                                if (nextToken(token) != ID)
                                {
@@ -698,7 +769,7 @@ ProjectFile::parse()
                                proj->setEnd(end);
                                break;
                        }
-                       else if (token == "projectid")
+                       else if (token == KW("projectid"))
                        {
                                for ( ; ; )
                                {
@@ -725,46 +796,69 @@ ProjectFile::parse()
                                }
                                break;
                        }
-                       else if (token == "xmltaskreport" )
+                       else if (token == KW("xmltaskreport"))
                        {
                           if( !readXMLTaskReport())
                              return FALSE;
                           break;
                        }
-                       else if (token == "htmltaskreport" ||
-                                        token == "htmlresourcereport")
+#ifdef HAVE_KDE
+                       else if (token == "icalreport" )
+                       {
+                          if( !readICalTaskReport())
+                             return FALSE;
+                          break;
+                       }
+#endif
+                       else if (token == KW("htmltaskreport") ||
+                                        token == KW("htmlresourcereport"))
                        {
                                if (!readHTMLReport(token))
                                        return FALSE;
                                break;
                        }
-                       else if (token == "htmlaccountreport")
+                       else if (token == KW("htmlaccountreport"))
                        {
                                if (!readHTMLAccountReport())
                                        return FALSE;
                                break;
                        }
-                       else if( token == "kotrusmode" )
-                       {
-                          if( kotrus )
-                          {
-                             if( nextToken(token) != STRING )
-                             {
-                                kotrus->setKotrusMode( "NoKotrus" );
-                             }
-                             else
-                             {
-                                if( token == "db" || token == "xml" || token == "nokotrus" )
-                                   kotrus->setKotrusMode( token );
-                                else
-                                {
-                                   fatalError( "Unknown kotrus-mode");
-                                   return( false );
-                                }
-                             }
-                          }
-                          break;
+                       else if (token == KW("export"))
+                       {
+                               if (!readExportReport())
+                                       return FALSE;
+                               break;
+                       }
+                       else if (token == KW("kotrusmode"))
+                       {
+                               if (nextToken(token) != STRING ||
+                                       (token != KW("db") && token != KW("xml") &&
+                                        token != KW("nokotrus")))
+                               {
+                                       fatalError("Unknown kotrus mode");
+                                       return FALSE;
+                               }
+                               if (token != KW("nokotrus"))
+                               {
+                                       Kotrus* kotrus = new Kotrus();
+                                       kotrus->setKotrusMode(token);
+                                       proj->setKotrus(kotrus);
+                               }
+                               break;
                        }
+                       else if (token == KW("supplement"))
+                       {
+                               if (nextToken(token) != ID ||
+                                       (token != KW("task") && (token != KW("resource"))))
+                               {
+                                       fatalError("'task' or 'resource' expected");
+                                       return FALSE;
+                               }
+                               if ((token == "task" && !readTaskSupplement()) ||
+                                       (token == "resource" && !readResourceSupplement()))
+                                       return FALSE;
+                               break;
+                       }       
                        // break missing on purpose!
                default:
                        fatalError(QString("Syntax Error at '") + token + "'!");
@@ -887,19 +981,17 @@ ProjectFile::readTask(Task* parent)
        }
 
        if (parent)
-       {
                id = parent->getId() + "." + id;
-               // We need to check that the task id has not been declared before.
-               TaskList tl;
-               parent->getSubTaskList(tl);
-               for (Task* t = tl.first(); t != 0; t = tl.next())
-                       if (t->getId() == id)
-                       {
-                               fatalError(QString().sprintf(
-                                       "Task %s has already been declared", id.latin1()));
-                               return FALSE;
-                       }
-       }
+       
+       // We need to check that the task id has not been declared before.
+       TaskList tl = proj->getTaskList();
+       for (Task* t = tl.first(); t != 0; t = tl.next())
+               if (t->getId() == id)
+               {
+                       fatalError(QString().sprintf
+                                          ("Task %s has already been declared", id.latin1()));
+                       return FALSE;
+               }
 
        Task* task = new Task(proj, id, name, parent, getFile(), getLine());
 
@@ -907,17 +999,57 @@ ProjectFile::readTask(Task* parent)
        if (parent)
                parent->addSub(task);
 
+
+       if (!readTaskBody(task))
+               return FALSE;
+       
+       if (task->getName().isEmpty())
+       {
+               fatalError(QString("No name specified for task ") + id + "!");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+bool
+ProjectFile::readTaskSupplement()
+{
+       QString token;
+       TokenType tt;
+       Task* task;
+
+       if (((tt = nextToken(token)) != ID && tt != RELATIVE_ID) ||
+               ((task = proj->getTask(token)) == 0))
+       {
+               fatalError("Already defined task ID expected");
+               return FALSE;
+       }
+       if (nextToken(token) != LCBRACE)
+       {
+               fatalError("'}' expected");
+               return FALSE;
+       }
+       return readTaskBody(task);
+}
+
+bool
+ProjectFile::readTaskBody(Task* task)
+{
+       QString token;
+       TokenType tt;
+       
        for (bool done = false ; !done; )
        {
                switch (tt = nextToken(token))
                {
                case ID:
-                       if (token == "task")
+                       if (token == KW("task"))
                        {
                                if (!readTask(task))
                                        return FALSE;
                        }
-                       else if (token == "note")
+                       else if (token == KW("note"))
                        {
                                if ((tt = nextToken(token)) == STRING)
                                        task->setNote(token);
@@ -927,61 +1059,61 @@ ProjectFile::readTask(Task* parent)
                                        return FALSE;
                                }
                        }
-                       else if (token == "milestone")
+                       else if (token == KW("milestone"))
                        {
                                task->setMilestone();
                        }
-                       else if READ_DATE("start", setPlanStart)
-                       else if READ_DATE("end", setPlanEnd)
-                       else if READ_DATE("minstart", setMinStart)
-                       else if READ_DATE("maxstart", setMaxStart)
-                       else if READ_DATE("minend", setMinEnd)
-                       else if READ_DATE("maxend", setMaxEnd)
-                       else if READ_DATE("actualstart", setActualStart)
-                       else if READ_DATE("actualsnd", setActualEnd)
-                       else if (token == "length")
+                       else if READ_DATE(KW("start"), setPlanStart)
+                       else if READ_DATE(KW("end"), setPlanEnd)
+                       else if READ_DATE(KW("minstart"), setMinStart)
+                       else if READ_DATE(KW("maxstart"), setMaxStart)
+                       else if READ_DATE(KW("minend"), setMinEnd)
+                       else if READ_DATE(KW("maxend"), setMaxEnd)
+                       else if READ_DATE(KW("actualstart"), setActualStart)
+                       else if READ_DATE(KW("actualend"), setActualEnd)
+                       else if (token == KW("length"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setPlanLength(d);
                        }
-                       else if (token == "effort")
+                       else if (token == KW("effort"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setPlanEffort(d);
                        }
-                       else if (token == "duration")
+                       else if (token == KW("duration"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setPlanDuration(d);
                        }
-                       else if (token == "actuallength")
+                       else if (token == KW("actuallength"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setActualLength(d);
                        }
-                       else if (token == "actualeffort")
+                       else if (token == KW("actualeffort"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setActualEffort(d);
                        }
-                       else if (token == "actualduration")
+                       else if (token == KW("actualduration"))
                        {
                                double d;
                                if (!readPlanTimeFrame(task, d))
                                        return FALSE;
                                task->setActualDuration(d);
                        }
-                       else if (token == "complete")
+                       else if (token == KW("complete"))
                        {
                                if (nextToken(token) != INTEGER)
                                {
@@ -996,7 +1128,7 @@ ProjectFile::readTask(Task* parent)
                                }
                                task->setComplete(complete);
                        }
-                       else if (token == "responsible")
+                       else if (token == KW("responsible"))
                        {
                                Resource* r;
                                if (nextToken(token) != ID ||
@@ -1007,12 +1139,12 @@ ProjectFile::readTask(Task* parent)
                                }
                                task->setResponsible(r);
                        }
-                       else if (token == "allocate")
+                       else if (token == KW("allocate"))
                        {
                                if (!readAllocate(task))
                                        return FALSE;
                        }
-                       else if (token == "depends")
+                       else if (token == KW("depends"))
                        {
                                for ( ; ; )
                                {
@@ -1032,7 +1164,7 @@ ProjectFile::readTask(Task* parent)
                                        }
                                }
                        }
-                       else if (token == "preceeds")
+                       else if (token == KW("preceeds"))
                        {
                                for ( ; ; )
                                {
@@ -1052,12 +1184,12 @@ ProjectFile::readTask(Task* parent)
                                        }
                                }
                        }
-                       else if (token == "scheduling")
+                       else if (token == KW("scheduling"))
                        {
                                nextToken(token);
-                               if (token == "asap")
+                               if (token == KW("asap"))
                                        task->setScheduling(Task::ASAP);
-                               else if (token == "alap")
+                               else if (token == KW("alap"))
                                        task->setScheduling(Task::ALAP);
                                else
                                {
@@ -1065,7 +1197,7 @@ ProjectFile::readTask(Task* parent)
                                        return FALSE;
                                }
                        }
-                       else if (token == "flags")
+                       else if (token == KW("flags"))
                        {
                                for ( ; ; )
                                {
@@ -1083,7 +1215,7 @@ ProjectFile::readTask(Task* parent)
                                        }
                                }
                        }
-                       else if (token == "priority")
+                       else if (token == KW("priority"))
                        {
                                int priority;
                                if (!readPriority(priority))
@@ -1091,7 +1223,7 @@ ProjectFile::readTask(Task* parent)
                                task->setPriority(priority);
                                break;
                        }
-                       else if (token == "account")
+                       else if (token == KW("account"))
                        {
                                QString account;
                                if (nextToken(account) != ID ||
@@ -1103,7 +1235,7 @@ ProjectFile::readTask(Task* parent)
                                task->setAccount(proj->getAccount(account));
                                break;
                        }
-                       else if (token == "startcredit")
+                       else if (token == KW("startcredit"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -1113,7 +1245,7 @@ ProjectFile::readTask(Task* parent)
                                task->setStartCredit(token.toDouble());
                                break;
                        }
-                       else if (token == "endcredit")
+                       else if (token == KW("endcredit"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -1123,7 +1255,7 @@ ProjectFile::readTask(Task* parent)
                                task->setEndCredit(token.toDouble());
                                break;
                        }
-                       else if (token == "projectid")
+                       else if (token == KW("projectid"))
                        {
                                if (nextToken(token) != ID ||
                                        !proj->isValidId(token))
@@ -1134,7 +1266,7 @@ ProjectFile::readTask(Task* parent)
                                task->setProjectId(token);
                                break;
                        }
-                       else if (token == "include")
+                       else if (token == KW("include"))
                        {
                                if (!readInclude())
                                        return FALSE;
@@ -1151,28 +1283,41 @@ ProjectFile::readTask(Task* parent)
                        done = true;
                        break;
                default:
-                       qDebug("%s", token.latin1());
                        fatalError(QString("Syntax Error at '") + token + "'");
                        return FALSE;
                }
        }
 
-       if (task->getName().isEmpty())
-       {
-               fatalError(QString("No name specified for task ") + id + "!");
-               return FALSE;
-       }
-
        return TRUE;
 }
 
 bool
-ProjectFile::readVacation(time_t& from, time_t& to, bool readName, QString* n)
+ProjectFile::readVacation(time_t& from, time_t& to, bool readName,
+                                                 QString* n, bool* isResourceVacation)
 {
        TokenType tt;
        if (readName)
        {
-               if ((tt = nextToken(*n)) != STRING)
+               /* If we find a string then we expect a global vacation
+                * definition. If we find an ID then this is an out-of-scope
+                * vacation definition for the resource with this particular
+                * ID. */
+               *isResourceVacation = FALSE;
+               if ((tt = nextToken(*n)) == STRING)
+                       ;       // We don't have to do anything
+#if 0
+               else if (tt == ID)
+               {
+                       if (!proj->getResource(*n))
+                       {
+                               fatalError(QString().sprintf(
+                                       "Resource %s is undefined", n->latin1()));
+                               return FALSE;
+                       }
+                       *isResourceVacation = TRUE;
+               }
+#endif
+               else
                {
                        fatalError("String expected");
                        return FALSE;
@@ -1243,98 +1388,224 @@ ProjectFile::readResource(Resource* parent)
        if ((tt = nextToken(token)) == LCBRACE)
        {
                // read optional attributes
-               while ((tt = nextToken(token)) != RCBRACE)
+               if (!readResourceBody(r))
+                       return FALSE;
+       }
+       else
+               openFiles.last()->returnToken(tt, token);
+
+       proj->addResource(r);
+
+       return TRUE;
+}
+
+bool
+ProjectFile::readResourceSupplement()
+{
+       QString token;
+       Resource* r;
+       if (nextToken(token) != ID || (r = proj->getResource(token)) == 0)
+       {
+               fatalError("Already defined resource ID expected");
+               return FALSE;
+       }
+       if (nextToken(token) != LCBRACE)
+       {
+               fatalError("'{' expected");
+               return FALSE;
+       }
+       return readResourceBody(r);
+}
+
+bool
+ProjectFile::readResourceBody(Resource* r)
+{
+       QString token;
+       TokenType tt;
+
+       while ((tt = nextToken(token)) != RCBRACE)
+       {
+               if (tt != ID)
                {
-                       if (tt != ID)
+                       fatalError(QString("Unknown attribute '") + token + "'");
+                       return FALSE;
+               }
+               if (token == KW("resource"))
+               {
+                       if (!readResource(r))
+                               return FALSE;
+               }
+               else if (token == KW("mineffort"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               fatalError(QString("Unknown attribute '") + token + "'");
+                               fatalError("Real value exptected");
                                return FALSE;
                        }
-                       if (token == "resource")
+                       r->setMinEffort(token.toDouble());
+               }
+               else if (token == KW("maxeffort"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (!readResource(r))
-                                       return FALSE;
+                               fatalError("Real value exptected");
+                               return FALSE;
                        }
-                       else if (token == "mineffort")
+                       r->setMaxEffort(token.toDouble());
+               }
+               else if (token == KW("efficiency"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setMinEffort(token.toDouble());
+                               fatalError("Read value expected");
+                               return FALSE;
                        }
-                       else if (token == "maxeffort")
+                       r->setEfficiency(token.toDouble());
+               }
+               else if (token == KW("rate"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setMaxEffort(token.toDouble());
+                               fatalError("Real value exptected");
+                               return FALSE;
                        }
-                       else if (token == "efficiency")
+                       r->setRate(token.toDouble());
+               }
+               else if (token == KW("kotrusid"))
+               {
+                       if (nextToken(token) != STRING)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Read value expected");
-                                       return FALSE;
-                               }
-                               r->setEfficiency(token.toDouble());
+                               fatalError("String expected");
+                               return FALSE;
                        }
-                       else if (token == "rate")
+                       r->setKotrusId(token);
+               }
+               else if (token == KW("vacation"))
+               {
+                       time_t from, to;
+                       if (!readVacation(from, to))
+                               return FALSE;
+                       r->addVacation(new Interval(from, to));
+               }
+               else if (token == KW("workinghours"))
+               {
+                       int dow;
+                       QPtrList<Interval>* l = new QPtrList<Interval>();
+                       if (!readWorkingHours(dow, l))
+                               return FALSE;
+
+                       r->setWorkingHours(dow, l);
+               }
+               else if (token == KW("shift"))
+               {
+                       QString id;
+                       if (nextToken(id) != ID)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setRate(token.toDouble());
+                               fatalError("Shift ID expected");
+                               return FALSE;
                        }
-                       else if (token == "kotrusid")
+                       Shift* s;
+                       if ((s = proj->getShift(id)) == 0)
                        {
-                               if (nextToken(token) != STRING)
+                               fatalError("Unknown shift");
+                               return FALSE;
+                       }
+                       time_t from, to;
+                       if (!readVacation(from, to))
+                               return FALSE;
+                       if (!r->addShift(Interval(from, to), s))
+                       {
+                               fatalError("Shift interval overlaps with other");
+                               return FALSE;
+                       }
+               }
+               else if (token == KW("flags"))
+               {
+                       for ( ; ; )
+                       {
+                               QString flag;
+                               if (nextToken(flag) != ID || !proj->isAllowedFlag(flag))
                                {
-                                       fatalError("String expected");
+                                       fatalError("flag unknown");
                                        return FALSE;
                                }
-                               r->setKotrusId(token);
+                               r->addFlag(flag);
+                               if ((tt = nextToken(token)) != COMMA)
+                               {
+                                       openFiles.last()->returnToken(tt, token);
+                                       break;
+                               }
                        }
-                       else if (token == "vacation")
+               }
+               else if (token == KW("include"))
+               {
+                       if (!readInclude())
+                               return FALSE;
+                       break;
+               }
+               else
+               {
+                       fatalError(QString("Unknown attribute '") + token + "'");
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+bool
+ProjectFile::readShift(Shift* parent)
+{
+       // Syntax: 'shift id "name" { ... }
+       QString id;
+       if (nextToken(id) != ID)
+       {
+               fatalError("ID expected");
+               return FALSE;
+       }
+       QString name;
+       if (nextToken(name) != STRING)
+       {
+               fatalError("String expected");
+               return FALSE;
+       }
+
+       if (proj->getShift(id))
+       {
+               fatalError(QString().sprintf(
+                       "Shift %s has already been defined", id.latin1()));
+               return FALSE;
+       }
+
+       Shift* s = new Shift(proj, id, name, parent);
+
+       TokenType tt;
+       QString token;
+       if ((tt = nextToken(token)) == LCBRACE)
+       {
+               // read optional attributes
+               while ((tt = nextToken(token)) != RCBRACE)
+               {
+                       if (tt != ID)
                        {
-                               time_t from, to;
-                               if (!readVacation(from, to))
+                               fatalError(QString("Unknown attribute '") + token + "'");
+                               return FALSE;
+                       }
+                       if (token == KW("shift"))
+                       {
+                               if (!readShift(s))
                                        return FALSE;
-                               r->addVacation(new Interval(from, to));
                        }
-                       else if (token == "workinghours")
+                       else if (token == KW("workinghours"))
                        {
                                int dow;
                                QPtrList<Interval>* l = new QPtrList<Interval>();
                                if (!readWorkingHours(dow, l))
                                        return FALSE;
                                
-                               r->setWorkingHours(dow, l);
-                       }
-                       else if (token == "flags")
-                       {
-                               for ( ; ; )
-                               {
-                                       QString flag;
-                                       if (nextToken(flag) != ID || !proj->isAllowedFlag(flag))
-                                       {
-                                               fatalError("flag unknown");
-                                               return FALSE;
-                                       }
-                                       r->addFlag(flag);
-                                       if ((tt = nextToken(token)) != COMMA)
-                                       {
-                                               openFiles.last()->returnToken(tt, token);
-                                               break;
-                                       }
-                               }
+                               s->setWorkingHours(dow, l);
                        }
-                       else if (token == "include")
+                       else if (token == KW("include"))
                        {
                                if (!readInclude())
                                        return FALSE;
@@ -1350,7 +1621,7 @@ ProjectFile::readResource(Resource* parent)
        else
                openFiles.last()->returnToken(tt, token);
 
-       proj->addResource(r);
+       proj->addShift(s);
 
        return TRUE;
 }
@@ -1385,15 +1656,16 @@ ProjectFile::readAccount(Account* parent)
                /* Only accounts with no parent can have a type specifier. All
                 * sub accounts inherit the type of the parent. */
                QString at;
-               if (nextToken(at) != ID && (at != "cost" || at != "revenue"))
+               if (nextToken(at) != ID && (at != KW("cost") ||
+                                                                       at != KW("revenue")))
                {
                        fatalError("Account type 'cost' or 'revenue' expected");
                        return FALSE;
                }
-               acctType = at == "cost" ? Account::Cost : Account::Revenue;
+               acctType = at == KW("cost") ? Account::Cost : Account::Revenue;
        }
        else
-               acctType = parent->getType();
+               acctType = parent->getAcctType();
 
        Account* a = new Account(proj, id, name, parent, acctType);
        if (parent)
@@ -1413,18 +1685,18 @@ ProjectFile::readAccount(Account* parent)
                                fatalError(QString("Unknown attribute '") + token + "'");
                                return FALSE;
                        }
-                       if (token == "account" && !cantBeParent)
+                       if (token == KW("account") && !cantBeParent)
                        {
                                if (!readAccount(a))
                                        return FALSE;
                                hasSubAccounts = TRUE;
                        }
-                       else if (token == "credit")
+                       else if (token == KW("credit"))
                        {
                                if (!readCredit(a))
                                        return FALSE;
                        }
-                       else if (token == "kotrusid" && !hasSubAccounts)
+                       else if (token == KW("kotrusid") && !hasSubAccounts)
                        {
                                if (nextToken(token) != STRING)
                                {
@@ -1434,7 +1706,7 @@ ProjectFile::readAccount(Account* parent)
                                a->setKotrusId(token);
                                cantBeParent = TRUE;
                        }
-                       else if (token == "include")
+                       else if (token == KW("include"))
                        {
                                if (!readInclude())
                                        return FALSE;
@@ -1506,7 +1778,7 @@ ProjectFile::readAllocate(Task* t)
                                fatalError(QString("Unknown attribute '") + token + "'");
                                return FALSE;
                        }
-                       if (token == "load")
+                       if (token == KW("load"))
                        {
                                if (nextToken(token) != REAL)
                                {
@@ -1521,11 +1793,11 @@ ProjectFile::readAllocate(Task* t)
                                }
                                a->setLoad((int) (100 * load));
                        }
-                       else if (token == "persistent")
+                       else if (token == KW("persistent"))
                        {
                                a->setPersistent(TRUE);
                        }
-                       else if (token == "alternative")
+                       else if (token == KW("alternative"))
                        {
                                do
                                {
@@ -1564,17 +1836,17 @@ ProjectFile::readTimeValue(ulong& value)
                fatalError("Unit expected");
                return FALSE;
        }
-       if (unit == "min")
+       if (unit == KW("min"))
                value = val.toULong() * 60;
-       else if (unit == "h")
+       else if (unit == KW("h"))
                value = val.toULong() * (60 * 60);
-       else if (unit == "d")
+       else if (unit == KW("d"))
                value = val.toULong() * (60 * 60 * 24);
-       else if (unit == "w")
+       else if (unit == KW("w"))
                value = val.toULong() * (60 * 60 * 24 * 7);
-       else if (unit == "m")
+       else if (unit == KW("m"))
                value = val.toULong() * (60 * 60 * 24 * 30);
-       else if (unit == "y")
+       else if (unit == KW("y"))
                value = val.toULong() * (60 * 60 * 24 * 356);
        else
        {
@@ -1600,17 +1872,17 @@ ProjectFile::readPlanTimeFrame(Task* task, double& value)
                fatalError("Unit expected");
                return FALSE;
        }
-       if (unit == "min")
+       if (unit == KW("min"))
                value = val.toDouble() / (8 * 60);
-       else if (unit == "h")
+       else if (unit == KW("h"))
                value = val.toDouble() / 8;
-       else if (unit == "d")
+       else if (unit == KW("d"))
                value = val.toDouble();
-       else if (unit == "w")
+       else if (unit == KW("w"))
                value = val.toDouble() * 5;
-       else if (unit == "m")
+       else if (unit == KW("m"))
                value = val.toDouble() * 20;
-       else if (unit == "y")
+       else if (unit == KW("y"))
                value = val.toDouble() * 240;
        else
        {
@@ -1631,7 +1903,8 @@ ProjectFile::readWorkingHours(int& dayOfWeek, QPtrList<Interval>* l)
                fatalError("Weekday expected");
                return FALSE;
        }
-       const char* days[] = { "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT" };
+       const char* days[] = { KW("sun"), KW("mon"), KW("tue"), KW("wed"),
+               KW("thu"), KW("fri"), KW("sat") };
        for (dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++)
                if (days[dayOfWeek] == day)
                        break;
@@ -1640,6 +1913,14 @@ ProjectFile::readWorkingHours(int& dayOfWeek, QPtrList<Interval>* l)
                fatalError("Weekday expected");
                return FALSE;
        }
+
+       QString token;
+       TokenType tt;
+       if ((tt = nextToken(token)) == ID && token == KW("off"))
+               return TRUE;
+       else
+               returnToken(tt, token);
+
        for ( ; ; )
        {
                QString start;
@@ -1690,6 +1971,23 @@ ProjectFile::readPriority(int& priority)
        return TRUE;
 }
 
+#ifdef HAVE_KDE
+bool
+ProjectFile::readICalTaskReport()
+{
+   QString token;
+   if (nextToken(token) != STRING)
+   {
+      fatalError("File name expected");
+      return FALSE;
+   }
+   ReportICal *rep = new ReportICal( proj, token, proj->getStart(), proj->getEnd());
+   proj->addICalReport( rep );
+
+   return( true );
+}
+#endif
+
 bool
 ProjectFile::readXMLTaskReport()
 {
@@ -1699,7 +1997,8 @@ ProjectFile::readXMLTaskReport()
       fatalError("File name expected");
       return FALSE;
    }
-   ReportXML *rep = new ReportXML( proj, token, proj->getStart(), proj->getEnd());
+   ReportXML *rep = new ReportXML(proj, token, proj->getStart(),
+                                                                 proj->getEnd());
    proj->addXMLReport( rep );
 
    return( true );
@@ -1717,10 +2016,10 @@ ProjectFile::readHTMLReport(const QString& reportType)
        }
        
        ReportHtml* report;
-       if (reportType == "htmltaskreport")
+       if (reportType == KW("htmltaskreport"))
                report = new HTMLTaskReport(proj, token, proj->getStart(),
                                                                        proj->getEnd());
-       else if (reportType == "htmlresourcereport")
+       else if (reportType == KW("htmlresourcereport"))
                report = new HTMLResourceReport(proj, token, proj->getStart(),
                                                                                proj->getEnd());
        else
@@ -1745,7 +2044,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        fatalError("Attribute ID or '}' expected");
                        return FALSE;
                }
-               if (token == "columns")
+               if (token == KW("columns"))
                {
                        report->clearColumns();
                        for ( ; ; )
@@ -1764,7 +2063,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                                }
                        }
                }
-               else if (token == "start")
+               else if (token == KW("start"))
                {
                        if (nextToken(token) != DATE)
                        {
@@ -1773,7 +2072,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        }
                        report->setStart(date2time(token));
                }
-               else if (token == "end")
+               else if (token == KW("end"))
                {
                        if (nextToken(token) != DATE)
                        {
@@ -1782,7 +2081,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        }
                        report->setEnd(date2time(token));
                }
-               else if (token == "headline")
+               else if (token == KW("headline"))
                {
                        if (nextToken(token) != STRING)
                        {
@@ -1791,7 +2090,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        }
                        report->setHeadline(token);
                }
-               else if (token == "caption")
+               else if (token == KW("caption"))
                {
                        if (nextToken(token) != STRING)
                        {
@@ -1800,15 +2099,15 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        }
                        report->setCaption(token);
                }
-               else if (token == "showactual")
+               else if (token == KW("showactual"))
                {
                        report->setShowActual(TRUE);
                }
-               else if (token == "showprojectids")
+               else if (token == KW("showprojectids"))
                {
                        report->setShowPIDs(TRUE);
                }
-               else if (token == "hidetask")
+               else if (token == KW("hidetask"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1816,7 +2115,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setHideTask(et);
                }
-               else if (token == "rolluptask")
+               else if (token == KW("rolluptask"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1824,12 +2123,12 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setRollUpTask(et);
                }
-               else if (token == "sorttasks")
+               else if (token == KW("sorttasks"))
                {
                        if (!readSorting(report, 0))
                                return FALSE;
                }
-               else if (token == "hideresource")
+               else if (token == KW("hideresource"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1837,7 +2136,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setHideResource(et);
                }
-               else if (token == "rollupresource")
+               else if (token == KW("rollupresource"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1845,7 +2144,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setRollUpResource(et);
                }
-               else if (token == "sortresources")
+               else if (token == KW("sortresources"))
                {
                        if (!readSorting(report, 1))
                                return FALSE;
@@ -1857,7 +2156,7 @@ ProjectFile::readHTMLReport(const QString& reportType)
                }
        }
 
-       if (reportType == "htmltaskreport")
+       if (reportType == KW("htmltaskreport"))
                proj->addHTMLTaskReport((HTMLTaskReport*) report);
        else
                proj->addHTMLResourceReport((HTMLResourceReport*) report);
@@ -1895,7 +2194,7 @@ ProjectFile::readHTMLAccountReport()
                        fatalError("Attribute ID or '}' expected");
                        return FALSE;
                }
-               if (token == "columns")
+               if (token == KW("columns"))
                {
                        report->clearColumns();
                        for ( ; ; )
@@ -1914,7 +2213,7 @@ ProjectFile::readHTMLAccountReport()
                                }
                        }
                }
-               else if (token == "start")
+               else if (token == KW("start"))
                {
                        if (nextToken(token) != DATE)
                        {
@@ -1923,7 +2222,7 @@ ProjectFile::readHTMLAccountReport()
                        }
                        report->setStart(date2time(token));
                }
-               else if (token == "end")
+               else if (token == KW("end"))
                {
                        if (nextToken(token) != DATE)
                        {
@@ -1932,7 +2231,7 @@ ProjectFile::readHTMLAccountReport()
                        }
                        report->setEnd(date2time(token));
                }
-               else if (token == "headline")
+               else if (token == KW("headline"))
                {
                        if (nextToken(token) != STRING)
                        {
@@ -1941,7 +2240,7 @@ ProjectFile::readHTMLAccountReport()
                        }
                        report->setHeadline(token);
                }
-               else if (token == "caption")
+               else if (token == KW("caption"))
                {
                        if (nextToken(token) != STRING)
                        {
@@ -1950,19 +2249,19 @@ ProjectFile::readHTMLAccountReport()
                        }
                        report->setCaption(token);
                }
-               else if (token == "hideplan")
+               else if (token == KW("hideplan"))
                {
                        report->setHidePlan(TRUE);
                }
-               else if (token == "showactual")
+               else if (token == KW("showactual"))
                {
                        report->setShowActual(TRUE);
                }
-               else if (token == "accumulate")
+               else if (token == KW("accumulate"))
                {
                        report->setAccumulate(TRUE);
                }
-               else if (token == "hideaccount")
+               else if (token == KW("hideaccount"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1970,7 +2269,7 @@ ProjectFile::readHTMLAccountReport()
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setHideAccount(et);
                }
-               else if (token == "rollupaccount")
+               else if (token == KW("rollupaccount"))
                {
                        Operation* op;
                        if ((op = readLogicalExpression()) == 0)
@@ -1978,7 +2277,7 @@ ProjectFile::readHTMLAccountReport()
                        ExpressionTree* et = new ExpressionTree(op);
                        report->setRollUpAccount(et);
                }
-               else if (token == "sortaccounts")
+               else if (token == KW("sortaccounts"))
                {
                        if (!readSorting(report, 2))
                                return FALSE;
@@ -1995,6 +2294,64 @@ ProjectFile::readHTMLAccountReport()
        return TRUE;
 }
 
+bool
+ProjectFile::readExportReport()
+{
+       QString token;
+       if (nextToken(token) != STRING)
+       {
+               fatalError("File name expected");
+               return FALSE;
+       }
+       
+       ExportReport* report;
+       report = new ExportReport(proj, token);
+               
+       TokenType tt;
+       if ((tt = nextToken(token)) != LCBRACE)
+       {
+               openFiles.last()->returnToken(tt, token);
+               return TRUE;
+       }
+
+       for ( ; ; )
+       {
+               if ((tt = nextToken(token)) == RCBRACE)
+                       break;
+               else if (tt != ID)
+               {
+                       fatalError("Attribute ID or '}' expected");
+                       return FALSE;
+               }
+               
+               if (token == KW("hidetask"))
+               {
+                       Operation* op;
+                       if ((op = readLogicalExpression()) == 0)
+                               return FALSE;
+                       ExpressionTree* et = new ExpressionTree(op);
+                       report->setHideTask(et);
+               }
+               else if (token == KW("rolluptask"))
+               {
+                       Operation* op;
+                       if ((op = readLogicalExpression()) == 0)
+                               return FALSE;
+                       ExpressionTree* et = new ExpressionTree(op);
+                       report->setRollUpTask(et);
+               }
+               else
+               {
+                       fatalError("Illegal attribute");
+                       return FALSE;
+               }
+       }
+
+       proj->addExportReport(report);
+
+       return TRUE;
+}
+
 Operation*
 ProjectFile::readLogicalExpression(int precedence)
 {
@@ -2002,79 +2359,111 @@ ProjectFile::readLogicalExpression(int precedence)
        QString token;
        TokenType tt;
 
-       qDebug("readLogicalExpression");
-       if ((tt = nextToken(token)) == ID || tt == INTEGER)
+       if ((tt = nextToken(token)) == ID || tt == RELATIVE_ID)
        {
-               if (tt == ID)
+               if (proj->isAllowedFlag(token))
+                       op = new Operation(token);
+               else if (proj->getTask(token))
+                       op = new Operation(Operation::TaskId, token);
+               else if (proj->getResource(token))
+                       op = new Operation(Operation::ResourceId, token);
+               else if (proj->getAccount(token))
+                       op = new Operation(Operation::AccountId, token);
+               else if (ExpressionTree::isFunction(token))
                {
-                       if (!proj->isAllowedFlag(token))
-                       {
-                               fatalError(QString("Flag ") + token + " is unknown.");
-                               qDebug("Done 0");
+                       if ((op = readFunctionCall(token)) == 0)
                                return 0;
-                       }
-                       op = new Operation(token);
-                       qDebug(token);
                }
                else
-                       op = new Operation(token.toLong());
-               if (precedence == 0)
                {
-                       if ((tt = nextToken(token)) != AND && tt != OR)
-                       {
-                               returnToken(tt, token);
-                       }
-                       else if (tt == AND)
-                       {
-                               qDebug("&");
-                               Operation* op2 = readLogicalExpression();
-                               op = new Operation(op, Operation::And, op2);
-                       }
-                       else if (tt == OR)
-                       {
-                               qDebug("|");
-                               Operation* op2 = readLogicalExpression();
-                               op = new Operation(op, Operation::Or, op2);
-                       }
+                       fatalError(QString("Flag or function '") + token + "' is unknown.");
+                       return 0;
                }
        }
+       else if (tt == INTEGER)
+       {
+               op = new Operation(token.toLong());
+       }
        else if (tt == TILDE)
        {
-               qDebug("~");
                if ((op = readLogicalExpression(1)) == 0)
                {
-                       qDebug("Done 0");
                        return 0;
                }
                op = new Operation(op, Operation::Not);
        }
        else if (tt == LBRACE)
        {
-               qDebug("(");
                if ((op = readLogicalExpression()) == 0)
                {
-                       qDebug("Done 0");
                        return 0;
                }
                if ((tt = nextToken(token)) != RBRACE)
                {
                        fatalError("')' expected");
-                       qDebug("Done 0");
                        return 0;
                }
-               qDebug(")");
        }
        else
        {
                fatalError("Logical expression expected");
-               qDebug("Done 0");
                return 0;
        }
        
-       qDebug("Done op");
+       if (precedence < 1)
+       {
+               if ((tt = nextToken(token)) != AND && tt != OR)
+               {
+                       returnToken(tt, token);
+               }
+               else if (tt == AND)
+               {
+                       Operation* op2 = readLogicalExpression();
+                       op = new Operation(op, Operation::And, op2);
+               }
+               else if (tt == OR)
+               {
+                       Operation* op2 = readLogicalExpression();
+                       op = new Operation(op, Operation::Or, op2);
+               }
+       }
+
        return op;
 }
 
+Operation*
+ProjectFile::readFunctionCall(const QString& name)
+{
+       QString token;
+       TokenType tt;
+       
+       if ((tt = nextToken(token)) != LBRACE)
+       {
+               fatalError("'(' expected");
+               return 0;
+       }
+       QPtrList<Operation> args;
+       for (int i = 0; i < ExpressionTree::arguments(name); i++)
+       {
+               Operation* op;
+               if ((op = readLogicalExpression()) == 0)
+                       return 0;
+               args.append(op);
+               if ((i < ExpressionTree::arguments(name) - 1) &&
+                       nextToken(token) != COMMA)
+               {
+                       fatalError("Comma expected");
+                       return 0;
+               }
+       }
+       if ((tt = nextToken(token)) != RBRACE)
+       {
+               fatalError("')' expected");
+               return 0;
+       }
+       return new Operation(name, args);
+}
+
 bool
 ProjectFile::readSorting(Report* report, int which)
 {
@@ -2082,55 +2471,55 @@ ProjectFile::readSorting(Report* report, int which)
 
        nextToken(token);
        CoreAttributesList::SortCriteria sorting;
-       if (token == "tree")
+       if (token == KW("tree"))
                sorting = CoreAttributesList::TreeMode;
-       else if (token == "indexup")
+       else if (token == KW("indexup"))
                sorting = CoreAttributesList::IndexUp;
-       else if (token == "indexdown")
+       else if (token == KW("indexdown"))
                sorting = CoreAttributesList::IndexDown;
-       else if (token == "idup")
+       else if (token == KW("idup"))
                sorting = CoreAttributesList::IdUp;
-       else if (token == "iddown")
+       else if (token == KW("iddown"))
                sorting = CoreAttributesList::IdDown;
-       else if (token == "fullnameup")
+       else if (token == KW("fullnameup"))
                sorting = CoreAttributesList::FullNameUp;
-       else if (token == "fullnamedown")
+       else if (token == KW("fullnamedown"))
                sorting = CoreAttributesList::FullNameDown;
-       else if (token == "nameup")
+       else if (token == KW("nameup"))
                sorting = CoreAttributesList::NameUp;
-       else if (token == "namedown")
+       else if (token == KW("namedown"))
                sorting = CoreAttributesList::NameDown;
-       else if (token == "startup")
+       else if (token == KW("startup"))
                sorting = CoreAttributesList::StartUp;
-       else if (token == "startdown")
+       else if (token == KW("startdown"))
                sorting = CoreAttributesList::StartDown;
-       else if (token == "endup")
+       else if (token == KW("endup"))
                sorting = CoreAttributesList::EndUp;
-       else if (token == "enddown")
+       else if (token == KW("enddown"))
                sorting = CoreAttributesList::EndDown;
-       else if (token == "priorityup")
+       else if (token == KW("priorityup"))
                sorting = CoreAttributesList::PrioUp;
-       else if (token == "prioritydown")
+       else if (token == KW("prioritydown"))
                sorting = CoreAttributesList::PrioDown;
-       else if (token == "responsibleup")
+       else if (token == KW("responsibleup"))
                sorting = CoreAttributesList::ResponsibleUp;
-       else if (token == "responsibledown")
+       else if (token == KW("responsibledown"))
                sorting = CoreAttributesList::ResponsibleDown;
-       else if (token == "mineffortup")
+       else if (token == KW("mineffortup"))
                sorting = CoreAttributesList::MinEffortUp;
-       else if (token == "mineffortdown")
+       else if (token == KW("mineffortdown"))
                sorting = CoreAttributesList::MinEffortDown;
-       else if (token == "maxeffortup")
+       else if (token == KW("maxeffortup"))
                sorting = CoreAttributesList::MaxEffortUp;
-       else if (token == "maxeffortdown")
+       else if (token == KW("maxeffortdown"))
                sorting = CoreAttributesList::MaxEffortDown;
-       else if (token == "rateup")
+       else if (token == KW("rateup"))
                sorting = CoreAttributesList::RateUp;
-       else if (token == "ratedown")
+       else if (token == KW("ratedown"))
                sorting = CoreAttributesList::RateDown;
-       else if (token == "kotrusidup")
+       else if (token == KW("kotrusidup"))
                sorting = CoreAttributesList::KotrusIdUp;
-       else if (token == "kotrusiddown")
+       else if (token == KW("kotrusiddown"))
                sorting = CoreAttributesList::KotrusIdDown;
        else
        {
@@ -2161,14 +2550,25 @@ time_t
 ProjectFile::date2time(const QString& date)
 {
        int y, m, d, hour, min;
-       if (date.find(':') == -1)
-       {
-               sscanf(date, "%d-%d-%d", &y, &m, &d);
+       char tZone[16] = "";
+       if (sscanf(date, "%d-%d-%d-%d:%d-%s", &y, &m, &d, &hour, &min, tZone) == 6)
+               ;
+       else if (sscanf(date, "%d-%d-%d-%d:%d", &y, &m, &d, &hour, &min) == 5)
+               tZone[0] = '\0';
+       else if (sscanf(date, "%d-%d-%d", &y, &m, &d) == 3)
+       {                       
+               tZone[0] = '\0';
                hour = min = 0;
        }
-       else
-               sscanf(date, "%d-%d-%d-%d:%d", &y, &m, &d, &hour, &min);
 
+       char savedTZ[16] = "";
+       if (strcmp(tZone, "") != 0)
+       {
+               if (getenv("TZ"))
+                       strcpy(getenv("TZ"), savedTZ);
+               setenv("TZ", tZone, 1);
+       }
+       
        if (y < 1970)
        {
                fatalError("Year must be larger than 1969");
@@ -2188,6 +2588,11 @@ ProjectFile::date2time(const QString& date)
        struct tm t = { 0, min, hour, d, m - 1, y - 1900, 0, 0, -1, 0, 0 };
        time_t localTime = mktime(&t);
 
+       if (strcmp(savedTZ, "") != 0) 
+               setenv("TZ", savedTZ, 1);
+       else
+               unsetenv("TZ");
+
        return localTime;
 }