OSDN Git Service

* Support for later completion of task and resources added. By
authorcs <cs@e1914e07-63f8-0310-9059-d6d858d7cdca>
Sun, 12 May 2002 09:15:49 +0000 (09:15 +0000)
committercs <cs@e1914e07-63f8-0310-9059-d6d858d7cdca>
Sun, 12 May 2002 09:15:49 +0000 (09:15 +0000)
writing 'supplement task <ID> { ... }' an already defined task
can be extended. So it's easier now to create a file which contains
the vacations for all resources seperate from the resource definition
itself.

* Extended expression parser to work on string type values as
well.

* Logical expressions for hidetask, rolluptask etc. can now
contain functions as well. Currently there is support for 'istask',
'issubtaskof', 'contains', 'ismilestone'.

* Moved the docs directory from taskjugger subdir to topdir.

* Added feature list and changelog to the documentation.

* Property reference is now sorted in alphabetical order.

* Added missing 'export' report to documentation.

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

34 files changed:
ChangeLog
Contrib/vim/tjsp.vim
Examples/AccountingSoftware/AcSo.tjp
Examples/AccountingSoftware/tj [new file with mode: 0755]
Makefile.am
TestSuite/README [new file with mode: 0644]
TestSuite/Scheduler/Correct/Vacation.tjp
TestSuite/Syntax/Correct/Expression.sh [new file with mode: 0755]
TestSuite/Syntax/Correct/Expression.tjp [new file with mode: 0644]
TestSuite/Syntax/Errors/Vacation1.tjp [new file with mode: 0644]
TestSuite/Syntax/Errors/Vacation2.tjp [new file with mode: 0644]
TestSuite/Syntax/Errors/Vacation3.tjp [new file with mode: 0644]
TestSuite/testdir
docs/.cvsignore [new file with mode: 0644]
docs/Makefile.am [new file with mode: 0644]
docs/en/.cvsignore [new file with mode: 0644]
docs/en/Makefile.am [new file with mode: 0644]
docs/en/README [new file with mode: 0644]
docs/en/index.sgml.in [new file with mode: 0644]
taskjuggler.lsm
taskjuggler/Account.h
taskjuggler/CoreAttributes.h
taskjuggler/ExpressionTree.cpp
taskjuggler/ExpressionTree.h
taskjuggler/Makefile.am
taskjuggler/Project.cpp
taskjuggler/Project.h
taskjuggler/ProjectFile.cpp
taskjuggler/ProjectFile.h
taskjuggler/Report.cpp
taskjuggler/ResourceList.h
taskjuggler/ShiftList.h
taskjuggler/Task.cpp
taskjuggler/Task.h

index 09d8393..81d218c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,3 @@
-Version 1.0.0 (2002-03-14)
-==========================
-- Initial stable public release
-
-Version 1.0.1 (2002-03-15)
-==========================
-- Fixed completely broken global vacation handling
-- Added test case for vacation handling to test suite
+The changelog has been moved to the SGML documentation. See
+docs/en/index.sgml.in for the current changelog.
 
index 25addbb..7d70d5e 100644 (file)
@@ -137,6 +137,7 @@ syn keyword tjspkeyword start
 syn keyword tjspkeyword startcredit
 syn keyword tjspkeyword startdown
 syn keyword tjspkeyword startup
+syn keyword tjspkeyword supplement
 syn keyword tjspkeyword timingresolution
 syn keyword tjspkeyword tree
 syn keyword tjspkeyword vacation
index 28fccf6..916c08f 100644 (file)
@@ -110,10 +110,30 @@ task AcSo "Accounting Software" {
 
     task done "Ship Product to customer" {
       milestone
-      maxend 2002-04-17
+# Uncomment this to trigger a warning that the project is late.
+#      maxend 2002-04-17
       depends !!test.beta, !!manual
       startcredit 20000.0
     }
   }
 }
 
+htmltaskreport "AcSo-Tasks.html" {
+  columns no, name, start, end, daily
+       headline "Accounting Software Project"
+       caption "This table shows the load of each day for all the tasks.
+       Additionally the resources used for each task are listed."
+  hideresource 0
+  showactual
+}
+
+htmlresourcereport "AcSo-Resources.html" {
+  columns no, name, weekly
+}
+
+htmlaccountreport "AcSo-Accounting.html" {
+  columns no, name, total, monthly
+  accumulate
+  showactual
+}
+
diff --git a/Examples/AccountingSoftware/tj b/Examples/AccountingSoftware/tj
new file mode 100755 (executable)
index 0000000..8f4d715
--- /dev/null
@@ -0,0 +1,4 @@
+#! /bin/sh
+
+taskjuggler --debug 1 AcSo.tjp
+
index 1a8cfd3..41066b3 100644 (file)
@@ -1,6 +1,6 @@
 ####### kdevelop will overwrite this part!!! (begin)##########
 
-SUBDIRS = taskjuggler 
+SUBDIRS = taskjuggler docs
 
 EXTRA_DIST = taskjuggler.kdevprj admin AUTHORS COPYING ChangeLog INSTALL README TODO taskjuggler.lsm 
 
diff --git a/TestSuite/README b/TestSuite/README
new file mode 100644 (file)
index 0000000..d815445
--- /dev/null
@@ -0,0 +1,11 @@
+This is what may become a real testsuite. There are 2 classes of
+tests; Syntactical tests and scheduler tests. For each class there are
+tests that must pass and tests that must fail. All *.tjp files that
+are found in the respective directories are executed by the test
+suite. You can run the test suite by executing ./runtests in the
+TestSuite directory.
+
+If you want to help the taskjuggler development you can help to
+complete the test suite. Ideally each syntax struct should have a pass
+and at least one fail test.
+
index a23e09f..a3f5b8b 100644 (file)
@@ -12,10 +12,13 @@ resource team "Team" {
        }
 
        resource r2 "Resource2" {
-               vacation 2000-01-18
        }
 }
 
+supplement resource r2 {
+       vacation 2000-01-18
+}
+
 resource r3 "Resource3" {
 }
 
diff --git a/TestSuite/Syntax/Correct/Expression.sh b/TestSuite/Syntax/Correct/Expression.sh
new file mode 100755 (executable)
index 0000000..f203e49
--- /dev/null
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+cmp Expression_containstask.html Expression_containstask_ref.html
+if test $? -ne 0 ; then
+  exit 1
+fi
+
+cmp Expression_issubtaskof.html Expression_issubtaskof_ref.html
+if test $? -ne 0 ; then
+  exit 1
+fi
+
+cmp Expression_istask.html Expression_istask_ref.html
+if test $? -ne 0 ; then
+  exit 1
+fi
+
+cmp Expression_ismilestone.html Expression_ismilestone_ref.html
+if test $? -ne 0 ; then
+  exit 1
+fi
+
+/bin/rm Expression_*.html
+
+exit 0
+
diff --git a/TestSuite/Syntax/Correct/Expression.tjp b/TestSuite/Syntax/Correct/Expression.tjp
new file mode 100644 (file)
index 0000000..5f0c102
--- /dev/null
@@ -0,0 +1,61 @@
+project test "Test Project" "$Id" 2000-01-01 2000-01-04
+
+resource tux "Tux"
+
+flags flag1, flag2, flag3, flag4
+
+task t1 "FooTask1" {
+       task t1_1 "FooTask1_1" {
+               flags flag2
+               start 2000-01-01
+               length 1d
+       }
+       flags flag3
+}
+
+task t2 "FooTask2" {
+       flags flag1
+  start 2000-01-01
+  duration 1d
+}
+
+task t3 "FooTask3" {
+       flags flag4
+       milestone
+  start 2000-01-01
+}
+
+htmltaskreport "Expression_istask.html" {
+       hidetask istask(t2)
+}
+
+htmltaskreport "Expression_istask_ref.html" {
+       hidetask flag1
+}
+
+htmltaskreport "Expression_issubtaskof.html" {
+       hidetask issubtaskof(t1)
+}
+
+htmltaskreport "Expression_issubtaskof_ref.html" {
+       hidetask flag2
+}
+
+htmltaskreport "Expression_containstask.html" {
+       hidetask containstask(t1.t1_1)
+       sorttasks indexdown
+}
+
+htmltaskreport "Expression_containstask_ref.html" {
+       hidetask flag3
+       sorttasks indexdown
+}
+
+htmltaskreport "Expression_ismilestone.html" {
+       hidetask ismilestone()
+}
+
+htmltaskreport "Expression_ismilestone_ref.html" {
+       hidetask flag4
+}
+
diff --git a/TestSuite/Syntax/Errors/Vacation1.tjp b/TestSuite/Syntax/Errors/Vacation1.tjp
new file mode 100644 (file)
index 0000000..da7047a
--- /dev/null
@@ -0,0 +1,5 @@
+project test "Test" "$Id" 2000-01-01 2000-01-31
+
+# Date missing
+vacation "Monday off"
+
diff --git a/TestSuite/Syntax/Errors/Vacation2.tjp b/TestSuite/Syntax/Errors/Vacation2.tjp
new file mode 100644 (file)
index 0000000..e4266aa
--- /dev/null
@@ -0,0 +1,7 @@
+project test "Test" "$Id" 2000-01-01 2000-01-31
+
+resource team "Team" {
+       vacation 2000-01-21 2000-01-25
+}
+
+
diff --git a/TestSuite/Syntax/Errors/Vacation3.tjp b/TestSuite/Syntax/Errors/Vacation3.tjp
new file mode 100644 (file)
index 0000000..1262a4c
--- /dev/null
@@ -0,0 +1,6 @@
+project test "Test" "$Id" 2000-01-01 2000-01-31
+
+# Resource r2 does not exist
+vacation r2 2000-01-18
+
+
index 291d094..6477733 100755 (executable)
@@ -2,26 +2,36 @@
 
 set errors=0
 
-rm -f log
-touch log
-
-for f in Correct/*.tjp ; do
+function do_testing
+{
+  f=$1
+  op=$2
   echo "Running test $f" >> log
   ../../taskjuggler/taskjuggler $f 2>> log
-  if [ $? -ne 0 ]; then
+  if [ $? $op 0 ]; then
     errors=$(( $errors + 1 ))
     echo "Test $f failed!"
   fi
+  checkscript=`echo $f | sed s/\\\\\(.*\\\\\).tjp/\\\1.sh/g`
+  if [ -x $checkscript ] ; then
+    sh $checkscript
+    if [ $? -ne 0 ] ; then
+      errors=$(( $errors + 1 ))
+      echo "Text $f failed (check script)!"
+    fi
+  fi
+}
+
+rm -f log
+touch log
+
+for f in Correct/*.tjp ; do
+  do_testing $f -ne
 done
-  
 for f in Errors/*.tjp ; do
-  echo "Running test $f" >> log
-  ../../taskjuggler/taskjuggler $f 2>> log
-  if [ $? -eq 0 ]; then
-    errors=$(( $errors + 1 ))
-    echo "Test $f failed!"
-  fi
+  do_testing $f -eq
 done
-
 exit $errors
 
diff --git a/docs/.cvsignore b/docs/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644 (file)
index 0000000..550ae51
--- /dev/null
@@ -0,0 +1,5 @@
+####### kdevelop will overwrite this part!!! (begin)##########
+
+SUBDIRS = en 
+
+####### kdevelop will overwrite this part!!! (end)############
diff --git a/docs/en/.cvsignore b/docs/en/.cvsignore
new file mode 100644 (file)
index 0000000..c081b38
--- /dev/null
@@ -0,0 +1,4 @@
+Makefile
+Makefile.in
+*.html
+index.sgml
diff --git a/docs/en/Makefile.am b/docs/en/Makefile.am
new file mode 100644 (file)
index 0000000..116fa92
--- /dev/null
@@ -0,0 +1,19 @@
+EXTRA_DIST = index.html index-1.html index-2.html index-3.html index-4.html index-5.html index-6.html index-7.html index-8.html index-9.html index-10.html index-11.html
+
+docprefix = $(prefix)/share/doc/packages
+
+install-data-local:
+       $(mkinstalldirs) $(docprefix)/taskjuggler/
+       $(INSTALL_DATA) $(srcdir)/index.sgml $(docprefix)/taskjuggler/index.sgml
+       $(INSTALL_DATA) $(srcdir)/index.html $(docprefix)/taskjuggler/index.html
+       $(INSTALL_DATA) $(srcdir)/index-*.html $(docprefix)/taskjuggler/
+
+uninstall-local:
+       -rm -f $(docprefix)/taskjuggler/index*
+
+index.sgml: ../../config.h index.sgml.in
+       sed 's,TJVER,@VERSION@,' index.sgml.in > index.sgml
+       sgml2html index.sgml
+
+all: index.sgml
+
diff --git a/docs/en/README b/docs/en/README
new file mode 100644 (file)
index 0000000..d6292ac
--- /dev/null
@@ -0,0 +1,15 @@
+Documentation
+
+
+The documentation can be generated from a sgml source.  Type make to
+create html documentation. Calling make in this directory also patches
+the source index.sgml.in to index.sgml.
+
+Enter sgml2latex index.sgml to get latex documents. 
+smgl2* can generate other documentation formats.
+
+- IMPORTANT -
+  Always edit index.sgml.in, not index.sgml !
+
+
+Klaas Freitag <freitag@suse.de>
diff --git a/docs/en/index.sgml.in b/docs/en/index.sgml.in
new file mode 100644 (file)
index 0000000..4885c5e
--- /dev/null
@@ -0,0 +1,1430 @@
+<!doctype linuxdoc system>
+<article>
+<title>The TaskJuggler Manual
+<author>Chris Schlaeger <tt>cs@suse.de</tt>,
+Marc R&uuml;hrschneck <tt>mac@suse.de</tt>
+<date>Version TJVER, Thu Feb 14 14:33:25 CET 2002
+<abstract>
+This document describes TaskJuggler version TJVER
+
+</abstract>
+
+<toc>
+
+<sect>Introduction
+<p>
+<sect1>About TaskJuggler
+<p>
+
+TaskJuggler is a project management tool. It helps to organize and plan
+projects. It schedules the whole project and tries to optimize
+the resources needed for the project.
+
+The output can be a report showing the several tasks, the resource usage,
+or the account information. Multiple reports can be created as html files, 
+enabling easy display with a web browser. 
+
+<p>
+<sect1>Features and Highlights
+<p>
+
+<itemize>
+<item>Automatic scheduling of interdependent tasks with resource
+conflict solver.
+<item>Powerful project description syntax with macro support.
+<item>Flexible working hours and vacation handling.
+<item>Support for shifts.
+<item>Timezone support.
+<item>Flexibel resource grouping.
+<item>Project accounting support.
+<item>Task may have initial costs, finishing costs.
+<item>Resource may have running costs.
+<item>Support for simple profit/loss analysis.
+<item>HTML and XML report generation.
+<item>Support for plan and actual scenario comparisons.
+<item>Project tracking support.
+<item>Groupware support by using a revision control system such as CVS
+or RCS on the project description files.
+<item>Support for central resource allocation database.
+</itemize>
+
+<p>
+<sect1>TaskJuggler on the Web
+<p>
+The official TaskJuggler web page can be found at <url
+url="http://www.suse.de/~freitag/taskjuggler"
+name="http://www.suse.de/~freitag/taskjuggler">.
+
+<sect1>Changes
+<p>
+
+<sect2>Version 1.0.0 (2002-03-14)
+<p>
+<itemize>
+
+<item>Initial stable public release
+
+</itemize>
+<p>
+<sect2>Version 1.0.1 (2002-03-15)
+<p>
+<itemize>
+
+<item>Fixed completely broken global vacation handling
+
+<item>Added test case for vacation handling to test suite
+
+</itemize>
+<p>
+
+<sect2>Version 1.1
+<p>
+<itemize>
+
+<item> Added some reports to the example file, so users actually get a
+result of the taskjuggler run. 
+
+<item> Support for later completion of task and resources added. By
+writing 'supplement task &lt;ID&gt; { ... }' an already defined task
+can be extended. So it's easier now to create a file which contains
+the vacations for all resources seperate from the resource definition
+itself.
+
+<item>Extended expression parser to work on string type values as well.
+
+<item>Logical expressions for hidetask, rolluptask etc. can now
+contain functions as well. Currently there is support for 'istask',
+'issubtaskof', 'contains', 'ismilestone'.
+
+<item>Moved the docs directory from taskjugger subdir to topdir.
+
+<item>Added feature list and changelog to the documentation.
+
+<item>Property reference is now sorted in alphabetical order.
+
+<item>Added missing 'export' report to documentation.
+
+</itemize>
+<p>
+
+<sect>Installation
+<p>
+<sect1>Obtaining TaskJuggler 
+<p>
+
+TaskJuggler may be obtained from the following web site:
+
+<htmlurl url="http://www.suse.de/~cs/taskjuggler"
+name="http://www.suse.de/~cs/taskjuggler/">
+
+<sect1>Requirements
+<p>
+
+To build and run TaskJuggler, you need:
+
+<itemize>
+<item>qt3 &mdash; The qt c++ class library version 3
+<item> gcc 2.95 &mdash; The GNU C compiler version 2.95. The c++
+extensions must be available
+</itemize>
+
+This version of TaskJuggler was built and tested on SuSE Linux 7.3/x86
+
+<sect1>Compilation and Installation
+<p>
+
+To compile and install TaskJuggler on your system, type the following 
+in the base directory of the TaskJuggler distribution:
+
+<tscreen><verb>
+% ./configure
+% make
+% make install
+</verb></tscreen>
+
+<p>
+Since TaskJuggler uses <tt/autoconf/, you should have no trouble
+compiling it.
+If you have problems, please report them to the TaskJuggler developers
+mailing list at <htmlurl url="mailto:taskjuggler-devel@suse.de"
+name="taskjuggler-devel@suse.de"> in English.
+
+
+<p>
+<sect> Usage <p>
+<sect1> Basics
+<p>
+
+TaskJuggler uses one or more ASCII files to describe a project. The main
+project should be placed in a file with the <tt>.tjp</tt> extension. This
+main project may contain several subprojects. Such subprojects should be
+placed in files with the <tt>.tjsp</tt> extension. These subprojects are
+included in the main project during compile time.
+
+<sect1> General Usage
+<p>
+
+TaskJuggler works like a compiler. You provide the source files, it computes
+the contents and creates the output files.
+
+<p>
+After you created the project description file, have TaskJuggler 
+compute and create the output. For example, if you have created the
+<tt>AcSo.tjp</tt> project file. You need to send this file to TaskJuggler then:
+
+<tscreen><verb>
+% taskjuggler AcSo.tjp
+</verb></tscreen>
+
+TaskJuggler will try to schedule all tasks with the specified
+conditions and generate the reports that were requested with the <ref
+id="htmltaskreport" name="htmltaskreport">, <ref
+id="htmlresourcereport" name="htmlresourcereport"> or other report
+attributes.
+
+<sect1> The Command Line Options
+<p>
+
+To get a list of the command line options of TaskJuggler, use the <tt>--help</tt>
+option:
+
+<tscreen><verb>
+% taskjuggler --help
+</verb></tscreen>
+
+<sect>An Example
+<p>
+
+The easiest way to give an overview of the functionality of TaskJuggler is
+with an example.
+
+<sect1> Introducing the Example: Accounting Software
+<p>
+
+Refer to section <ref id="example" name="The Example: Accounting
+Software"> for a printout of the example.
+
+In this project, we plan to create an accounting program. The project
+starts on January 16, 2002, and its end is planned for June 30, 2002. The
+project will consist of the following tasks:
+
+<descrip>
+<tag/Specification/The developers set up the specification for the
+software and documentation.
+<tag/Software development/This is the whole process of coding the software. It
+includes the following subtasks:
+  <descrip>
+  <tag/Database coupling/Connection procedures to the database.
+  <tag/Graphical user interface/Creating the user interface.
+  <tag/Back-end functions/Creating the calucation and computing routines for the
+  data.
+  </descrip>
+
+<tag/Software testing/Testing the software. There are two stages of software
+testing:
+  <descrip>
+  <tag/Alpha test/Test the software in alpha stage.
+  <tag/Beta test/Test the software in beta stage. The customer normally takes
+  part in this beta test phase.
+  </descrip>
+
+<tag/Manual/Creating the printed user manual
+
+<tag/Ship to customer/This task includes all steps necessary to communicate
+to the customer. This is an important task, as it defines the basic milestones
+of the project. For example, we cannot start the project before the contract
+is signed. It is also important to check the planned date of shipping the
+software to the customer.
+
+This process consist of the following subtasks:
+  <descrip>
+  <tag/Projectstart/This milestone defines the start of the project.
+  <tag/Betaversion/This marks the start of the beta test. Normally, the
+  customer wants to see a beta version, so this is also a milestone.
+  <tag/Ship product to customer/This is the date when the project has ended.
+  Software is in final stage, the manual is ready and printed, and everything is
+  shipped to the customer.
+  </descrip>
+</descrip>
+
+<sect> The Basic Parts of a <tt>.tjp</tt> File
+<p>
+
+This section gives an overview of the most important commands, properties,
+and attributes used in a typical project file. Refer to <ref
+id="reference" name="Property Reference"> for a complete list of commands and
+properties usable in project files.
+
+<descrip>
+<tag>project fibu "Accounting Software" "1.0" 2002-01-16 2002-06-30</tag>
+
+This statement informs TaskJuggler about the most important things on the
+project. These things include:
+
+<descrip>
+<tag/fibu/The project ID, unique within the scope of the project
+<tag/Accounting Software/The short description of the project
+<tag/1.0/The version of the schedule
+<tag/2002-01-16 2002-6-30/Begin and end dates of the project
+</descrip>
+
+Refer to the <ref id="project" name="project"> command in the reference
+for details.
+
+<tag>resource dev "Developers" { ... }</tag>
+
+This defines a resource with the unique ID <tt/dev/. It will be shown as
+<tt/Developers/ on the schedule later.
+
+<descrip>
+<tag/dev/The resource ID, unique for TaskJuggler
+<tag/Developers/The real name of the resource
+</descrip>
+
+In the example, the resource consists of the three developers (<tt/dev1/,
+<tt/dev2/, and <tt/dev3/). For every resource, you can specify additional
+attributes in separate curly braces {}.
+
+Refer to the <ref id="resource" name="resource"> command in the
+reference for details.
+
+<tag>task AcSo "Accounting Software" { ... }</tag>
+
+This defines the task <tt/AcSo/. In this example, it represents the whole
+project to build the Accounting Software. A task may contain several subtasks.
+
+Refer to the <ref id="task" name="task"> command in the reference.
+
+<tag>htmltaskreport "tasks.html" name,start,end,resources,weekly</tag>
+
+This command creates a task-based report in html and saves it as
+<tt/tasks.html/ to the current directory. The report will include the task
+name, start and end of the task, and the necessary resources. The report's 
+resolution will be in weeks.
+
+Refer to the <ref id="htmltaskreport" name="htmltaskreport"> command in
+the reference for details.
+</descrip>
+
+<sect> Other Useful Commands and Environments
+<p>
+
+<descrip> 
+<tag> <tt/now 2002-02-17/</tag>
+
+This sets the current date to 2002-02-17. This is the day or week that will be
+higlighted in the report later. This helps with printing and creating reports for
+the future.
+
+<tag> <tt/rate 310.0/</tag>
+
+<tag> <tt/currency "EUR"/</tag>
+
+Sets the global monetary currency to Euro. It is used for printing out cost and
+revenue values in the correct currency.
+
+<tag> <tt/account dev "Development" cost {}/</tag>
+
+This creates an account <tt/dev/ as a <tt/cost/ account. There is also a
+account type <tt/revenue/, which is used to cover all kinds of income (see
+reference: <ref id="account" name="account">).
+</descrip>
+
+<sect>Property Reference<p><label id="reference">
+
+<bf>Comments</bf><p><label id="comments">
+There are two ways to annotate a project file with comments. All text
+after a '#' will be ignored. Comments that span multiple rows must be
+started with '/*' and ended with '*/'.
+
+<descrip>
+<label id="id"><tag/ID/A string that may consist of the characters A-Z, a-z, 0-9, and _.
+It may not start with a number.
+
+<label id="global_id"><tag/GLOBAL_ID/A GLOBAL_ID may have the same characters as ID, but
+additionally may contain '.' and '!'. '!' may only be used at the
+beginning and is used in relative IDs. A '!' means one level up.
+
+<label id="string"><tag/STRING/A string may contain any characters and is enclosed in '"'. A
+string may include line breaks.
+
+<label id="date"><tag/DATE/A DATE is an ISO-compliant date in the
+format YYYY-MM-DD[-hh:mm]. Hour, minute,
+and second are optional. If not specified, the values are set to 0.
+
+<label id="time"><tag/TIME/A time in the format HH:MM.
+
+<label id="unit"><tag/UNIT/May be h for hours, d for days, w for weeks, m for months, y for
+years.
+
+<label id="weekday"><tag/WEEKDAY/May be
+<descrip>
+<tag/mon/ for Monday
+<tag/tue/ for Tuesday
+<tag/wed/ for Wednesday
+<tag/thu/ for Thursday
+<tag/fri/ for Friday
+<tag/sat/ for Saturday
+<tag/sun/ for Sunday
+</descrip>
+
+<label id="integer"><tag/INTEGER/A number that is an integer.
+
+<label id="real"><tag/REAL/A real number (e.g., 3.14).
+
+<label id="logicalexpression"><tag/LOGICALEXPRESSION/This is a logical expression consisting of logical
+operations, such as '&' for and, '|' for or, and '&tilde;' for not, to
+operate on INTEGER values
+or symbols. As symbols flag names and certain functions are supported. The
+expression is evaluated from left to right. '&tilde;' has a higher
+precedence than other operators. Use braces to avoid ambiguous
+operations. If flagFoo, flagFooBar, and flagBar are declared flags, the
+following example is a correct expression:
+
+(flagFoo | flagFooBar) & &tilde;flagBar
+
+The following functions can be used in logical expressions:
+
+<descrip>
+<tag/containstask(<ref id="id" name="ID">)/ true if the task has task ID as sub task.
+<tag/ismilestone()/ true if the task is a milestone.
+<tag/issubtask(<ref id="id" name="ID">)/ true if the task is a sub task of task ID.
+<tag/istask(<ref id="id" name="ID">)/ true if the tasks has the listed ID.
+</descrip>
+
+<label id="sortingcriteria"><tag/SORTINGCRITERIA/See attribute description for allowed values.
+</descrip>
+
+Optional attributes of a property must be enclosed by {}.
+
+
+<sect1>account &lt;id&gt; &lt;name&gt; &lt;type&gt;<label id="account">
+<p>
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+type: <ref id="id" name="ID">
+
+Optional attributes:
+
+<descrip>
+<tag/account &lt;id&gt; &lt;name&gt;/
+Accounts may be nested. An account that has subaccounts may not have
+a balance or a kotrusid.
+
+<tag/credit &lt;date&gt; &lt;description&gt; &lt;amount&gt;/
+date: <ref id="date" name="DATE">
+
+description <ref id="string" name="STRING">
+
+amount: <ref id="real" name="REAL">
+
+Credits the specified amount to the account at the specified date. The
+description should contain some information about the reason for the
+transaction.
+
+<tag/kotrusid &lt;id&gt;/
+id: <ref id="string" name="STRING">
+
+The KoTrus <ref id="id" name="ID"> of the account (Kostentraeger).
+This is a special reserved keyword.  
+</descrip>
+
+Declares an account. Accounts can be used to calculate costs of tasks
+or the whole project. Account declaration may be nested, but only the
+top level accounts may have a type attribute specified. All
+subaccounts inherit this type. The type may be 'Cost' or 'Revenue'.
+
+
+<sect1>currency &lt;text&gt;<label id="currency">
+<p>
+text: <ref id="string" name="STRING">
+
+The currency for money values in reports.
+
+
+<sect1>currencydigits &lt;number&gt;<label id="currencydigits">
+<p>
+number: <ref id="integer" name="INTEGER">
+
+The number of decimal places.
+
+
+<sect1>export &lt;filename&gt;<label id="export">
+<p>
+filename: <ref id="string" name="STRING">
+<p>
+Optional attributes:
+
+<descrip>
+<tag/hidetask &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+List only tasks that do not have flags meeting the described logical
+expression.
+
+<tag/rolluptask &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+Do not show subtasks of tasks with flags meeting the described
+logical expression.
+
+</descrip>
+
+The export report looks like a regular taskjuggler file but contains
+fixed start and end dates for all tasks. The tasks only have start and
+end times and their flags. No other attributes are exported.
+
+The export report can be used to share certain tasks or milestones
+with other projects.
+
+
+<sect1>flags &lt;id&gt;&lsqb;,&lt;id&gt;&rsqb;<label id="flags">
+<p>
+id: <ref id="id" name="ID">
+
+Declares the specified flags. Flags can be assigned to tasks,
+resources, or accounts to be used as filters during report
+generation. It is legal to declare a flag more than once.
+
+
+<sect1>htmlaccountreport &lt;filename&gt;<label id="htmlaccountreport">
+<p>
+
+filename: <ref id="string" name="STRING">
+
+Optional attributes:
+
+<descrip>
+<tag/columns &lt;colid&gt;&lsqb;,&lt;colid&gt;&rsqb;/
+colid: <ref id="id" name="ID">
+
+Specifies which columns should be included in the task report. The
+following values for colid are available:
+
+<descrip>
+<tag/no/The task index
+
+<tag/id/The global <ref id="id" name="ID"> of a task
+
+<tag/name/The name of a task, resource, or account
+
+<tag/total/Total accumulated values
+
+<tag/daily/A day-by-day calendar view of the accounts
+
+<tag/weekly/A week-by-week calendar view of the accounts
+
+<tag/monthly/A month-by-month calendar view of the accounts
+
+<tag/quaterly/A quarter-by-quarter calender view of the accounts
+</descrip>
+
+<tag/start &lt;day&gt;/
+day: <ref id="date" name="DATE">
+
+The start date for the calender view.
+
+<tag/end &lt;day&gt;/
+day: <ref id="date" name="DATE">
+
+The end date for the calender view.
+
+<tag/show &lt;flag&gt;&lsqb;,flag&rsqb;/
+flag: <ref id="id" name="ID">
+
+List only accounts with the listed flags. This attribute
+conflicts with 'hide'.
+
+<tag/hide &lt;flag&gt;&lsqb;,flag&rsqb;/
+flag: <ref id="id" name="ID">
+
+List only accounts that do not have the listed flags. This attribute
+conflicts with 'show'.
+</descrip>
+
+
+<sect1>htmlresourcereport &lt;filename&gt;<label id="htmlresourcereport">
+<p>
+
+filename: <ref id="string" name="STRING">
+
+Optional attributes:
+
+See <ref id="htmltaskreport" name="htmltaskresport">
+
+
+<sect1>htmltaskreport &lt;filename&gt;<label id="htmltaskreport">
+<p>
+
+filename: <ref id="string" name="STRING">
+
+Optional attributes:
+
+<descrip>
+<tag/columns &lt;colid&gt;&lsqb,&lt;colid&gt;&rsqb/
+colid: <ref id="id" name="ID">
+
+Specifies which columns should be included in the task report. The
+following values for colid are available:
+
+<descrip>
+<tag/no/The task index
+<tag/id/The global <ref id="id" name="ID"> of a task
+<tag/name/The name of a task, resource, or account
+<tag/start/The start date of a task
+<tag/end/The end date of a task
+<tag/minstart/The earliest desired start date
+<tag/maxstart/The latest desired start date
+<tag/minend/The earliest desired end date
+<tag/maxend/The latest desired end date
+<tag/priority/The scheduling priority
+<tag/resources/The names of the used resources
+<tag/depends/The task index of the tasks on which this task depends
+<tag/follows/The task index of the tasks that depend on this task
+<tag/responsible/The name of the resource responsible for a task
+<tag/responsibilies/A list of all tasks indicies for which a resource is responsible 
+<tag/note/The description of the task
+<tag/daily/A day-by-day calendar view of the tasks
+<tag/weekly/A week-by-week calendar view of the tasks
+<tag/monthly/A month-by-month calendar view of the tasks
+</descrip>
+
+<tag/start &lt;day&gt;/
+day: <ref id="date" name="DATE">
+
+The start date for the calender view.
+
+<tag/end &lt;day&gt;/
+day: <ref id="date" name="DATE">
+
+The end date for the calender view.
+
+<tag/headline &lt;text&gt;/
+text: <ref id="string" name="STRING">
+
+Defines the headline used for the report. The headline is printed on
+top of the page and with a larger font.
+
+<tag/caption &lt;text&gt;/
+text: <ref id="string" name="STRING">
+
+Defines the caption used for the report. The caption is printed right
+above the task list.
+
+<tag/sorttasks &lt;criteria&gt;/
+
+criteria: <ref id="sortingcriteria" name="SORTINGCRITERIA">
+
+The sorting criteria specifies how the tasks in the generated report
+will be sorted. Possible values are:
+
+<descrip>
+<tag/tasktree/This is the default and creates a list with subtasks
+indented and grouped together. If this sorting is used, parent tasks
+are shown when subtasks are not hidden, even if the parent task
+matches the hide expression.
+
+<tag/tree/Show nesting with indentation
+
+<tag/indexup/Last index on top
+
+<tag/indexdown/First index on top
+
+<tag/idup/Last <ref id="id" name="ID"> on top
+
+<tag/iddown/First <ref id="id" name="ID"> on top
+
+<tag/fullnameup/Last full name on top
+
+<tag/fullnamedown/First full name on top
+
+<tag/nameup/Last name on top
+
+<tag/namedown/First name on top
+
+<tag/startup/Latest start date on top
+
+<tag/startdown/Earliest start date on top
+
+<tag/endup/Latest end date on top
+
+<tag/enddown/Earliest end date on top
+
+<tag/priorityup/Lowest priority on top
+
+<tag/prioritydown/Highest priority on top
+
+<tag/responsibleup/Last name of responsible on top
+
+<tag/responsibledown/First name of responsible on top
+
+<tag/mineffortup/Smallest minimal effort on top
+
+<tag/mineffortdown/Largest minimal effort on top
+
+<tag/maxeffortup/Smallest maximum effort on top
+
+<tag/maxeffortdown/Largest maximum effort on top
+
+<tag/rateup/Smallest rate on top
+
+<tag/ratedown/Largest rate on top
+
+<tag/kotrusidup/Last kotrusid on top
+
+<tag/kotrusiddown/First kotrusid on top
+</descrip>
+
+<tag/showActual/
+If used, not only the plan values are listed in the table, but also the
+actual values. The actual values are put underneath the plan values.
+
+<tag/hidetask &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+List only tasks that do not have flags meeting the described logical
+expression.
+
+<tag/rolluptask &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+Do not show subtasks of tasks with flags meeting the described
+logical expression.
+
+<tag/hideresource &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+List only resources that do not have flags meeting the described logical
+expression.
+
+<tag/rollupresource &lt;expression&gt;/
+expression: <ref id="logicalexpression" name="LOGICALEXPRESSION">
+
+Do not show subresources of resources with flags meeting the
+described logical expression.
+
+Generates a report of all tasks (excluding hidden and filtered) in
+HTML format. Multiple declarations of htmltaskreport can be made to
+generate several different reports with one run of TaskJuggler.
+</descrip>
+
+
+<sect1>icalreport &lt;filename&gt;<label id="icalreport">
+<p>
+
+filename: <ref id="string" name="STRING">
+
+create an ical calender format output file which can be imported
+to korganiser.
+
+
+<sect1>include &lt;filename&gt;<label id="include">
+<p>
+filename: <ref id="string" name="STRING">
+
+Includes the specified file name as if its contents would be written
+instead of the include property. include commands can be used within
+global scope or between property declarations of tasks, resources, and
+accounts.
+
+
+<sect1>kotrusMode &lt;mode&gt;<label id="kotrusMode">
+<p>
+
+mode: <ref id="string" name="STRING">
+
+sets the kotrus mode. Valid values are
+<itemize>
+<item>'NoKotrus' for no KoTrus connection
+<item>'XML' to read from an XML file (not yet supported)
+<item>'DB' to read from database configured in your .taskjugglerrc
+</itemize>
+
+
+<sect1>macro &lt;id&gt; &lsqb; body &rsqb;<label id="macro">
+<p>
+id: <ref id="id" name="ID">
+
+The body is not optional. It must be enclosed in [ ]. Macros can be
+declared like this:
+
+<descrip>
+<tag/macro foo &lsqb; This text &rsqb;/
+
+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.
+
+<tag/macro foo &lsqb; This ${1} text &rsqb;/
+
+will expand to ' This stupid text ' if called as ${foo
+"stupid"}. Macros may call other macros.
+</descrip>
+
+Macro <ref id="id" name="ID">s should have at least one uppercase letter as all lowercase
+letter <ref id="id" name="ID">s may be used in a later version for built-in macros like 'if',
+'expr' or 'for'.
+
+
+<sect1>maxeffort &lt;value&gt;<label id="maxeffort">
+<p>
+value: <ref id="real" name="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.
+
+
+<sect1>mineffort &lt;value&gt;<label id="mineffort">
+<p>
+value: <ref id="real" name="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.
+
+
+<sect1>priority &lt;value&gt;<label id="priority">
+<p>
+value: <ref id="integer" name="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. The default value is 500.
+
+
+<sect1>project &lt;id&gt; &lt;name&gt; &lt;version&gt; &lt;start&gt;
+&lt;end&gt;<label id="project">
+<p>
+
+id: <ref id="id" name="ID"> 
+
+name: <ref id="string" name="STRING"> 
+
+version: <ref id="string" name="STRING">
+
+start: <ref id="date" name="DATE">
+
+end: <ref id="date" name="DATE">
+
+Optional attributes: none
+
+The project property is mandatory and should be the first property in
+a project file. &lt;id&gt; is the default project <ref id="id" name="ID"> used to register
+resource allocations in a global database. &lt;name&gt; is the name of the
+project. &lt;version&gt; is the version of the project file. Typically this
+is the CVS ID. &lt;start&gt; and &lt;end&gt; define the time frame of the
+project. The end may be well after the end of the last task, but must
+be specified to terminate the scheduling process.
+
+
+<sect1>rate &lt;money&gt;<label id="rate">
+<p>
+money: <ref id="real" name="REAL">
+
+The default daily rate for using a resource full-time. This value will
+be used for all subsequent resource declarations unless specified
+otherwise.
+
+
+<sect1>resource &lt;id&gt; &lt;name&gt;<label id="resource">
+<p>
+
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+Optional attributes:
+
+<descrip>
+<tag/resource &lt;id&gt; &lt;name&gt;/
+Resources may be nested to create groups. A nested resource inherits
+the attributes of the parent resource. Only those attributes 
+ specified prior to the declaration of the
+nested resource are inherited.
+<tag/mineffort &lt;value&gt;/
+value: <ref id="real" name="REAL">
+
+The daily minimum effort for a resource. Resources that are
+used less than this value will be marked in the report.
+
+<tag/maxeffort &lt;value&gt;/
+value: <ref id="real" name="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
+full working day. 0.5 means half a working day.
+
+<tag/efficiency &lt;value&gt;/
+value: <ref id="real" name="REAL">
+
+The efficiency of the resource. This can be used to describe a team as
+a resource. A team of five should have an efficiency of 5.0.
+
+<tag/rate &lt;value&gt;/
+value: <ref id="real" name="REAL">
+
+The daily costs of the resource.
+
+<tag/kotrusid &lt;id&gt;/
+id: <ref id="string" name="STRING">
+
+The KoTrus <ref id="id" name="ID"> of the resource (e-mail address).
+
+<tag/vacation &lt;from&gt; &lsqb;- &lt;to&gt;&rsqb;/
+from: <ref id="date" name="DATE">
+
+to: <ref id="date" name="DATE">
+
+Specifies a vacation for a resource. The to value is NOT included in
+the vacation. It specifies the first second after the vacation.
+
+<tag/workinghours &lt;weekday&gt; &lt;from&gt; - &lt;to&gt;&lsqb;,&lt;from&gt;-&lt;to&gt;&rsqb;/
+weekday: <ref id="weekday" name="WEEKDAY">
+
+from: <ref id="time" name="TIME">
+
+to: <ref id="time" name="TIME">
+
+Sets the working hours to the specified intervals. If no hours are
+specified for a day, the global definitions are used.
+
+<tag/shift &lt;id&gt; &lt;from&gt; - &lt;to&gt;/
+id: <ref id="id" name="ID">
+
+from: <ref id="date" name="DATE">
+
+to: <ref id="date" name="DATE">
+
+Assigns the resource to a defined shift during the specified
+interval. Multiple shifts can be defined, but shift invervals may not
+overlap.
+</descrip>
+
+
+<sect1>shift &lt;id&gt; &lt;name&gt;<label id="shift">
+<p>
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+The following optional parameter may be used. At least one optional
+parameter must be specified.
+
+<descrip>
+<tag/shift &lt;id&gt; &lt;name&gt;/
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+Shifts may be nested. A nested shift inherits the attributes of the
+enclosing shift.
+
+<tag/workinghours &lt;weekday&gt; &lt;from&gt;-&lt;to&gt;&lsqb;,&lt;from&gt;-&lt;to&gt;&rsqb/
+weekday: <ref id="weekday" name="WEEKDAY">
+
+from: <ref id="time" name="TIME">
+
+to: <ref id="time" name="TIME">
+
+Sets the working hours to the specified intervals. If no hours are
+specified for a day, the global definitions are used. If no working
+hours should be specified for a day, the keyword 'off' must be used
+instead of the time interval.
+
+</descrip>
+When several resource have the same working hours, these working hours
+should be defined as shifts. Each shift must have a unique <ref id="id" name="ID">.
+Resources can be assigned to shifts for certain intervals. Ref.
+Resources.
+
+
+<sect1>supplement &lt;task|resource&gt; &lt;ID&gt;<label id="completion">
+<p>
+ID: <ref id="id">
+<p>
+The supplement keyword provides a mechanism to add more attributes to
+already defined tasks or resources. The additional attributes must
+obey the same rules as in regular task or resource definitions and
+must be enclosed by curly braces.
+
+This construct is primerily meant for situations where the information
+about a task or resource is split over serveral files. E. g. the
+vacation dates for the resources may be in a seperate file that was
+generated by some other tool.
+
+
+<sect1>task &lt;id&gt; &lt;name&gt;<label id="task">
+<p>
+
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+Optional attributes:
+
+<descrip>
+<tag/task &lt;id&gt; &lt;name&gt;/
+id: <ref id="id" name="ID">
+
+name: <ref id="string" name="STRING">
+
+A task may have subtasks. If subtasks are specified, many of the
+other attributes are illegal. See attributes for details.
+
+<tag/note &lt;text&gt;/
+text: <ref id="string" name="STRING">
+
+A longer description of the task.
+
+<tag/start &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The planned start date for the task. If no start date is given,
+the task must depend on other tasks. If no dependency is given, the
+project start date is used. Setting a start date will switch the
+scheduling policy to ASAP.
+
+<tag/end &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The planned end date for the task. If no end date is given, the
+task must depend on other tasks. If no dependency is given, the project
+start date is used. Setting an end date will switch the scheduling
+policy to ALAP.
+
+<tag/minstart &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The earliest desired start date for the task. If this date cannot
+be met, the task is marked in the task list.
+
+This attribute is inherited by subtasks.
+
+<tag/maxstart &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The latest desired start date for the task. If this date cannot be
+met, the task is marked in the task list.
+
+This attribute is inherited by subtasks.
+
+<tag/actualstart &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The actual start date of the task. This can be specified to compare the planned 
+and actual dates.
+
+<tag/minend &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The earliest desired end date for the task. If this date cannot be
+met, the task is marked in the task list.
+
+This attribute is inherited by subtasks.
+
+<tag/maxend &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The latest desired end date for the task. If this date cannot be
+met, the task is marked in the task list.
+
+This attribute is inherited by subtasks.
+
+<tag/actualend &lt;date&gt;/
+date: <ref id="date" name="DATE">
+
+The actual end date of the task. This can be specified to compare the planned 
+and actual dates.
+
+<tag/length &lt;number&gt; &lt;unit&gt;/
+number: <ref id="real" name="REAL">
+
+unit: <ref id="unit" name="UNIT">
+
+Specifies the time the task occupies the resources. This is working
+time, not calender time. 7d means 7 working days, not one week.
+
+Tasks may not have subtasks if this attribute is used.
+
+<tag/duration &lt;number&gt; &lt;unit&gt;/
+number: <ref id="real" name="REAL">
+
+unit: <ref id="unit" name="UNIT">
+
+Specifies the time the task occupies the resources. This is calender
+time, not working time. 7d means one week.
+
+Tasks may not have subtasks if this attribute is used.
+
+<tag/effort &lt;number&gt; &lt;unit&gt;/
+number: <ref id="real" name="REAL">
+
+unit: <ref id="unit" name="UNIT">
+
+Specifies the effort needed to complete the task. An effort of 4d can
+be done with 2 full-time resources in 2 days.
+
+WARNING: In almost all real world projects effort is not the product
+of time and resources. This is only true if the task can be
+partitioned without adding any overhead. For more information about
+this read "Mythical Man-Month" by Frederick P. Brooks, Jr.
+
+Tasks may not have subtasks if this attribute is used.
+
+<tag/complete &lt;percent&gt;/
+percent: <ref id="integer" name="INTEGER">
+
+Specifies what percentage of the task is already completed. This can be
+useful for project tracking.
+
+Tasks may not have subtasks if this attribute is used.
+
+<tag/allocate &lt;id&gt;/
+id: <ref id="id" name="ID">
+
+Optional attributes:
+
+<descrip>
+<tag/load &lt;days&gt;/
+days: <ref id="real" name="REAL">
+
+Specifies how many days the resource can be used per day for this
+task. A load of 0.5 means that the resource will be used for at most
+half a working day for this task.
+
+<tag/alternative &lt;id&gt;&lsqb,&lt;id&gt;&rsqb;/
+id: <ref id="id" name="ID">
+
+Specifies <ref id="id" name="ID">s of alternative resources. One of the alternatives will
+be used if the main resource is not available. If multiple
+resources are used, they must be separated by commas.
+
+<tag/persistent/
+
+If set, the first available resource out of the specified resource and
+its specified alternatives will be used for the entire task.
+</descrip>
+
+
+Specifies a resource that can be used to fulfill the task. More than
+one resource can be  specified for a task. All resources must be
+declared before they can be used. Ref. 'resource'. Resource
+allocations are mandatory for 'effort'-based tasks. Task with a
+'length' or 'duration' specification may have resources allocated, but
+do not require them.
+
+Tasks may not have subtasks if this attribute is used.
+
+<tag/scheduling &lt;policy&gt;/
+policy: <ref id="id" name="ID">
+
+This specifies the scheduling policy for the task. Possible values are:
+
+<descrip>
+<tag/ASAP/As soon as possible. The task is scheduled to happen as early as
+possible.
+
+<tag/ALAP/As late as possible. The task is scheduled to happen as late as
+possible.
+</descrip>
+
+The scheduling policy is automatically changed if the 'depends' or 
+'preceeds' attributes are used. If multiple attributes that affect the
+scheduling policy are used, that last attribute determines the
+effective policy.
+
+<tag/depends &lt;id&gt;&lsqb,&lt;id&gt;&rsqb;/
+id: GLOBAL_<ref id="id" name="ID">
+
+Specifies that the task cannot start before the task with the
+specified <ref id="id" name="ID">s have been finished. If multiple <ref id="id" name="ID">s are specified, they
+must be separated by commas. IDs must be either global or relative. A
+relative <ref id="id" name="ID"> starts with a number of '!'. Each '!' moves the scope to the
+parent task. Global <ref id="id" name="ID">s do not contain '!', but have <ref id="id" name="ID">s separated by
+dots.
+
+Example:
+<tscreen><verb>
+task foo1 {
+   task foo2 { start 2002-12-04 }
+   task foo3 { depends !foo2 }
+}
+task bar { depends foo1.foo2 }
+</verb></tscreen>
+
+By using the 'depends' attribute, the scheduling policy is
+automatically set to ASAP. If 'depends' and 'preceeds' are used, the
+last policy counts.
+
+<tag/preceeds &lt;id&gt;&lsqb;,&lt;id&gt;&rsqb;/
+id: GLOBAL_<ref id="id" name="ID">
+
+Specifies that this task preceeds the tasks with the specified
+<ref id="id" name="ID">s. If multiple tasks are specified, they must be separated by 
+commas. The format is equivalent to the 'depends' attribute.
+
+By using the 'preceeds' attribute, the scheduling policy is
+automatically set to ALAP. If 'depends' and 'preceeds' are used, the
+last policy counts.
+
+<tag/flags &lt;id&gt;&lsqb;,&lt;id&gt;&rsqb;/
+id: <ref id="id" name="ID">
+
+Attaches flags to the task. Flags can be used to filter tasks from the
+the output. Flags must be declared before they can be used. Ref. 'flags'.
+
+Flags are inherited by subtasks from their parent tasks if they are
+declared before the subtask. Flags that are declared after the subtasks 
+are NOT inherited.
+
+<tag/responsible &lt;id&gt;/
+id: <ref id="id" name="ID">
+
+The ID of the resource that is responsible for this task.
+
+This attribute is inherited by subtasks if specified prior to the
+definition of the subtask.
+
+<tag/priority &lt;value&gt;/
+value: <ref id="integer" name="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 subtasks if specified prior to the
+definition of the subtask.
+
+<tag/account &lt;id&gt;/
+id: <ref id="id" name="ID">
+
+Specifies the account to which all money associated with this task will be
+credited.
+
+This attribute is inherited by subtasks if specified prior to the
+definition of the subtask.
+
+<tag/startcredit &lt;amount&gt;/
+amount: <ref id="real" name="REAL">
+
+Specifies an amount that is credited to the account specified by the
+'account' property at the moment the tasks starts.
+
+<tag/endcredit &lt;amount&gt;/
+amount: <ref id="real" name="REAL">
+
+Specifies an amount that is credited to the account specified by the
+'account' property at the moment the tasks ends.
+</descrip>
+
+Tasks may be nested and some attributes are inherited by the subtasks.
+
+
+<sect1>timingresolution &lt;value&gt; &lt;unit&gt;<label id="timingresolution">
+<p>
+value: INTERGER
+
+unit: <ref id="unit" name="UNIT">
+
+Sets the minimum timing resolution. The smaller the value, the longer
+the schedulings process requires. The default is 1 hour. The smallest
+value is 5 min.
+
+
+<sect1>vacation name &lt;start&gt; &lsqb;- &lt;end&gt;&rsqb;<label id="vacationname">
+<p>
+name: <ref id="string" name="STRING">
+
+start: <ref id="date" name="DATE">
+
+end: <ref id="date" name="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.
+
+
+<sect1>workinghours &lt;weekday&gt; &lt;from&gt;-&lt;to&gt;&lsqb;,&lt;from&gt;-&lt;to&gt;&rsqb;<label id="hours">
+<p>
+weekday: <ref id="weekday" name="WEEKDAY">
+
+from: <ref id="time" name="TIME">
+
+to: <ref id="time" name="TIME">
+
+Sets the working hours to the specified intervals. The values are used
+as default values for all resources defined afterwards. The default
+values are 08:00-12:00 and 13:00-17:00 from Mon - Fri.
+
+
+<sect1>workinghoursperday &lt;value&gt;<label id="workinghoursperday">
+<p>
+value: <ref id="integer" name="INTEGER">
+
+Specifies the number of working hours per day. This value is used to
+calculate the daily load from the number of booked hours. If
+workingHoursPerDay is set to 8 and a resource is used for 12 hours on
+a day, the daily load is 1.5. Change this value with care as it
+affects many internal calculations.
+
+
+<sect1>xmltaskreport &lt;filename&gt;<label id="xmltaskreport">
+<p>
+
+filename: <ref id="string" name="STRING">
+
+create a xml task report to the given file. Note that this is still
+experimental. The format might change in future releases.
+
+
+<sect>The Example: Accounting Software<label id="example">
+<p>
+
+<tscreen><verb>
+project fibu "Accounting Software" "1.0" 2002-01-16 2002-06-30
+
+now 2002-02-17
+
+# The daily rate of all resources
+rate 310.0
+currency "EUR"
+
+# This is one way to form teams
+macro allocate_developers [
+  allocate dev1
+  allocate dev2 { load 0.5 }
+  allocate dev3
+]
+
+resource dev "Developers" {
+  resource dev1 "Paul Smith"
+  resource dev2 "Larry Bono"
+  resource dev3 "Klaus Mueller" { vacation 2002-02-01 - 2002-02-05 }
+}
+resource misc "The others" {
+  resource test "Peter Murphy" { maxeffort 0.8 rate 240.0 }
+  resource doc "Dim Sung"
+}
+
+account dev "Development" cost {}
+account doc "Dokumentation" cost {}
+account rev "Payments" revenue {}
+
+task AcSo "Accounting Software" {
+
+  account dev
+
+  task spec "Spezification" {
+    effort 20d
+    ${allocate_developers}
+    depends !deliveries.start
+  }
+
+  task software "Software development" {
+
+    priority 1000
+
+    task database "Database coupling" {
+      effort 20d
+      depends !!spec
+      allocate dev1
+      allocate dev2
+    }
+
+    task gui "Graphical user interface" {
+      effort 35d
+      actualeffort 40d
+      depends !database, !backend
+      allocate dev2
+      allocate dev3
+    }
+
+    task backend "Backend functions" {
+      effort 30d
+      complete 100
+      depends !database, !!spec
+      allocate dev1
+      allocate dev2
+    }
+    
+  }
+
+  task test "Software testing" {
+
+    task alpha "Alpha test" {
+      effort 1w
+      depends !!software
+      allocate test
+      allocate dev2
+    }
+
+    task beta "Beta test" {
+      effort 4w
+      depends !alpha
+      allocate test
+      allocate dev1
+    }
+  }
+
+  task manual "Manual" {
+    effort 10w
+    depends !deliveries.start
+    allocate doc
+    allocate dev3
+    account doc
+  }
+
+  task deliveries "Ship to customer" {
+
+    account rev
+
+    task start "Projectstart" {
+      milestone
+      start 2002-01-16
+      actualstart 2002-01-20
+      startcredit 30000.0
+    }
+
+    task beta "Betaversion" {
+      milestone
+      depends !!test.alpha
+      startcredit 10000.0
+    }
+
+    task done "Ship product to customer" {
+      milestone
+      maxend 2002-04-17
+      depends !!test.beta, !!manual
+      startcredit 20000.0
+    }
+  }
+}
+
+htmltaskreport "tasks.html" name,start,end,resources,weekly
+</verb></tscreen>
+
+<sect>Questions and Answers<p>
+
+<sect>Copyright<p>
+
+TaskJuggler Copyright 2001 Chris Schlaeger , cs@suse.de
+
+
+This program is free software. You can redistribute it and modify
+it under the terms of the GNU General Public License version 2 as published
+by the Free Software Foundation. 
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+<p>
+</article>
index af7a51a..143d2a2 100644 (file)
@@ -1,14 +1,14 @@
 Begin3
 Title:          TaskJuggler 
-Version:        0.1
+Version:        1.0.1
 Entered-date:   
-Description:    
-Keywords:        
+Description:    Project Management Software
+Keywords:       project planing, scheduling, project management, tasks, milestones
 Author:         Chris Schlaeger <cs@suse.de> 
 Maintained-by:  Chris Schlaeger <cs@suse.de> 
-Primary-site:                  
-Home-page:      http:// 
-Original-site:  
-Platforms:       Linux and other Unices
-Copying-policy: GNU Public License
+Primary-site:   http://www.suse.de/~freitag/taskjuggler                
+Home-page:      http://www.suse.de/~freitag/taskjuggler 
+Original-site:  http://www.suse.de/~freitag/taskjuggler
+Platforms:      Linux and other Unices
+Copying-policy: GNU Public License Version 2.0
 End
index a09af6f..11d737d 100644 (file)
@@ -83,7 +83,9 @@ public:
        {
                kotrusId = "";
        }
-       ~Account() { };
+       virtual ~Account() { };
+
+       virtual char* getType() { return "Account"; }
 
        Account* getParent() { return (Account*) parent; }
 
@@ -92,8 +94,8 @@ public:
        void setKotrusId(const QString& k) { kotrusId = k; }
        const QString& getKotrusId() const { return kotrusId; }
 
-       void setType(AccountType at) { acctType = at; }
-       AccountType getType() const { return acctType; }
+       void setAcctType(AccountType at) { acctType = at; }
+       AccountType getAcctType() const { return acctType; }
 
        void credit(Transaction* t)
        {
index 131ad38..d7b621c 100644 (file)
@@ -54,6 +54,8 @@ public:
                project(p), id(i), name(n), parent(parent_) { }
        virtual ~CoreAttributes() { }
 
+       virtual char* getType() { return "CoreAttributes"; }
+
        const QString& getId() const { return id; }
 
        void setIndex(uint idx) { index = idx; }
@@ -61,6 +63,8 @@ public:
 
        void setSequenceNo(uint no) { sequenceNo = no; }
 
+       Project* getProject() { return project; }
+
        void setName(const QString& n) { name = n; }
        const QString& getName() const { return name; }
        void getFullName(QString& fullName);
index 1107753..7a01f26 100644 (file)
  */
 
 #include "ExpressionTree.h"
+#include "CoreAttributes.h"
+#include "Project.h"
+#include "Task.h"
+
+QDict<int> ExpressionTree::funcArgc;
 
 long
-Operation::eval(ExpressionTree* et)
+Operation::evalAsInt(ExpressionTree* et)
 {
        switch (opt)
        {
        case Const:
                return value;
        case Variable:
-               return et->resolve(variable);
+               return et->resolve(name);
+       case Function:
+               return evalFunction(et);
+       case TaskId:
+       case ResourceId:
+       case AccountId:
+               return 0;
        case Not:
-               return !op1->eval(et);
+               return !ops.at(0)->evalAsInt(et);
        case And:
-               return op1->eval(et) && op2->eval(et);
+               return ops.at(0)->evalAsInt(et) && ops.at(1)->evalAsInt(et);
        case Or:
-               return op1->eval(et) || op2->eval(et);
+               return ops.at(0)->evalAsInt(et) || ops.at(1)->evalAsInt(et);
        default:
-               qFatal("Unknown opType");
+               qFatal("Unknown opType %d (name: %s)", opt, name.ascii());
+               return 0;
+       }
+}
+
+QString
+Operation::evalAsString(ExpressionTree* et)
+{
+       switch(opt)
+       {
+               case Const:
+                       return QString("%1").arg(value);
+               case Variable:
+                       return QString("%1").arg(et->resolve(name));
+               case Function:
+                       return evalFunctionAsString(et);
+               case TaskId:
+               case ResourceId:
+               case AccountId:
+                       return name;
+               default:
+                       return QString("%1").arg(ops.at(0)->evalAsInt(et));
+       }
+}
+
+long
+Operation::evalFunction(ExpressionTree* et)
+{
+       if (name == "istask")
+       {
+               return strcmp(et->getCoreAttributes()->getType(), "Task") == 0
+                       && et->getCoreAttributes()->getId() ==
+                       ops.at(0)->evalAsString(et);
+       }
+       else if (name == "issubtaskof")
+       {
+               if (strcmp(et->getCoreAttributes()->getType(), "Task") != 0)
+                       return 0;
+               Task* p;
+               if ((p = et->getCoreAttributes()->getProject()->getTask
+                        (ops.at(0)->evalAsString(et))) == 0)
+                       return 0;
+               return p->isSubTask((Task*) et->getCoreAttributes());
+       }
+       else if (name == "containstask")
+       {
+               if (strcmp(et->getCoreAttributes()->getType(), "Task") != 0)
+                       return 0;
+               Task* st;
+               if ((st = et->getCoreAttributes()->getProject()->getTask
+                        (ops.at(0)->evalAsString(et))) == 0)
+                       return 0;
+               return ((Task*) et->getCoreAttributes())->isSubTask(st);
+       }
+       else if (name == "ismilestone")
+       {
+               if (strcmp(et->getCoreAttributes()->getType(), "Task") != 0)
+                       return 0;
+               return ((Task*) et->getCoreAttributes())->isMilestone();
+       }
+       else
+               qFatal("Unknown function %s", name.data());     
+
+       return 0;
+}
+
+QString
+Operation::evalFunctionAsString(ExpressionTree* et)
+{
+       // There are no functions yet that return a string.
+       return "";
+}
+
+ExpressionTree::ExpressionTree(Operation* op) : expression(op)
+{
+       symbolTable.setAutoDelete(TRUE);
+       if (funcArgc.isEmpty())
+       {
+               funcArgc.insert("istask", new int(1));
+               funcArgc.insert("issubtaskof", new int(1));
+               funcArgc.insert("containstask", new int(1));
+               funcArgc.insert("ismilestone", new int(0));
        }
-       return 0;       // should never be reached
 }
 
 long
@@ -38,3 +129,16 @@ ExpressionTree::resolve(const QString& symbol)
 {
        return symbolTable[symbol] != 0 ? *(symbolTable[symbol]) : 0;
 }
+
+bool
+ExpressionTree::isFunction(const QString& name)
+{
+       return funcArgc[name];
+}
+
+int
+ExpressionTree::arguments(const QString& name)
+{
+       return *funcArgc[name];
+}
+
index 21a67d6..9e5cfd6 100644 (file)
 
 #include <qstring.h>
 #include <qdict.h>
+#include <qptrlist.h>
 
+class CoreAttributes;
 class ExpressionTree;
 
 class Operation
 {
 public:
-       enum opType { Const, Variable, Not, And, Or };
+       enum opType { Const = 1, Variable, Function, TaskId, ResourceId,
+               AccountId, Not, And, Or };
 
        Operation(long v) : opt(Const), value(v) { }
-       Operation(const QString& v) : opt(Variable), variable(v) { }
+       Operation(opType ot, const QString& n) : opt(ot), name(n) { }
+       Operation(const QString& v) : opt(Variable), name(v) { }
        Operation(Operation* o1, opType o, Operation* o2 = 0)
-               : opt(o), op1(o1), op2(o2) { }
+               : opt(o)
+       {
+               ops.setAutoDelete(TRUE);
+               ops.append(o1);
+               ops.append(o2);
+       }
+       Operation(const QString n, QPtrList<Operation> args) :
+          opt(Function), name(n)
+       {
+               ops = args;
+               ops.setAutoDelete(TRUE);
+       }
        ~Operation() { }
 
-       long eval(ExpressionTree* et);
+       long evalAsInt(ExpressionTree* et);
+       QString evalAsString(ExpressionTree* et);
 
 private:
        Operation() { } // don't use this
 
+       long evalFunction(ExpressionTree* et);
+       QString evalFunctionAsString(ExpressionTree* et);
+
        opType opt;
        long value;
-       QString variable;
-       Operation* op1;
-       Operation* op2;
+       QString name;
+       QPtrList<Operation> ops;
 } ;
 
 class ExpressionTree
 {
 public:
-       ExpressionTree(Operation* op) : expression(op)
-       {
-               symbolTable.setAutoDelete(TRUE);
-       }
+       ExpressionTree(Operation* op);
        ~ExpressionTree() { }
 
-       long eval() { return expression->eval(this); }
+       long evalAsInt(CoreAttributes* c)
+       {
+               ca = c;
+               return expression->evalAsInt(this);
+       }
        long resolve(const QString& symbol);
 
        void registerSymbol(const QString& symbol, long value)
@@ -59,11 +78,20 @@ public:
        }
        void clearSymbolTable() { symbolTable.clear(); }
 
+       CoreAttributes* getCoreAttributes() { return ca; }
+
+       static bool isFunction(const QString& name);
+
+       static int arguments(const QString& name);
+
 private:
        ExpressionTree() { }    // don't use this
 
+       CoreAttributes* ca;
        QDict<long> symbolTable;
        Operation* expression;
+       
+       static QDict<int> funcArgc;
 } ;
 
 #endif
index b7d4637..c528f6d 100644 (file)
@@ -13,9 +13,7 @@ INTERFACES =
 TRANSLATIONS = 
 # KDE_OPTIONS = qtonly
 taskjuggler_LDADD   =  $(LIB_QT) $(LIBSOCKET)
-CXXFLAGS = -Wall -g
-
-SUBDIRS = docs 
+CXXFLAGS = -Wall -O2
 
 # set the include path for X, qt and KDE
 INCLUDES= $(all_includes)
index 9b87e28..cc022d0 100644 (file)
@@ -184,7 +184,7 @@ Project::schedule()
 
        updateActiveTaskList(sortedTasks);
        for (day = start; !(activeAsap.isEmpty() && activeAlap.isEmpty()) &&
-                        day >= start && day < end; day += timeDelta)
+                day >= start && day < end; day += timeDelta)
        {
                timeDelta = scheduleGranularity;
                do
index 6132e57..be2a036 100644 (file)
@@ -96,6 +96,11 @@ public:
                return vacationList.next();
        }
 
+       Task* getTask(const QString& id)
+       {
+               return taskList.getTask(id);
+       }
+
        void addResource(Resource* r)
        {
                resourceList.append(r);
@@ -147,7 +152,7 @@ public:
 
        void addXMLReport(ReportXML *r ) { xmlreport = r; }
 #ifdef HAVE_KDE
-        void addICalReport( ReportICal *ic ) { icalReport = ic; }
+       void addICalReport( ReportICal *ic ) { icalReport = ic; }
 #endif
    
        void addHTMLTaskReport(HTMLTaskReport* h) { htmlTaskReports.append(h); }
@@ -266,12 +271,10 @@ private:
        AccountList accountList;
 
        Kotrus* kotrus;
-       TaskList activeAsap;
-       TaskList activeAlap;
 
        ReportXML* xmlreport;
 #ifdef HAVE_KDE
-        ReportICal *icalReport;
+       ReportICal *icalReport;
 #endif
    
        QList<HTMLTaskReport> htmlTaskReports;
@@ -280,6 +283,13 @@ private:
        QList<ExportReport> exportReports;
 
        static int debugLevel;
+
+       /**
+        * The task lists for active ASAP and ALAP tasks are only used
+        * during the scheduling process.
+        */
+       TaskList activeAsap;
+       TaskList activeAlap;
 } ;
 
 #endif
index 4b3457b..470a066 100644 (file)
@@ -559,9 +559,14 @@ ProjectFile::parse()
                        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;
                        }
@@ -841,6 +846,19 @@ ProjectFile::parse()
                                }
                                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 + "'!");
@@ -981,6 +999,46 @@ 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))
@@ -1230,22 +1288,36 @@ ProjectFile::readTask(Task* parent)
                }
        }
 
-       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;
@@ -1316,137 +1388,167 @@ 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 + "'");
+                       fatalError(QString("Unknown attribute '") + token + "'");
+                       return FALSE;
+               }
+               if (token == KW("resource"))
+               {
+                       if (!readResource(r))
                                return FALSE;
-                       }
-                       if (token == KW("resource"))
+               }
+               else if (token == KW("mineffort"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (!readResource(r))
-                                       return FALSE;
+                               fatalError("Real value exptected");
+                               return FALSE;
                        }
-                       else if (token == KW("mineffort"))
+                       r->setMinEffort(token.toDouble());
+               }
+               else if (token == KW("maxeffort"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setMinEffort(token.toDouble());
+                               fatalError("Real value exptected");
+                               return FALSE;
                        }
-                       else if (token == KW("maxeffort"))
+                       r->setMaxEffort(token.toDouble());
+               }
+               else if (token == KW("efficiency"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setMaxEffort(token.toDouble());
+                               fatalError("Read value expected");
+                               return FALSE;
                        }
-                       else if (token == KW("efficiency"))
+                       r->setEfficiency(token.toDouble());
+               }
+               else if (token == KW("rate"))
+               {
+                       if (nextToken(token) != REAL)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Read value expected");
-                                       return FALSE;
-                               }
-                               r->setEfficiency(token.toDouble());
+                               fatalError("Real value exptected");
+                               return FALSE;
                        }
-                       else if (token == KW("rate"))
+                       r->setRate(token.toDouble());
+               }
+               else if (token == KW("kotrusid"))
+               {
+                       if (nextToken(token) != STRING)
                        {
-                               if (nextToken(token) != REAL)
-                               {
-                                       fatalError("Real value exptected");
-                                       return FALSE;
-                               }
-                               r->setRate(token.toDouble());
+                               fatalError("String expected");
+                               return FALSE;
                        }
-                       else if (token == KW("kotrusid"))
+                       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) != STRING)
-                               {
-                                       fatalError("String expected");
-                                       return FALSE;
-                               }
-                               r->setKotrusId(token);
+                               fatalError("Shift ID expected");
+                               return FALSE;
                        }
-                       else if (token == KW("vacation"))
+                       Shift* s;
+                       if ((s = proj->getShift(id)) == 0)
                        {
-                               time_t from, to;
-                               if (!readVacation(from, to))
-                                       return FALSE;
-                               r->addVacation(new Interval(from, to));
+                               fatalError("Unknown shift");
+                               return FALSE;
                        }
-                       else if (token == KW("workinghours"))
+                       time_t from, to;
+                       if (!readVacation(from, to))
+                               return FALSE;
+                       if (!r->addShift(Interval(from, to), s))
                        {
-                               int dow;
-                               QPtrList<Interval>* l = new QPtrList<Interval>();
-                               if (!readWorkingHours(dow, l))
-                                       return FALSE;
-                               
-                               r->setWorkingHours(dow, l);
+                               fatalError("Shift interval overlaps with other");
+                               return FALSE;
                        }
-                       else if (token == KW("shift"))
+               }
+               else if (token == KW("flags"))
+               {
+                       for ( ; ; )
                        {
-                               QString id;
-                               if (nextToken(id) != ID)
-                               {
-                                       fatalError("Shift ID expected");
-                                       return FALSE;
-                               }
-                               Shift* s;
-                               if ((s = proj->getShift(id)) == 0)
-                               {
-                                       fatalError("Unknown shift");
-                                       return FALSE;
-                               }
-                               time_t from, to;
-                               if (!readVacation(from, to))
-                                       return FALSE;
-                               if (!r->addShift(Interval(from, to), s))
+                               QString flag;
+                               if (nextToken(flag) != ID || !proj->isAllowedFlag(flag))
                                {
-                                       fatalError("Shift interval overlaps with other");
+                                       fatalError("flag unknown");
                                        return FALSE;
                                }
-                       }
-                       else if (token == KW("flags"))
-                       {
-                               for ( ; ; )
+                               r->addFlag(flag);
+                               if ((tt = nextToken(token)) != COMMA)
                                {
-                                       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;
-                                       }
+                                       openFiles.last()->returnToken(tt, token);
+                                       break;
                                }
                        }
-                       else if (token == KW("include"))
-                       {
-                               if (!readInclude())
-                                       return FALSE;
-                               break;
-                       }
-                       else
-                       {
-                               fatalError(QString("Unknown attribute '") + token + "'");
+               }
+               else if (token == KW("include"))
+               {
+                       if (!readInclude())
                                return FALSE;
-                       }
+                       break;
+               }
+               else
+               {
+                       fatalError(QString("Unknown attribute '") + token + "'");
+                       return FALSE;
                }
        }
-       else
-               openFiles.last()->returnToken(tt, token);
-
-       proj->addResource(r);
 
        return TRUE;
 }
@@ -1563,7 +1665,7 @@ ProjectFile::readAccount(Account* parent)
                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)
@@ -2257,14 +2359,26 @@ ProjectFile::readLogicalExpression(int precedence)
        QString token;
        TokenType tt;
 
-       if ((tt = nextToken(token)) == ID)
+       if ((tt = nextToken(token)) == ID || tt == RELATIVE_ID)
        {
-               if (!proj->isAllowedFlag(token))
+               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 ((op = readFunctionCall(token)) == 0)
+                               return 0;
+               }
+               else
                {
-                       fatalError(QString("Flag ") + token + " is unknown.");
+                       fatalError(QString("Flag or function '") + token + "' is unknown.");
                        return 0;
                }
-               op = new Operation(token);
        }
        else if (tt == INTEGER)
        {
@@ -2317,6 +2431,39 @@ ProjectFile::readLogicalExpression(int precedence)
        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)
 {
index 989186b..24cea21 100644 (file)
@@ -96,9 +96,13 @@ private:
 
        bool readInclude();
        bool readTask(Task* parent);
+       bool readTaskSupplement();
+       bool readTaskBody(Task* task);
        bool readResource(Resource* parent);
+       bool readResourceSupplement();
+       bool readResourceBody(Resource* r);
        bool readVacation(time_t& from, time_t& to, bool readName = FALSE,
-                                         QString* = 0);
+                                         QString* = 0, bool* isResourceVacation = 0);
        bool readAccount(Account* parent);
        bool readShift(Shift* parent);
        bool readCredit(Account* a);
@@ -112,9 +116,10 @@ private:
        bool readExportReport();
        bool readXMLTaskReport();
 #ifdef HAVE_KDE
-        bool readICalTaskReport();
+       bool readICalTaskReport();
 #endif
        Operation* readLogicalExpression(int precedence = 0);
+       Operation* readFunctionCall(const QString& name);
        bool readSorting(Report* report, int which);
        time_t date2time(const QString& date);
        time_t hhmm2time(const QString& hhmm);
index 23525fa..b10090c 100644 (file)
@@ -54,7 +54,7 @@ Report::isHidden(CoreAttributes* c, ExpressionTree* et)
        QStringList flags = c->getFlagList();
        for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
                et->registerSymbol(*it, 1);
-       return et->eval() != 0;
+       return et->evalAsInt(c) != 0;
 }
 
 bool
@@ -67,7 +67,7 @@ Report::isRolledUp(CoreAttributes* c, ExpressionTree* et)
        QStringList flags = c->getFlagList();
        for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
                et->registerSymbol(*it, 1);
-       return et->eval() != 0;
+       return et->evalAsInt(c) != 0;
 }
 
 bool
@@ -80,7 +80,7 @@ Report::isTaskRolledUp(Task* t)
        QStringList flags = t->getFlagList();
        for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
                rollUpTask->registerSymbol(*it, 1);
-       return rollUpTask->eval() != 0;
+       return rollUpTask->evalAsInt(t) != 0;
 }
 
 bool
@@ -93,7 +93,7 @@ Report::isResourceRolledUp(Resource* r)
        QStringList flags = r->getFlagList();
        for (QStringList::Iterator it = flags.begin(); it != flags.end(); ++it)
                rollUpResource->registerSymbol(*it, 1);
-       return rollUpResource->eval() != 0;
+       return rollUpResource->evalAsInt(r) != 0;
 }
 
 void
index 3801707..a02607b 100644 (file)
@@ -110,6 +110,8 @@ public:
        Resource(Project* p, const QString& i, const QString& n, Resource* p);
        virtual ~Resource();
 
+       virtual char* getType() { return "Resource"; }
+
        Resource* getParent() const { return (Resource*) parent; }
 
        bool isGroup() const { return !sub.isEmpty(); }
index 9784566..89b8b33 100644 (file)
@@ -42,6 +42,8 @@ public:
        Shift(Project* prj, const QString& i, const QString& n, Shift* p);
        virtual ~Shift();
 
+       virtual char* getType() { return "Shift"; }
+
        void setWorkingHours(int day, QPtrList<Interval>* l)
        {
                if (day < 0 || day > 6)
index a0c55c6..c483aad 100644 (file)
 
 int Task::debugLevel = 0;
 
+Task*
+TaskList::getTask(const QString& id)
+{
+       for (Task* t = first(); t != 0; t = next())
+               if (t->getId() == id)
+                       return t;
+
+       return 0;
+}
+
 Task::Task(Project* proj, const QString& id_, const QString& n, Task* p,
                   const QString f, int l)
        : CoreAttributes(proj, id_, n, p), file(f), line(l)
@@ -1145,6 +1155,16 @@ Task::getSubTaskList(TaskList& tl)
        }
 }
 
+bool
+Task::isSubTask(Task* tsk)
+{
+       for (Task* t = subFirst(); t != 0; t = subNext())
+               if (t == tsk || t->isSubTask(tsk))
+                       return TRUE;
+
+       return FALSE;
+}
+
 void
 Task::treeSortKey(QString& key)
 {
index b3836ee..3f5bbd2 100644 (file)
@@ -100,6 +100,8 @@ public:
        Task* first() { return (Task*) CoreAttributesList::first(); }
        Task* next() { return (Task*) CoreAttributesList::next(); }
 
+       Task* getTask(const QString& id);
+
 protected:
        virtual int compareItems(QCollection::Item i1, QCollection::Item i2);
 } ;
@@ -116,7 +118,9 @@ class Task : public CoreAttributes
 public:
        Task(Project* prj, const QString& id_, const QString& n, Task* p,
                 const QString f, int l);
-       ~Task() { }
+       virtual ~Task() { }
+
+       virtual char* getType() { return "Task"; }
 
        enum SchedulingInfo { ASAP, ALAP };
 
@@ -297,6 +301,8 @@ public:
 
        void getSubTaskList(TaskList& tl);
 
+       bool isSubTask(Task* t);
+
        void treeSortKey(QString& key);
 
        void preparePlan();
@@ -354,13 +360,13 @@ private:
 
        /**
         * A list of all tasks that preceed this task. This is redundant
-        * information but stored for conveniance. Interdependant tasks are
+        * information but stored for conveniance. Interdependent tasks are
         * linked in a doubly linked list. */
        TaskList previous;
 
        /**
         * A list of all tasks that follow this task. This is redundant
-        * information but stored for conveniance. Interdependant tasks are
+        * information but stored for conveniance. Interdependent tasks are
         * linked in a doubly linked list. */
        TaskList followers;