New upstream release.
Vincent Bernat
3 years ago
432 | 432 | background-color:#EE0000; |
433 | 433 | position:absolute; |
434 | 434 | } |
435 | .markdateline { | |
436 | background-color:#000000; | |
437 | position:absolute; | |
438 | } | |
435 | 439 | .white { |
436 | 440 | background-color:#FFFFFF; |
437 | 441 | position:absolute; |
0 | 0 | /* |
1 | 1 | * This file contains a project skeleton. It is part of the |
2 | 2 | * TaskJuggler project management tool. You can use this as a basis to |
3 | * start you own project file. | |
3 | * start your own project file. | |
4 | 4 | */ |
5 | 5 | project your_project_id "Your Project Title" 2011-11-11-0:00--0500 +4m { |
6 | 6 | # Set the default time zone for the project. If not specified, UTC |
27 | 27 | |
28 | 28 | # You can define your own attributes for tasks and resources. This |
29 | 29 | # is handy to capture additional information about the project that |
30 | # is not directly impacting the project schedule but you like to | |
30 | # is not directly impacting the project schedule, but which you like to | |
31 | 31 | # keep in one place. |
32 | 32 | #extend task { |
33 | 33 | # reference spec "Link to Wiki page" |
58 | 58 | # used to filter out subsets of them during reporting. |
59 | 59 | flags important, hidden |
60 | 60 | |
61 | # If you want to do budget planning for you project, you need to | |
61 | # If you want to do budget planning for your project, you need to | |
62 | 62 | # define some accounts. |
63 | 63 | account cost "Project Cost" { |
64 | 64 | account dev "Development" |
66 | 66 | } |
67 | 67 | account rev "Customer Payments" |
68 | 68 | |
69 | # The Profit&Loss analysis should be rev - cost accounts. | |
69 | # The Profit & Loss analysis should be rev - cost accounts. | |
70 | 70 | balance cost rev |
71 | 71 | |
72 | # Define you public holidays here. | |
72 | # Define your public holidays here. | |
73 | 73 | vacation "New Year's Day" 2012-01-02 |
74 | 74 | vacation "Birthday of Martin Luther King, Jr." 2012-01-16 |
75 | 75 | vacation "Washington's Birthday" 2012-02-20 |
82 | 82 | vacation "Christmas Day" 2012-12-25 |
83 | 83 | |
84 | 84 | # The daily default rate of all resources. This can be overridden for each |
85 | # resource. We specify this, so that we can do a good calculation of | |
85 | # resource. We specify this so we can do a good calculation of | |
86 | 86 | # the costs of the project. |
87 | 87 | rate 400.0 |
88 | 88 | |
122 | 122 | |
123 | 123 | # Now the project has been specified completely. Stopping here would |
124 | 124 | # result in a valid TaskJuggler file that could be processed and |
125 | # scheduled. But no reports would be generated to visualize the | |
125 | # scheduled. Here reports will be generated to visualize the | |
126 | 126 | # results. |
127 | 127 | |
128 | 128 | navigator navbar { |
19 | 19 | # used, but this will likely be outside of the project range, so it |
20 | 20 | # can't be seen in the reports. |
21 | 21 | now 2002-03-05-13:00 |
22 | # The currency for all money values is the Euro. | |
22 | # The currency for all money values is the US Dollar. | |
23 | 23 | currency "USD" |
24 | 24 | |
25 | 25 | # We want to compare the baseline scenario to one with a slightly |
0 | [NAME] | |
1 | tj3 \- schedules tj3 projects and generates reports | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBTASKJUGGLER_DATA_PATH\fR | |
7 | Override the path to the TaskJuggler data folder. | |
8 | The data folder contains the css, icons and scripts | |
9 | for TaskJuggler reports. | |
10 | ||
11 | .TP | |
12 | \fBTZ\fR | |
13 | The POSIX Time Zone environment variable. | |
14 | ||
15 | Any environment variable may be used in a TaskJuggler file using the expression $(VAR_NAME). | |
16 | ||
17 | [EXAMPLES] | |
18 | ||
19 | tj3 tutorial.tjp | |
20 | ||
21 | [SEE ALSO] | |
22 | tj3client(1), tj3d(1), tj3man(1), tj3ss_receiver(1), tj3ss_sender(1), tj3ts_receiver(1), tj3ts_sender(1), tj3ts_summary(1), tj3webd(1) | |
23 | ||
24 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3client \- send commands and data to the TaskJuggler daemon | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | [FILES] | |
10 | ||
11 | .TP | |
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must contain: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | ||
18 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
19 | ||
20 | [EXAMPLES] | |
21 | .TP | |
22 | Load a project: | |
23 | tj3client add yourproject.tjp | |
24 | .PP | |
25 | .TP | |
26 | List available reports for a project: | |
27 | tj3client list-reports <project_id> | |
28 | .PP | |
29 | .TP | |
30 | Generate a report: | |
31 | tj3client report <project_id> <report_id> | |
32 | .PP | |
33 | .TP | |
34 | Terminate a running instance of the server: | |
35 | tj3client terminate | |
36 | ||
37 | ||
38 | ||
39 | [SEE ALSO] | |
40 | tj3d(1) | |
41 | ||
42 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tjd3 \- the TaskJuggler daemon | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | [FILES] | |
10 | ||
11 | .TP | |
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must contain: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | ||
18 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
19 | ||
20 | .TP | |
21 | \fBtj3d.log\fR | |
22 | ||
23 | The tj3d log file, created in the working directory. Location can be overridden using the --logfile FILE option. | |
24 | ||
25 | [SECURITY] | |
26 | The author advises: "the daemon has not received any kind of security review ... only use the daemon in a trusted environment with only trusted users!" | |
27 | ||
28 | ||
29 | [SEE ALSO] | |
30 | tj3client(1) | |
31 | ||
32 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3man \- get documentation for TaskJuggler keywords or generate user manual | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBBROWSER\fR | |
7 | The web browser used to display the user manual as HTML. | |
8 | ||
9 | [EXAMPLES] | |
10 | ||
11 | tj3man shift | |
12 | .br | |
13 | tj3man --html shift.timesheet | |
14 | .br | |
15 | tj3man --html | |
16 | ||
17 | [SEE ALSO] | |
18 | ||
19 | tj3(1) | |
20 | ||
21 | The TaskJuggler manual is also available online at http://www.taskjuggler.org/tj3/manual/. |
0 | [NAME] | |
1 | tj3ss_receiver \- receive filled-out status sheets via email | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | ||
10 | [FILES] | |
11 | .TP | |
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must configure an e-mail delivery method and sender e-mail e.g.: | |
14 | ||
15 | _global: | |
16 | emailDeliveryMethod: smtp | |
17 | smtpServer: smtp.your_company.com | |
18 | .br | |
19 | _statussheets: | |
20 | senderEmail: 'TaskJuggler <statussheets@taskjuggler.amd.com>' | |
21 | ||
22 | An alternative config file location may be specified using the -c, --config FILE option. | |
23 | ||
24 | .TP | |
25 | \fBstatussheets.log\fR | |
26 | The statussheets log file, created in the working directory. | |
27 | ||
28 | .TP | |
29 | \fBStatusSheets/FailedMails/\fR | |
30 | Directory created in the working directory to store the failed emails. | |
31 | ||
32 | .TP | |
33 | \fBStatusSheets/FailedSheets/\fR | |
34 | Directory created in the working directory to store the failed status sheets. | |
35 | ||
36 | ||
37 | [SEE ALSO] | |
38 | tj3ss_sender(1) | |
39 | ||
40 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3ss_sender \- send out status sheets templates via email | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | ||
10 | [FILES] | |
11 | ||
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must configure an authentication key, an e-mail delivery method and sender e-mail e.g.: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | smtpServer: smtp.your_company.com | |
18 | .br | |
19 | _statussheets: | |
20 | senderEmail: 'TaskJuggler <statussheets@taskjuggler.amd.com>' | |
21 | ||
22 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
23 | ||
24 | .TP | |
25 | \fBstatussheets.log\fR | |
26 | The statussheets log file, created in the working directory. | |
27 | ||
28 | .TP | |
29 | \fBStatusSheetTemplates\fR | |
30 | Base directory of the sheet templates, created in the working directory. | |
31 | ||
32 | ||
33 | [SEE ALSO] | |
34 | ||
35 | tj3ss_receiver(1), tj3d(1) | |
36 | ||
37 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3ts_receiver \- receive filled-out time sheets via email | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | ||
10 | [FILES] | |
11 | .TP | |
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must configure an authentication key, an e-mail delivery method and sender e-mail e.g.: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | smtpServer: smtp.your_company.com | |
18 | _timesheets: | |
19 | senderEmail: 'TaskJuggler <timesheets@taskjuggler.amd.com>' | |
20 | ||
21 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
22 | ||
23 | .TP | |
24 | \fBtimesheets.log\fR | |
25 | The statussheets log file, created in the working directory. | |
26 | ||
27 | .TP | |
28 | \fBTimeSheets/FailedMails/\fR | |
29 | Directory created in the working directory to store the failed emails. | |
30 | ||
31 | .TP | |
32 | \fBTimeSheets/FailedSheets/\fR | |
33 | Directory created in the working directory to store the failed status sheets. | |
34 | ||
35 | ||
36 | [SEE ALSO] | |
37 | ||
38 | tj3ts_sender(1) | |
39 | ||
40 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3ts_sender \- send out time sheets templates via email | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | [FILES] | |
10 | ||
11 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
12 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must configure an authentication key, an e-mail delivery method and sender e-mail e.g.: | |
13 | ||
14 | _global: | |
15 | authKey: ******** | |
16 | smtpServer: smtp.your_company.com | |
17 | projectId: acso | |
18 | .br | |
19 | _timesheets: | |
20 | senderEmail: 'TaskJuggler <statussheets@taskjuggler.amd.com>' | |
21 | ||
22 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
23 | ||
24 | .TP | |
25 | \fBtimesheets.log\fR | |
26 | The timesheets log file, created in the working directory. | |
27 | ||
28 | .TP | |
29 | \fBTimeSheetTemplates\fR | |
30 | Base directory of the sheet templates, created in the working directory. | |
31 | ||
32 | ||
33 | [SEE ALSO] | |
34 | tj3ts_receiver(1) | |
35 | ||
36 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3ts_summary \- send out individual copies and a summary of accepted time sheets | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | ||
10 | [FILES] | |
11 | ||
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must configure an authentication key, an e-mail delivery method, project id, sender e-mail and receipients e.g.: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | smtpServer: smtp.your_company.com | |
18 | projectId: acso | |
19 | .br | |
20 | _timesheets: | |
21 | senderEmail: 'TaskJuggler <statussheets@taskjuggler.amd.com>' | |
22 | _summary: | |
23 | sheetRecipients: | |
24 | - team@your_company.com | |
25 | ||
26 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
27 | ||
28 | ||
29 | .TP | |
30 | \fBtimesheets.log\fR | |
31 | The timesheets log file, created in the working directory. | |
32 | ||
33 | .TP | |
34 | \fBTimeSheetTemplates\fR | |
35 | Base directory of the sheet templates, created in the working directory. | |
36 | ||
37 | ||
38 | [SEE ALSO] | |
39 | tj3ts_receiver(1) tj3ts_sender(1) | |
40 | ||
41 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
0 | [NAME] | |
1 | tj3webd \- TaskJuggler reports web server | |
2 | ||
3 | [ENVIRONMENT] | |
4 | ||
5 | .TP | |
6 | \fBHOME\fR | |
7 | The user's home folder. Used to search for configuration file if not specified. | |
8 | ||
9 | [FILES] | |
10 | ||
11 | .TP | |
12 | \fB.taskjugglerrc\fR or \fBtaskjuggler.rc\fR | |
13 | tj3d searches for a config file named .taskjugglerrc or taskjuggler.rc in the current path, the user's home path as specified by the HOME environment variable or /etc/. At a minimum the file must contain: | |
14 | ||
15 | _global: | |
16 | authKey: ******** | |
17 | ||
18 | (the user should specify their own auth key and set file permissions accordingly). An alternative config file location may be specified using the -c, --config FILE option. | |
19 | ||
20 | [SEE ALSO] | |
21 | tj3d(1) | |
22 | ||
23 | The full TaskJuggler manual is available online at http://www.taskjuggler.org/tj3/manual/, or via the tj3man command. |
49 | 49 | end |
50 | 50 | |
51 | 51 | # Set the selection mode identified by name specified in _str_. For |
52 | # efficiency reasons, we turn the name into a Fixnum value. | |
52 | # efficiency reasons, we turn the name into an Integer value. | |
53 | 53 | def setSelectionMode(str) |
54 | 54 | modes = %w( order minallocated minloaded maxloaded random ) |
55 | 55 | @selectionMode = modes.index(str) |
2 | 2 | # |
3 | 3 | # = AttributeBase.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
135 | 135 | |
136 | 136 | def to_num |
137 | 137 | v = get |
138 | if v.is_a?(Fixnum) || v.is_a?(Bignum) || v.is_a?(Float) | |
138 | if v.is_a?(Integer) || v.is_a?(Float) | |
139 | 139 | v |
140 | 140 | else |
141 | 141 | nil |
144 | 144 | |
145 | 145 | def to_sort |
146 | 146 | v = get |
147 | if v.is_a?(Fixnum) || v.is_a?(Bignum) || v.is_a?(Float) | |
147 | if v.is_a?(Integer) || v.is_a?(Float) | |
148 | 148 | v |
149 | 149 | elsif v.respond_to?('to_s') |
150 | v.to_s | |
150 | if v.respond_to?('join') | |
151 | # If the attribute is an Array we convert it to a comma separated | |
152 | # list. | |
153 | v.join(', ') | |
154 | else | |
155 | v.to_s | |
156 | end | |
151 | 157 | else |
152 | 158 | nil |
153 | 159 | end |
263 | 263 | |
264 | 264 | end |
265 | 265 | |
266 | class FixnumAttribute < AttributeBase | |
267 | def initialize(property, type, container) | |
268 | super | |
269 | end | |
270 | ||
271 | def FixnumAttribute::tjpId | |
266 | class IntegerAttribute < AttributeBase | |
267 | def initialize(property, type, container) | |
268 | super | |
269 | end | |
270 | ||
271 | def IntegerAttribute::tjpId | |
272 | 272 | 'integer' |
273 | 273 | end |
274 | 274 | end |
15 | 15 | |
16 | 16 | class TaskJuggler |
17 | 17 | |
18 | # The JobInfo class is just a storage container for some batch job realted | |
18 | # The JobInfo class is just a storage container for some batch job related | |
19 | 19 | # pieces of information. It contains things like a job id, the process id, |
20 | 20 | # the stdout data and the like. |
21 | 21 | class JobInfo |
165 | 165 | # |
166 | 166 | # sbStart must be a TjTime of the scoreboard start |
167 | 167 | # slotDuration must be the duration of the scoreboard slots in seconds |
168 | # a and b should be TjTime or Fixnum objects that describe the start and | |
168 | # a and b should be TjTime or Integer objects that describe the start and | |
169 | 169 | # end time or index of the interval. |
170 | 170 | # |
171 | 171 | # TimeInterval.new(iv) |
190 | 190 | # If the third argument is a date we convert it to a scoreboard index. |
191 | 191 | args[2] = dateToIndex(args[2]) if args[2].is_a?(TjTime) |
192 | 192 | |
193 | if args[2].is_a?(Fixnum) || args[2].is_a?(Bignum) | |
193 | if args[2].is_a?(Integer) | |
194 | 194 | super(args[2], args[2]) |
195 | 195 | else |
196 | 196 | raise ArgumentError, "Illegal argument 3: #{args[0].class}" |
203 | 203 | args[2] = dateToIndex(args[2]) if args[2].is_a?(TjTime) |
204 | 204 | args[3] = dateToIndex(args[3]) if args[3].is_a?(TjTime) |
205 | 205 | |
206 | if !(args[2].is_a?(Fixnum) || args[2].is_a?(Bignum)) | |
206 | if !(args[2].is_a?(Integer)) | |
207 | 207 | raise ArgumentError, "Interval start must be an index or TjTime, " + |
208 | 208 | "not a #{args[2].class}" |
209 | 209 | end |
210 | if !(args[3].is_a?(Fixnum) || args[3].is_a?(Bignum)) | |
210 | if !(args[3].is_a?(Integer)) | |
211 | 211 | raise ArgumentError, "Interval end must be an index or TjTime, " + |
212 | 212 | "not a #{args[3].class}" |
213 | 213 | end |
220 | 220 | raise ArgumentError, "sbStart must be a TjTime object, not a" + |
221 | 221 | "#{@sbStart.class}" |
222 | 222 | end |
223 | unless @slotDuration.is_a?(Fixnum) | |
224 | raise ArgumentError, "slotDuration must be a Fixnum, not a " + | |
223 | unless @slotDuration.is_a?(Integer) | |
224 | raise ArgumentError, "slotDuration must be an Integer, not a " + | |
225 | 225 | "#{@slotDuration.class}" |
226 | 226 | end |
227 | 227 | |
228 | 228 | end |
229 | 229 | |
230 | # Assign the start of the interval. +arg+ can be a Fixnum, Bignum or | |
230 | # Assign the start of the interval. +arg+ can be an Integer or | |
231 | 231 | # TjTime object. |
232 | 232 | def start=(arg) |
233 | 233 | case arg |
234 | when Fixnum | |
235 | when Bignum | |
234 | when Integer | |
236 | 235 | @start = arg |
237 | 236 | when TjTime |
238 | 237 | @start = dateToIndex(arg) |
241 | 240 | end |
242 | 241 | end |
243 | 242 | |
244 | # Assign the start of the interval. +arg+ can be a Fixnum, Bignum or | |
243 | # Assign the start of the interval. +arg+ can be an Integer or | |
245 | 244 | # TjTime object. |
246 | 245 | def end=(arg) |
247 | 246 | case arg |
248 | when Fixnum | |
249 | when Bignum | |
247 | when Integer | |
250 | 248 | @end = arg |
251 | 249 | when TjTime |
252 | 250 | @end = dateToIndex(arg) |
612 | 612 | # This function returns a list of entries that have all the exact same |
613 | 613 | # date and are the last entries before the deadline _date_. Only messages |
614 | 614 | # with at least the required alert level _minLevel_ are returned. Messages |
615 | # with alert level _minLevel_ must be newer than _minDate_. | |
615 | # with alert level _minLevel_ or higher must be newer than _minDate_. | |
616 | 616 | def currentEntries(date, property, minLevel, minDate, logExp) |
617 | 617 | pEntries = getEntries(property) ? getEntries(property).last(date) : |
618 | 618 | JournalEntryList.new |
620 | 620 | # date. |
621 | 621 | pEntries.delete_if do |e| |
622 | 622 | e.headline.empty? || e.alertLevel < minLevel || |
623 | (e.alertLevel == minLevel && minDate && e.date < minDate) | |
623 | (e.alertLevel >= minLevel && minDate && e.date < minDate) | |
624 | 624 | end |
625 | 625 | |
626 | 626 | unless pEntries.empty? |
138 | 138 | # 2nd arg must be a scenario index. |
139 | 139 | return false if (scenarioIdx = project.scenarioIdx(args[1])).nil? |
140 | 140 | # 3rd arg must be an integer number. |
141 | return false unless args[2].is_a?(Fixnum) | |
141 | return false unless args[2].is_a?(Integer) | |
142 | 142 | |
143 | 143 | property.isDependencyOf(scenarioIdx, task, args[2]) |
144 | 144 | end |
2 | 2 | # |
3 | 3 | # = LogicalOperation.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
63 | 63 | coerceTime(o, expr) |
64 | 64 | end |
65 | 65 | return res |
66 | elsif opnd1.is_a?(Fixnum) || opnd1.is_a?(Float) || opnd1.is_a?(Bignum) | |
66 | elsif opnd1.is_a?(Integer) || opnd1.is_a?(Float) | |
67 | 67 | return evalBinaryOperation(opnd1, operator, opnd2) do |o| |
68 | 68 | coerceNumber(o, expr) |
69 | 69 | end |
144 | 144 | # An empty String means false, else true. |
145 | 145 | return !val.empty? if val.is_a?(String) |
146 | 146 | # In TJP logic 'non 0' means false. |
147 | return val != 0 if val.is_a?(Fixnum) || val.is_a?(Bignum) | |
147 | return val != 0 if val.is_a?(Integer) | |
148 | 148 | |
149 | 149 | expr.error("Operand #{val} can't be evaluated to true or false.") |
150 | 150 | end |
151 | 151 | |
152 | 152 | # Force the _val_ into a number. In case this fails, an exception is raised. |
153 | 153 | def coerceNumber(val, expr) |
154 | unless val.is_a?(Fixnum) || val.is_a?(Float) || val.is_a?(Bignum) | |
154 | unless val.is_a?(Integer) || val.is_a?(Float) | |
155 | 155 | expr.error("Operand #{val} of type #{val.class} must be a number.") |
156 | 156 | end |
157 | 157 | val |
215 | 215 | query.scenarioIdx = @scenario.sequenceNo - 1 |
216 | 216 | query.attributeId = @operand1 |
217 | 217 | query.process |
218 | unless query.ok | |
219 | return "Error in conversion to String: #{query.errorMessage}" | |
220 | end | |
218 | 221 | query.to_s |
219 | 222 | else |
220 | 223 | "#{@scenario.fullId}.#{@operand1}" |
229 | 229 | private |
230 | 230 | |
231 | 231 | def checkLevel(level) |
232 | if level.is_a?(Fixnum) | |
232 | if level.is_a?(Integer) | |
233 | 233 | if level < 0 || level > 5 |
234 | 234 | raise ArgumentError, "Unsupported level #{level}" |
235 | 235 | end |
103 | 103 | end |
104 | 104 | |
105 | 105 | # Return the 'index' attributes of this property, prefixed by the 'index' |
106 | # attributes of all its parents. The result is an Array of Fixnums. | |
106 | # attributes of all its parents. The result is an Array of Integers. | |
107 | 107 | def getIndicies |
108 | 108 | idcs = [] |
109 | 109 | p = self |
77 | 77 | 'currencyFormat' => RealFormat.new([ '-', '', '', ',', 2 ]), |
78 | 78 | 'dailyworkinghours' => 8.0, |
79 | 79 | 'end' => nil, |
80 | 'markdate' => nil, | |
80 | 81 | 'flags' => [], |
81 | 82 | 'journal' => Journal.new, |
82 | 83 | 'limits' => nil, |
125 | 126 | false, false, false, true ], |
126 | 127 | [ 'projection', 'Projection Mode', BooleanAttribute, |
127 | 128 | true, false, false, false ], |
128 | [ 'seqno', 'No', FixnumAttribute, | |
129 | [ 'seqno', 'No', IntegerAttribute, | |
129 | 130 | false, false, false, nil ], |
130 | 131 | ] |
131 | 132 | attrs.each { |a| @scenarios.addAttributeType(AttributeDefinition.new(*a)) } |
138 | 139 | false, false, false, "" ], |
139 | 140 | [ 'id', 'ID', StringAttribute, |
140 | 141 | false, false, false, nil ], |
141 | [ 'index', 'Index', FixnumAttribute, | |
142 | [ 'index', 'Index', IntegerAttribute, | |
142 | 143 | false, false, false, -1 ], |
143 | 144 | [ 'leaves', 'Leaves', LeaveListAttribute, |
144 | 145 | true, true, true, LeaveList.new ], |
146 | 147 | false, false, false, nil ], |
147 | 148 | [ 'replace', 'Replace', BooleanAttribute, |
148 | 149 | true, false, true, false ], |
149 | [ 'seqno', 'No', FixnumAttribute, | |
150 | [ 'seqno', 'No', IntegerAttribute, | |
150 | 151 | false, false, false, nil ], |
151 | 152 | [ 'timezone', 'Time Zone', StringAttribute, |
152 | 153 | true, true, true, TjTime.timeZone ], |
169 | 170 | false, false, true, [] ], |
170 | 171 | [ 'id', 'ID', StringAttribute, |
171 | 172 | false, false, false, nil ], |
172 | [ 'index', 'Index', FixnumAttribute, | |
173 | [ 'index', 'Index', IntegerAttribute, | |
173 | 174 | false, false, false, -1 ], |
174 | 175 | [ 'flags', 'Flags', FlagListAttribute, |
175 | 176 | true, false, true, [] ], |
176 | 177 | [ 'name', 'Name', StringAttribute, |
177 | 178 | false, false, false, nil ], |
178 | [ 'seqno', 'No', FixnumAttribute, | |
179 | [ 'seqno', 'No', IntegerAttribute, | |
179 | 180 | false, false, false, nil ], |
180 | 181 | [ 'tree', 'Tree Index', StringAttribute, |
181 | 182 | false, false, false, "" ] |
200 | 201 | false, false, true, [] ], |
201 | 202 | [ 'efficiency','Efficiency', FloatAttribute, |
202 | 203 | true, false, true, 1.0 ], |
203 | [ 'effort', 'Total Effort', FixnumAttribute, | |
204 | [ 'effort', 'Total Effort', IntegerAttribute, | |
204 | 205 | false, false, true, 0 ], |
205 | 206 | [ 'email', 'Email', StringAttribute, |
206 | 207 | false, false, false, nil ], |
208 | 209 | false, false, false, [] ], |
209 | 210 | [ 'flags', 'Flags', FlagListAttribute, |
210 | 211 | true, false, true, [] ], |
211 | [ 'index', 'Index', FixnumAttribute, | |
212 | [ 'index', 'Index', IntegerAttribute, | |
212 | 213 | false, false, false, -1 ], |
213 | 214 | [ 'leaveallowances', 'Leave Allowances', LeaveAllowanceListAttribute, |
214 | 215 | true, false, true, LeaveAllowanceList.new ], |
222 | 223 | true, true, true, 0.0 ], |
223 | 224 | [ 'reports', 'Reports', ResourceListAttribute, |
224 | 225 | false, false, true, [] ], |
225 | [ 'seqno', 'No', FixnumAttribute, | |
226 | [ 'seqno', 'No', IntegerAttribute, | |
226 | 227 | false, false, false, nil ], |
227 | 228 | [ 'shifts', 'Shifts', ShiftAssignmentsAttribute, |
228 | 229 | true, false, true, nil ], |
263 | 264 | false, false, true, 0 ], |
264 | 265 | [ 'effort', 'Effort', DurationAttribute, |
265 | 266 | false, false, true, 0 ], |
266 | [ 'effortdone', 'Completed Effort', FixnumAttribute, | |
267 | [ 'effortdone', 'Completed Effort', IntegerAttribute, | |
267 | 268 | false, false, true, nil ], |
268 | [ 'effortleft', 'Remaining Effort', FixnumAttribute, | |
269 | [ 'effortleft', 'Remaining Effort', IntegerAttribute, | |
269 | 270 | false, false, true, nil ], |
270 | 271 | [ 'end', 'End', DateAttribute, |
271 | 272 | false, false, true, nil ], |
283 | 284 | false, false, true, nil ], |
284 | 285 | [ 'id', 'ID', StringAttribute, |
285 | 286 | false, false, false, nil ], |
286 | [ 'index', 'Index', FixnumAttribute, | |
287 | [ 'index', 'Index', IntegerAttribute, | |
287 | 288 | false, false, false, -1 ], |
288 | 289 | [ 'length', 'Length', DurationAttribute, |
289 | 290 | false, false, true, 0 ], |
307 | 308 | false, false, true, 0.0 ], |
308 | 309 | [ 'precedes', 'Following tasks', DependencyListAttribute, |
309 | 310 | true, false, true, [] ], |
310 | [ 'priority', 'Priority', FixnumAttribute, | |
311 | [ 'priority', 'Priority', IntegerAttribute, | |
311 | 312 | true, true, true, 500 ], |
312 | 313 | [ 'projectid', 'Project ID', SymbolAttribute, |
313 | 314 | true, true, true, nil ], |
317 | 318 | true, false, true, false ], |
318 | 319 | [ 'projectionmode', 'Projection Mode', BooleanAttribute, |
319 | 320 | true, false, true, false ], |
320 | [ 'seqno', 'No', FixnumAttribute, | |
321 | [ 'seqno', 'No', IntegerAttribute, | |
321 | 322 | false, false, false, nil ], |
322 | 323 | [ 'shifts', 'Shifts', ShiftAssignmentsAttribute, |
323 | 324 | true, false, true, nil ], |
360 | 361 | true, false, false, KeywordArray.new([ '*' ]) ], |
361 | 362 | [ 'end', 'End', DateAttribute, |
362 | 363 | true, true, false, nil ], |
364 | [ 'markdate', 'Markdate', DateAttribute, | |
365 | true, true, false, nil ], | |
363 | 366 | [ 'epilog', 'Epilog', RichTextAttribute, |
364 | 367 | true, false, false, nil ], |
365 | 368 | [ 'flags', 'Flags', FlagListAttribute, |
382 | 385 | true, false, false, nil ], |
383 | 386 | [ 'hideTask', 'Hide Task', LogicalExpressionAttribute, |
384 | 387 | true, false, false, nil ], |
385 | [ 'height', 'Height', FixnumAttribute, | |
388 | [ 'height', 'Height', IntegerAttribute, | |
386 | 389 | false, false, false, 480 ], |
387 | 390 | [ 'id', 'ID', StringAttribute, |
388 | 391 | false, false, false, nil ], |
389 | [ 'index', 'Index', FixnumAttribute, | |
392 | [ 'index', 'Index', IntegerAttribute, | |
390 | 393 | false, false, false, -1 ], |
391 | 394 | [ 'interactive', 'Interactive', BooleanAttribute, |
392 | 395 | false, false, false, false ], |
428 | 431 | true, false, false, [ 0 ] ], |
429 | 432 | [ 'selfcontained', 'Selfcontained', BooleanAttribute, |
430 | 433 | true, false, false, false ], |
431 | [ 'seqno', 'No', FixnumAttribute, | |
434 | [ 'seqno', 'No', IntegerAttribute, | |
432 | 435 | false, false, false, nil ], |
433 | 436 | [ 'shortTimeFormat', 'Short Time Format', StringAttribute, |
434 | 437 | true, true, false, nil ], |
460 | 463 | false, false, false, "" ], |
461 | 464 | [ 'weekStartsMonday', 'Week Starts Monday', BooleanAttribute, |
462 | 465 | true, true, false, false ], |
463 | [ 'width', 'Width', FixnumAttribute, | |
464 | true, false, false, 640 ] | |
466 | [ 'width', 'Width', IntegerAttribute, | |
467 | true, false, false, 640 ], | |
468 | [ 'novevents', 'No vevents in icalreports', BooleanAttribute, | |
469 | true, false, false, false ] | |
465 | 470 | ] |
466 | 471 | attrs.each { |a| @reports.addAttributeType(AttributeDefinition.new(*a)) } |
467 | 472 | |
559 | 564 | # |
560 | 565 | # Return the Scenario with the given _id_ or _index_. |
561 | 566 | def scenario(arg) |
562 | if arg.is_a?(Fixnum) | |
567 | if arg.is_a?(Integer) | |
563 | 568 | @scenarios.each do |sc| |
564 | 569 | return sc if sc.sequenceNo - 1 == arg |
565 | 570 | end |
865 | 870 | # isWorkingTime(startTime, endTime) -> true or false |
866 | 871 | # isWorkingTime(interval) -> true or false |
867 | 872 | # |
868 | # Return true if the slot or interval is withing globally defined working | |
873 | # Return true if the slot or interval is within globally defined working | |
869 | 874 | # time or false if not. If the argument is a TimeInterval, all slots of |
870 | 875 | # the interval must be working time to return true as result. Global work |
871 | 876 | # time means, no global leaves defined and the slot lies within a |
873 | 878 | def isWorkingTime(*args) |
874 | 879 | # Normalize argument(s) to TimeInterval |
875 | 880 | if args.length == 1 |
876 | if args[0].is_a?(Fixnum) || args[0].is_a?(Bignum) | |
881 | if args[0].is_a?(Integer) | |
877 | 882 | return @scoreboard[args[0]].nil? |
878 | 883 | elsif args[0].is_a?(TjTime) |
879 | 884 | return @scoreboard[dateToIdx(args[0])].nil? |
968 | 973 | |
969 | 974 | def collectTimeOffIntervals(iv, minDuration) |
970 | 975 | @scoreboard.collectIntervals(iv, minDuration) do |val| |
971 | val.is_a?(Fixnum) && (val & 0x3E) != 0 | |
976 | val.is_a?(Integer) && (val & 0x3E) != 0 | |
972 | 977 | end |
973 | 978 | end |
974 | 979 |
2 | 2 | # |
3 | 3 | # = PropertyList.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
270 | 270 | |
271 | 271 | @query.property = a |
272 | 272 | @query.process |
273 | unless @query.ok | |
274 | fatal "List sort failed: #{@query.errorMessage}" | |
275 | end | |
273 | 276 | aVal = @query.to_sort |
274 | 277 | |
275 | 278 | @query.property = b |
276 | 279 | @query.process |
280 | unless @query.ok | |
281 | fatal "List sort failed: #{@query.errorMessage}" | |
282 | end | |
277 | 283 | bVal = @query.to_sort |
278 | 284 | else |
279 | 285 | # In case we don't have a query, we use the static mechanism. |
50 | 50 | [ |
51 | 51 | [ 'id', 'ID', StringAttribute, false, false, false, '' ], |
52 | 52 | [ 'name', 'Name', StringAttribute, false, false, false, '' ], |
53 | [ 'seqno', 'Seq. No', FixnumAttribute, false, false, false, 0 ] | |
53 | [ 'seqno', 'Seq. No', IntegerAttribute, false, false, false, 0 ] | |
54 | 54 | ].each { |a| addAttributeType(AttributeDefinition.new(*a)) } |
55 | 55 | end |
56 | 56 |
2 | 2 | # |
3 | 3 | # = PropertyTreeNode.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
330 | 330 | end |
331 | 331 | |
332 | 332 | # Return the 'index' attributes of this property, prefixed by the 'index' |
333 | # attributes of all its parents. The result is an Array of Fixnums. | |
333 | # attributes of all its parents. The result is an Array of Integers. | |
334 | 334 | def getIndicies |
335 | 335 | idcs = [] |
336 | 336 | p = self |
701 | 701 | res += '-' * 75 + "\n" |
702 | 702 | end |
703 | 703 | |
704 | alias to_str to_s | |
705 | ||
704 | 706 | # Many PropertyTreeNode functions are scenario specific. These functions are |
705 | 707 | # provided by the class *Scenario classes. In case we can't find a function |
706 | 708 | # called for the base class we try to find it in corresponding *Scenario |
707 | 709 | # class. |
708 | def method_missing(func, scenarioIdx, *args, &block) | |
710 | def method_missing(func, scenarioIdx = 0, *args, &block) | |
709 | 711 | @data[scenarioIdx].send(func, *args, &block) |
710 | 712 | end |
711 | 713 |
80 | 80 | end |
81 | 81 | |
82 | 82 | def startIdx=(idx) |
83 | if idx.is_a?(Fixnum) | |
83 | if idx.is_a?(Integer) | |
84 | 84 | @startIdx = idx |
85 | 85 | @start = @project.idxToDate(idx) |
86 | 86 | else |
98 | 98 | end |
99 | 99 | |
100 | 100 | def endIdx=(idx) |
101 | if idx.is_a?(Fixnum) | |
101 | if idx.is_a?(Integer) | |
102 | 102 | @endIdx = idx |
103 | 103 | @end = @project.idxToDate(idx) |
104 | 104 | else |
238 | 238 | @attr ? @attr.to_s(self) : (@rti ? @rti.to_s : (@string || '')) |
239 | 239 | end |
240 | 240 | |
241 | # Return the result of the Query as Fixnum or Float. The result may be | |
241 | # Return the result of the Query as Integer or Float. The result may be | |
242 | 242 | # nil. |
243 | 243 | def to_num |
244 | 244 | @attr ? @attr.to_num : @numerical |
23 | 23 | # thousandsSeparator: Separator used after 3 integer digits. (String) |
24 | 24 | # fractionSeparator: Separator used between the inter part and the |
25 | 25 | # fractional part. (String) |
26 | # fractionDigits: Number of fractional digits to show. (Fixnum) | |
26 | # fractionDigits: Number of fractional digits to show. (Integer) | |
27 | 27 | class RealFormat |
28 | 28 | |
29 | 29 | attr_reader :signPrefix, :signSuffix, :thousandsSeparator, |
2 | 2 | # |
3 | 3 | # = Resource.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
36 | 36 | # provided by the class ResourceScenario. In case we can't find a |
37 | 37 | # function called for the Resource class we try to find it in |
38 | 38 | # ResourceScenario. |
39 | def method_missing(func, scenarioIdx, *args, &block) | |
39 | def method_missing(func, scenarioIdx = 0, *args, &block) | |
40 | 40 | @data[scenarioIdx].method(func).call(*args, &block) |
41 | 41 | end |
42 | 42 |
19 | 19 | def initialize(resource, scenarioIdx, attributes) |
20 | 20 | super |
21 | 21 | |
22 | # Scoreboard may be nil, a Task, or a bit vector encoded as a Fixnum | |
22 | # Scoreboard may be nil, a Task, or a bit vector encoded as an Integer | |
23 | 23 | # nil: Value has not been determined yet. |
24 | 24 | # Task: A reference to a Task object |
25 | 25 | # Bit 0: Reserved |
276 | 276 | query.sortable = query.numerical = val = |
277 | 277 | getLeave(query.startIdx, query.endIdx, :annual) |
278 | 278 | query.string = query.scaleLoad(val) |
279 | end | |
280 | ||
281 | # Compute a list of the annual leave days within the period specified by | |
282 | # the _query_. The result is a list of dates and how much of that day was | |
283 | # taken. | |
284 | def query_annualleavelist(query) | |
285 | iv_list = collectLeaveIntervals(Interval.new(query.start, query.end), :annual) | |
286 | iv_list.map! do |iv| | |
287 | # The interval is at most one working day. We list the date of that | |
288 | # day. | |
289 | day = iv.start.strftime(@project['timeFormat']) | |
290 | # And how much of the working day was taken. A full working day is | |
291 | # 1.0, a half working day 0.5. | |
292 | days = (iv.end - iv.start) / (60 * 60 * @project['dailyworkinghours']) | |
293 | "#{day} (#{'%.1f' % days})" | |
294 | end | |
295 | query.assignList(iv_list) | |
279 | 296 | end |
280 | 297 | |
281 | 298 | def query_annualleavebalance(query) |
684 | 701 | initScoreboard if @scoreboard.nil? |
685 | 702 | |
686 | 703 | @scoreboard.collectIntervals(iv, minDuration) do |val| |
687 | val.is_a?(Fixnum) && (val & 0x3E) != 0 | |
704 | val.is_a?(Integer) && (val & 0x3E) != 0 | |
705 | end | |
706 | end | |
707 | ||
708 | # Return a list of scoreboard intervals that are at least _minDuration_ long | |
709 | # and only contain leave slots of the given type. The result is an Array of | |
710 | # [ start, end ] TjTime values. | |
711 | def collectLeaveIntervals(iv, type) | |
712 | # Time-off intervals are only useful for leaf resources. Group resources | |
713 | # would just default to the global working hours. | |
714 | return [] unless @property.leaf? | |
715 | ||
716 | initScoreboard if @scoreboard.nil? | |
717 | ||
718 | @scoreboard.collectIntervals(iv, 60 * 60) do |val| | |
719 | val.is_a?(Integer) && (val & 0x3E) == (Leave::Types[type] << 2) | |
688 | 720 | end |
689 | 721 | end |
690 | 722 | |
722 | 754 | # leave. |
723 | 755 | def getLeaveSlots(startIdx, endIdx, type) |
724 | 756 | countSlots(startIdx, endIdx) do |val| |
725 | val.is_a?(Fixnum) && (val & 0x3E) == (Leave::Types[type] << 2) | |
757 | val.is_a?(Integer) && (val & 0x3E) == (Leave::Types[type] << 2) | |
726 | 758 | end |
727 | 759 | end |
728 | 760 | |
738 | 770 | def getTimeOffSlots(startIdx, endIdx) |
739 | 771 | countSlots(startIdx, endIdx) do |val| |
740 | 772 | # Bit 1 needs to be unset and the leave bits must not be 0. |
741 | val.is_a?(Fixnum) && (val & 0x2) == 0 && (val & 0x3C) != 0 | |
773 | val.is_a?(Integer) && (val & 0x2) == 0 && (val & 0x3C) != 0 | |
742 | 774 | end |
743 | 775 | end |
744 | 776 | |
899 | 931 | initScoreboard unless @scoreboard |
900 | 932 | |
901 | 933 | val = @scoreboard[sbIdx] |
902 | return true unless val.is_a?(Fixnum) | |
934 | return true unless val.is_a?(Integer) | |
903 | 935 | |
904 | 936 | leave_type = (val >> 2) & 0xF |
905 | 937 | leave_type < Leave::Types[:unemployed] |
26 | 26 | |
27 | 27 | # Create a RichTextSnip object. _document_ is a reference to the |
28 | 28 | # RichTextDocument. _fileName_ is the name of the structured text file |
29 | # using RichText syntax. _sectionCounter_ is an 3 item Fixnum Array. These | |
29 | # using RichText syntax. _sectionCounter_ is an 3 item Integer Array. These | |
30 | 30 | # 3 numbers are used to store the section counters over multiple |
31 | 31 | # RichTextSnip objects. |
32 | 32 | def initialize(document, fileName, sectionCounter) |
44 | 44 | def configure(object, section) |
45 | 45 | debug("Configuring object of type #{object.class}") |
46 | 46 | sections = section.split('.') |
47 | p = @config | |
47 | return false unless (p = @config) | |
48 | 48 | sections.each do |sec| |
49 | 49 | p = p['_' + sec] |
50 | 50 | unless p |
2 | 2 | # |
3 | 3 | # = Scoreboard.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
174 | 174 | end |
175 | 175 | |
176 | 176 | def inspect |
177 | s = '' | |
177 | 178 | 0.upto(@sb.length - 1) do |i| |
178 | puts "#{idxToDate(i)}: #{@sb[i]}" | |
179 | s << "#{idxToDate(i)}: #{@sb[i]}" | |
179 | 180 | end |
181 | ||
182 | s | |
180 | 183 | end |
181 | 184 | |
182 | 185 | end |
2 | 2 | # |
3 | 3 | # = Shift.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2019 | |
6 | 6 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 7 | # |
8 | 8 | # This program is free software; you can redistribute it and/or modify |
33 | 33 | # provided by the class ShiftScenario. In case we can't find a |
34 | 34 | # function called for the Shift class we try to find it in |
35 | 35 | # ShiftScenario. |
36 | def method_missing(func, scenarioIdx, *args) | |
36 | def method_missing(func, scenarioIdx = 0, *args) | |
37 | 37 | @data[scenarioIdx].method(func).call(*args) |
38 | 38 | end |
39 | 39 |
78 | 78 | # To optimize memory usage and computation time the Scoreboard objects for |
79 | 79 | # similar ShiftAssignments are shared. |
80 | 80 | # |
81 | # Scoreboard may be nil or a bit vector encoded as a Fixnum | |
81 | # Scoreboard may be nil or a bit vector encoded as an Integer | |
82 | 82 | # nil: Value has not been determined yet. |
83 | 83 | # Bit 0: 0: No assignment |
84 | 84 | # 1: Has assignement |
28 | 28 | attr_accessor :maxCpuCores, :warnTsDeltas, :generateTraces |
29 | 29 | |
30 | 30 | # Create a new TaskJuggler object. _console_ is a boolean that determines |
31 | # whether or not messsages can be written to $stderr. | |
31 | # whether or not messages can be written to $stderr. | |
32 | 32 | def initialize |
33 | 33 | @project = nil |
34 | 34 | @parser = nil |
140 | 140 | res |
141 | 141 | end |
142 | 142 | |
143 | # Generate all specified reports. The project must have be scheduled before | |
143 | # Generate all specified reports. The project must have been scheduled before | |
144 | 144 | # this method can be called. It returns true if no error occured, false |
145 | 145 | # otherwise. |
146 | 146 | def generateReports(outputDir = nil) |
288 | 288 | end |
289 | 289 | |
290 | 290 | # Check the content of the file _fileName_ and interpret it as a time sheet. |
291 | # If the sheet is syntaxtically correct and matches the loaded project, true | |
291 | # If the sheet is syntactically correct and matches the loaded project, true | |
292 | 292 | # is returned. Otherwise false. |
293 | 293 | def checkTimeSheet(fileName) |
294 | 294 | begin |
332 | 332 | end |
333 | 333 | |
334 | 334 | # Check the content of the file _fileName_ and interpret it as a status |
335 | # sheet. If the sheet is syntaxtically correct and matches the loaded | |
335 | # sheet. If the sheet is syntactically correct and matches the loaded | |
336 | 336 | # project, true is returned. Otherwise false. |
337 | 337 | def checkStatusSheet(fileName) |
338 | 338 | begin |
42 | 42 | |
43 | 43 | # This class is used to handle the low-level input operations. It knows |
44 | 44 | # whether it deals with a text buffer or a file and abstracts this to the |
45 | # Scanner. For each nested file the scanner puts an StreamHandle on the | |
45 | # Scanner. For each nested file the scanner puts a StreamHandle on the | |
46 | 46 | # stack while the file is scanned. With this stack the scanner can resume |
47 | # the processing of the enclosing file once the included files has been | |
47 | # the processing of the enclosing file once the included files have been | |
48 | 48 | # completely processed. |
49 | 49 | class StreamHandle |
50 | 50 | |
280 | 280 | end |
281 | 281 | |
282 | 282 | |
283 | # Start the processing. if _fileNameIsBuffer_ is true, we operate on a | |
283 | # Start the processing. If _fileNameIsBuffer_ is true, we operate on a | |
284 | 284 | # String, else on a File. |
285 | 285 | def open(fileNameIsBuffer = false) |
286 | 286 | @fileNameIsBuffer = fileNameIsBuffer |
122 | 122 | # Add a new rule to the rule set. _name_ must be a unique identifier. The |
123 | 123 | # function also sets the class variable @cr to the new rule. Subsequent |
124 | 124 | # calls to TextParser#pattern, TextParser#optional or |
125 | # TextParser#repeatable will then implicitely operate on the most recently | |
125 | # TextParser#repeatable will then implicitly operate on the most recently | |
126 | 126 | # added rule. |
127 | 127 | def newRule(name) |
128 | 128 | # Use a symbol instead of a String. |
45 | 45 | @sourceFileInfo = nil |
46 | 46 | end |
47 | 47 | |
48 | # Store the number of worked time slots. If the value is a Fixnum, it can | |
48 | # Store the number of worked time slots. If the value is an Integer, it can | |
49 | 49 | # be directly assigned. A Float is interpreted as percentage and must be |
50 | 50 | # in the rage of 0.0 to 1.0. |
51 | 51 | def work=(value) |
52 | if value.is_a?(Fixnum) | |
52 | if value.is_a?(Integer) | |
53 | 53 | @work = value |
54 | 54 | else |
55 | 55 | # Must be percent value |
50 | 50 | @opts.summary_width = @optsSummaryWidth |
51 | 51 | @opts.summary_indent = ' ' * @optsSummaryIndent |
52 | 52 | |
53 | @opts.banner = "#{AppConfig.softwareName} v#{AppConfig.version} - " + | |
54 | "#{AppConfig.packageInfo}\n\n" + | |
55 | "Copyright (c) #{AppConfig.copyright.join(', ')}\n" + | |
53 | @opts.banner = "Copyright (c) #{AppConfig.copyright.join(', ')}\n" + | |
56 | 54 | " by #{AppConfig.authors.join(', ')}\n\n" + |
57 | 55 | "#{AppConfig.license}\n" + |
58 | 56 | "For more info about #{AppConfig.softwareName} see " + |
59 | 57 | "#{AppConfig.contact}\n\n" + |
60 | 58 | "Usage: #{AppConfig.appName} [options] " + |
61 | 59 | "#{@mandatoryArgs}\n\n" |
62 | @opts.separator "" | |
60 | ||
61 | @opts.separator "\nOptions:" | |
63 | 62 | @opts.on('-c', '--config <FILE>', String, |
64 | 63 | format('Use the specified YAML configuration file')) do |arg| |
65 | 64 | @configFile = arg |
74 | 73 | format(<<'EOT' |
75 | 74 | Don't use ANSI contol sequences to color the terminal output. Colors should |
76 | 75 | only be used when spooling to an ANSI terminal. In case the detection fails, |
77 | you can this option to force colors to be off. | |
76 | you can use this option to force colors to be off. | |
78 | 77 | EOT |
79 | 78 | )) do |
80 | 79 | Term::ANSIColor::coloring = false |
90 | 89 | quit |
91 | 90 | end |
92 | 91 | @opts.on_tail('--version', format('Show version info')) do |
93 | puts "#{AppConfig.softwareName} v#{AppConfig.version} - " + | |
94 | "#{AppConfig.packageInfo}" | |
92 | # Display the software name and version in GNU format | |
93 | # as expected by help2man | |
94 | # https://www.gnu.org/prep/standards/standards.html#g_t_002d_002dversion | |
95 | puts "#{AppConfig.appName} (#{AppConfig.softwareName}) #{AppConfig.version}\n" | |
96 | # To also display the copyright and license statements in GNU format | |
97 | # uncomment the following and remove the equivalent statements from | |
98 | # --help | |
99 | # + | |
100 | #<<'EOT' | |
101 | #Copyright (C) 2016 Chris Schlaeger <cs@taskjuggler.org> | |
102 | #License GPLv2: GNU GPL version 2 <http://gnu.org/licenses/gpl.html> | |
103 | #This is free software; you can redistribute it and/or modify it under | |
104 | #the terms of version 2 of the GNU General Public License as published by the | |
105 | #Free Software Foundation. | |
106 | # | |
107 | #For more info about TaskJuggler see http://www.taskjuggler.org | |
108 | #EOT | |
95 | 109 | quit |
96 | 110 | end |
97 | 111 | |
127 | 141 | args = processArguments(argv) |
128 | 142 | |
129 | 143 | # If DEBUG mode has been enabled, we restore the INT trap handler again |
130 | # to get Ruby backtrackes. | |
144 | # to get Ruby backtraces. | |
131 | 145 | Kernel.trap('INT', intHandler) if $DEBUG |
132 | 146 | |
133 | 147 | unless @silent |
145 | 159 | retVal = appMain(args) |
146 | 160 | MessageHandlerInstance.instance.trapSetup = false |
147 | 161 | rescue TjRuntimeError |
148 | # We have hit a sitatuation that we can't recover from. A message | |
162 | # We have hit a situation that we can't recover from. A message | |
149 | 163 | # was severed via the MessageHandler to inform the user and we now |
150 | 164 | # abort the program. |
151 | 165 | return 1 |
2 | 2 | # |
3 | 3 | # = Tj3Config.rb -- The TaskJuggler III Project Management Software |
4 | 4 | # |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016 | |
5 | # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2016, | |
6 | # 2020 | |
6 | 7 | # by Chris Schlaeger <cs@taskjuggler.org> |
7 | 8 | # |
8 | 9 | # This program is free software; you can redistribute it and/or modify |
12 | 13 | |
13 | 14 | require 'taskjuggler/UTF8String' |
14 | 15 | require 'taskjuggler/AppConfig' |
16 | require 'taskjuggler/version' | |
15 | 17 | |
16 | AppConfig.version = '3.6.0' | |
18 | AppConfig.version = VERSION | |
17 | 19 | AppConfig.packageName = 'taskjuggler' |
18 | 20 | AppConfig.softwareName = 'TaskJuggler' |
19 | 21 | AppConfig.packageInfo = 'A Project Management Software' |
20 | AppConfig.copyright = [ (2006..2016).to_a ] | |
22 | AppConfig.copyright = [ (2006..2020).to_a ] | |
21 | 23 | AppConfig.authors = [ 'Chris Schlaeger <cs@taskjuggler.org>' ] |
22 | 24 | AppConfig.contact = 'http://www.taskjuggler.org' |
23 | 25 | AppConfig.license = <<'EOT' |
74 | 74 | @file.each_line do |line| |
75 | 75 | if line[0, mark.length] == mark |
76 | 76 | # We've found an annotation line. Get the tag and indicator. |
77 | dum, dum, dum, tag, indicator = line.split | |
77 | tokens = line.split | |
78 | tag = tokens[3] | |
79 | indicator = tokens[4] | |
78 | 80 | |
79 | 81 | if indicator == '+' |
80 | 82 | # Start a new snip |
75 | 75 | def rule_accountHeader |
76 | 76 | pattern(%w( _account !optionalID $STRING ), lambda { |
77 | 77 | if @property.nil? && !@accountprefix.empty? |
78 | @property = @project.accout(@accountprefix) | |
78 | @property = @project.account(@accountprefix) | |
79 | 79 | end |
80 | 80 | if @val[1] && @project.account(@val[1]) |
81 | 81 | error('account_exists', "Account #{@val[1]} has already been defined.", |
238 | 238 | inherited allocations or flags. |
239 | 239 | |
240 | 240 | For effort-based tasks the task duration is clipped to only extend from the |
241 | begining of the first allocation to the end of the last allocation. This is | |
241 | beginning of the first allocation to the end of the last allocation. This is | |
242 | 242 | done to optimize for an overall minimum project duration as dependent tasks |
243 | 243 | can potentially use the unallocated, clipped slots. |
244 | 244 | EOT |
286 | 286 | @allocate.setSelectionMode(@val[1]) |
287 | 287 | }) |
288 | 288 | doc('select', <<'EOT' |
289 | The select functions controls which resource is picked from an allocation and | |
289 | The select function controls which resource is picked from an allocation and | |
290 | 290 | it's alternatives. The selection is re-evaluated each time the resource used |
291 | 291 | in the previous time slot becomes unavailable. |
292 | 292 | |
300 | 300 | @allocate.persistent = true |
301 | 301 | }) |
302 | 302 | doc('persistent', <<'EOT' |
303 | Specifies that once a resource is picked from the list of alternatives this | |
303 | Specifies that once a resource is picked from the list of alternatives, this | |
304 | 304 | resource is used for the whole task. This is useful when several alternative |
305 | 305 | resources have been specified. Normally the selected resource can change after |
306 | 306 | each break. A break is an interval of at least one timeslot where no resources |
388 | 388 | descr(<<'EOT' |
389 | 389 | Pick the resource that has the smallest allocation factor. The |
390 | 390 | allocation factor is calculated from the various allocations of the resource |
391 | across the tasks. This is the default setting.) | |
391 | across the tasks. This is the default setting. | |
392 | 392 | EOT |
393 | 393 | ) |
394 | 394 | |
747 | 747 | Normally, columns with calculated values take the specified report period into |
748 | 748 | account when calculating their values. With this attribute, the user can |
749 | 749 | specify an end date for the period that should be used when calculating the |
750 | values of this column. It does not have an impact on column with time | |
750 | values of this column. It does not have an impact on columns with time | |
751 | 751 | invariant values. |
752 | 752 | EOT |
753 | 753 | ) |
780 | 780 | @column.listItem = @val[1] |
781 | 781 | }) |
782 | 782 | doc('listitem.column', <<'EOT' |
783 | Specifies a RichText pattern that is used to generate the text for the list | |
783 | Specifies a [[Rich_Text_Attributes|Rich Text]] pattern that is used to generate the text for the list | |
784 | 784 | items. The pattern should contain at least one ''''<nowiki><</nowiki>-query |
785 | 785 | attribute='XXX'->'''' element that will be replaced with the value of |
786 | 786 | attribute XXX. For the replacement, the property of the query will be the list |
823 | 823 | Normally, columns with calculated values take the specified report period into |
824 | 824 | account when calculating their values. With this attribute, the user can |
825 | 825 | specify a start date for the period that should be used when calculating the |
826 | values of this column. It does not have an impact on column with time | |
826 | values of this column. It does not have an impact on columns with time | |
827 | 827 | invariant values. |
828 | 828 | EOT |
829 | 829 | ) |
929 | 929 | ''''+HHMM'''' or ''''-HHMM''''. Dates must always be aligned with the |
930 | 930 | [[timingresolution]]. |
931 | 931 | |
932 | TaskJuggler also supports simple date calculations. You can add or substract a | |
932 | TaskJuggler also supports simple date calculations. You can add or subtract a | |
933 | 933 | given interval from a fixed date. |
934 | 934 | |
935 | 935 | %{2009-11-01 + 8m} |
936 | 936 | |
937 | This will result in an actual date of around 2009-07-01. Keep in mind that due | |
937 | This will result in an actual date of around 2010-07-01. Keep in mind that due | |
938 | 938 | to the varying lengths of months TaskJuggler cannot add exactly 8 calendar |
939 | 939 | months. The date calculation functionality makes most sense when used with |
940 | 940 | macros. |
941 | 941 | |
942 | 942 | %{${now} - 2w} |
943 | 943 | |
944 | This is result in a date 2 weeks earlier than the current (or specified) date. | |
944 | This results in a date 2 weeks earlier than the current (or specified) date. | |
945 | 945 | See [[duration]] for a complete list of supported time intervals. Don't forget |
946 | 946 | to put at least one space character after the date to prevent TaskJuggler from |
947 | 947 | interpreting the interval as an hour. |
1064 | 1064 | @property.set('definitions', @val[1]) |
1065 | 1065 | }) |
1066 | 1066 | doc('definitions', <<"EOT" |
1067 | This attributes controls what definitions will be contained in the report. If | |
1067 | This attribute controls what definitions will be contained in the report. If | |
1068 | 1068 | the list includes ''project'', the generated file will have a ''''.tjp'''' |
1069 | 1069 | extension. Otherwise it will have a ''''.tji'''' extension. |
1070 | 1070 | |
1071 | By default, the report contains everything and the generated files has a ''''.tjp'''' extension. | |
1071 | By default, the report contains everything and the generated files have a ''''.tjp'''' extension. | |
1072 | 1072 | EOT |
1073 | 1073 | ) |
1074 | 1074 | allOrNothingListRule('exportDefinitions', |
1187 | 1187 | descr(<<'EOT' |
1188 | 1188 | Export of the scheduled project in Microsoft Project XML format. This will |
1189 | 1189 | export the data of the fully scheduled project. The exported data include the |
1190 | tasks, resources and the assignments of resources to task. This is only a | |
1190 | tasks, resources and the assignments of resources to tasks. This is only a | |
1191 | 1191 | small subset of the data that TaskJuggler can manage. This export is intended |
1192 | 1192 | to share resource assignment data with other teams using Microsoft Project. |
1193 | TaskJuggler manages assignments with a larger accuracy than the Microsft | |
1193 | TaskJuggler manages assignments with a larger accuracy than the Microsoft | |
1194 | 1194 | Project XML format can represent. This will inevitably lead to some rounding |
1195 | 1195 | errors and different interpretation of the data. The numbers you will see in |
1196 | Project are not necessarily an exact match of the numbers you see in | |
1196 | Microsoft Project are not necessarily an exact match of the numbers you see in | |
1197 | 1197 | TaskJuggler. The XML file format requires the sequence of the tasks in the |
1198 | 1198 | file to follow the work breakdown structure. Hence all user provided sorting |
1199 | 1199 | directions will be ignored for this format. |
1384 | 1384 | |
1385 | 1385 | singlePattern('_inherit') |
1386 | 1386 | doc('inherit.extend', <<'EOT' |
1387 | If the this attribute is used, the property extension will be inherited by | |
1387 | If this attribute is used, the property extension will be inherited by | |
1388 | 1388 | child properties from their parent property. |
1389 | 1389 | EOT |
1390 | 1390 | ) |
1456 | 1456 | operations. The final result of a logical expression is always true or false. |
1457 | 1457 | Logical expressions are used the reduce the properties in a report to a |
1458 | 1458 | certain subset or to select alternatives for the cell content of a table. When |
1459 | used with attributes like [[hidejournalentry]] the logical expression | |
1459 | the logical expression is used with attributes like [[hidejournalentry]] and | |
1460 | 1460 | evaluates to true for a certain property, this property is hidden or rolled-up |
1461 | 1461 | in the report. |
1462 | 1462 | |
1506 | 1506 | }) |
1507 | 1507 | arg(0, 'operand', <<'EOT' |
1508 | 1508 | An operand is a declared flag. An operand can be a negated operand by |
1509 | prefixing a ~ charater or it can be another logical expression enclosed in | |
1509 | prefixing a ~ character or it can be another logical expression enclosed in | |
1510 | 1510 | braces. |
1511 | 1511 | EOT |
1512 | 1512 | ) |
1526 | 1526 | }) |
1527 | 1527 | arg(1, 'operand', <<'EOT' |
1528 | 1528 | An operand is a declared flag. An operand can be a negated operand by |
1529 | prefixing a ~ charater or it can be another logical expression enclosed in | |
1529 | prefixing a ~ character or it can be another logical expression enclosed in | |
1530 | 1530 | braces. |
1531 | 1531 | EOT |
1532 | 1532 | ) |
1581 | 1581 | |
1582 | 1582 | All functions may operate on the current property and the scope property. The |
1583 | 1583 | scope property is the enclosing property in reports with nested properties. |
1584 | Imagine e. g a task report with nested resources. When the function is called | |
1584 | Imagine e. g. a task report with nested resources. When the function is called | |
1585 | 1585 | for a task line, the task is the property and we don't have a scope property. |
1586 | 1586 | When the function is called for a resource line, the resource is the property |
1587 | 1587 | and the enclosing task is the scope property. |
1588 | 1588 | |
1589 | These number of arguments that are passed in brackets to the function depends | |
1589 | The number of arguments that are passed in brackets to the function depends | |
1590 | 1590 | on the specific function. See the reference for details on each function. |
1591 | 1591 | |
1592 | 1592 | All functions can be suffixed with an underscore character. In that case, the |
1593 | 1593 | function is operating on the scope property as if it were the property. The |
1594 | 1594 | original property is ignored in that case. In our task report example from |
1595 | above, calling a function with an appended dash would mean that a task | |
1595 | above, calling a function with an appended underscore would mean that a task | |
1596 | 1596 | line would be evaluated for the enclosing resource. |
1597 | 1597 | |
1598 | 1598 | In the example below you can see how this can be used. To generate a task |
1683 | 1683 | |
1684 | 1684 | pattern(%w( _isongoing _( $ID _) )) |
1685 | 1685 | doc('isongoing', <<'EOT' |
1686 | Will evaluate to true for tasks that overlap with the report period in given | |
1686 | Will evaluate to true for tasks that overlap with the report period in the given | |
1687 | 1687 | scenario. |
1688 | 1688 | EOT |
1689 | 1689 | ) |
1824 | 1824 | pattern(%w( !reportStart )) |
1825 | 1825 | pattern(%w( !rollupresource )) |
1826 | 1826 | pattern(%w( !rolluptask )) |
1827 | pattern(%w( _novevents), lambda { @property.set('novevents', [ true ]) }) | |
1828 | doc('novevents', <<'EOT' | |
1829 | Don't add VEVENT entries to generated [[icalreport]]s. | |
1830 | EOT | |
1831 | ) | |
1827 | 1832 | |
1828 | 1833 | pattern(%w( _scenario !scenarioId ), lambda { |
1829 | 1834 | # Don't include disabled scenarios in the report |
1836 | 1841 | end |
1837 | 1842 | }) |
1838 | 1843 | doc('scenario.ical', <<'EOT' |
1839 | Id of the scenario that should be included in the report. By default, the | |
1840 | top-level scenario will be included. This attribute can be used select another | |
1844 | ID of the scenario that should be included in the report. By default, the | |
1845 | top-level scenario will be included. This attribute can be used to select another | |
1841 | 1846 | scenario. |
1842 | 1847 | EOT |
1843 | 1848 | ) |
1862 | 1867 | # Show all journal entries. |
1863 | 1868 | @property.set('hideJournalEntry', |
1864 | 1869 | LogicalExpression.new(LogicalOperation.new(0))) |
1870 | # Add VEVENT entries to icalreports by default | |
1871 | @property.set('novevents', [ false ]) | |
1865 | 1872 | end |
1866 | 1873 | }) |
1867 | 1874 | arg(1, 'file name', <<'EOT' |
2020 | 2027 | end date without a time is expanded to midnight that day. So the day of the |
2021 | 2028 | end date is not included in the interval! The start and end dates must be separated by a hyphen character. |
2022 | 2029 | |
2023 | In the second form specifies the start date and an interval duration. The | |
2030 | The second form specifies the start date and an interval duration. The | |
2024 | 2031 | duration must be prefixed by a plus character. |
2025 | 2032 | EOT |
2026 | 2033 | ) |
2160 | 2167 | pattern(%w( _alerts_dep ), lambda { :alerts_dep }) |
2161 | 2168 | descr(<<'EOT' |
2162 | 2169 | In this mode only the last entries before the report end date for the context |
2163 | property and all its sub-properties and their dependencies is included. If | |
2170 | property and all its sub-properties and their dependencies are included. If | |
2164 | 2171 | there are multiple entries at the exact same date, then all these entries are |
2165 | 2172 | included. In contrast to the ''''status_down'''' mode, only entries with an |
2166 | 2173 | alert level above the default level, and only those with the highest overall |
2189 | 2196 | during the project. Depending on the context, a journal entry may or may not |
2190 | 2197 | be associated with a specific property or author. |
2191 | 2198 | |
2192 | A journal entry can consists of up to three parts. The headline is mandatory | |
2199 | A journal entry can consist of up to three parts. The headline is mandatory | |
2193 | 2200 | and should be only 5 to 10 words long. The introduction is optional and should |
2194 | 2201 | be only one or two sentences long. All other details should be put into the |
2195 | 2202 | third part. |
2208 | 2215 | @journalEntry.alertLevel = @val[1] |
2209 | 2216 | }) |
2210 | 2217 | doc('alert', <<'EOT' |
2211 | Specify the alert level for this entry. This attribute is inteded to be used for | |
2218 | Specify the alert level for this entry. This attribute is intended to be used for | |
2212 | 2219 | status reporting. When used for a journal entry that is associated with a |
2213 | 2220 | property, the value can be reported in the alert column. When multiple entries |
2214 | 2221 | have been specified for the property, the entry with the date closest to the |
2329 | 2336 | used to report the current annual leave balance. |
2330 | 2337 | |
2331 | 2338 | Leaves outside of the project period are silently ignored and will not be |
2332 | considered in the leave balance calculation. Therefor, leave allowances are | |
2339 | considered in the leave balance calculation. Therefore, leave allowances are | |
2333 | 2340 | only allowed within the project period. |
2334 | 2341 | EOT |
2335 | 2342 | ) |
2351 | 2358 | and intervals may overlap. The leave types have different priorities. A higher |
2352 | 2359 | priority leave type can overwrite a lower priority type. This means that |
2353 | 2360 | resource level leaves can overwrite global leaves when they have a higher |
2354 | priority. A sub resource can overwrite a leave of a enclosing resource. | |
2361 | priority. A sub resource can overwrite a leave of an enclosing resource. | |
2355 | 2362 | |
2356 | 2363 | Leave periods outside of the project interval are silently ignored. For leave |
2357 | 2364 | periods that are partially outside of the project period only the part inside |
2468 | 2475 | doc('dailymin', <<'EOT' |
2469 | 2476 | Minimum required effort for any calendar day. This value cannot be guaranteed by |
2470 | 2477 | the scheduler. It is only checked after the schedule is complete. In case the |
2471 | minium required amount has not been reached, a warning will be generated. | |
2478 | minimum required amount has not been reached, a warning will be generated. | |
2472 | 2479 | EOT |
2473 | 2480 | ) |
2474 | 2481 | example('Limits-1', '4') |
2505 | 2512 | doc('monthlymin', <<'EOT' |
2506 | 2513 | Minimum required effort for any calendar month. This value cannot be |
2507 | 2514 | guaranteed by the scheduler. It is only checked after the schedule is |
2508 | complete. In case the minium required amount has not been reached, a warning | |
2515 | complete. In case the minimum required amount has not been reached, a warning | |
2509 | 2516 | will be generated. |
2510 | 2517 | EOT |
2511 | 2518 | ) |
2524 | 2531 | doc('weeklymin', <<'EOT' |
2525 | 2532 | Minimum required effort for any calendar week. This value cannot be guaranteed by |
2526 | 2533 | the scheduler. It is only checked after the schedule is complete. In case the |
2527 | minium required amount has not been reached, a warning will be generated. | |
2534 | minimum required amount has not been reached, a warning will be generated. | |
2528 | 2535 | EOT |
2529 | 2536 | ) |
2530 | 2537 | end |
2631 | 2638 | A logical expression is a combination of operands and mathematical operations. |
2632 | 2639 | The final result of a logical expression is always true or false. Logical |
2633 | 2640 | expressions are used the reduce the properties in a report to a certain subset |
2634 | or to select alternatives for the cell content of a table. When used with | |
2635 | attributes like [[hidetask]] or [[hideresource]] the logical expression | |
2641 | or to select alternatives for the cell content of a table. When the | |
2642 | logical expression is used with attributes like [[hidetask]] or [[hideresource]] and | |
2636 | 2643 | evaluates to true for a certain property, this property is hidden or rolled-up |
2637 | 2644 | in the report. |
2638 | 2645 | |
2654 | 2661 | the validity first. E. g. to compare the end date of the ''''plan'''' |
2655 | 2662 | scenario with the ''''maxend'''' value use ''''isvalid(plan.maxend) & |
2656 | 2663 | (plan.end > plan.maxend)''''. The ''''&'''' and ''''|'''' operators are lazy. |
2657 | If the result is already known after evaluation the first operand, the second | |
2664 | If the result is already known after evaluation of the first operand, the second | |
2658 | 2665 | operand will not be evaluated any more. |
2659 | 2666 | EOT |
2660 | 2667 | ) |
2689 | 2696 | will expand to ''''This stupid text'''' if called as ''''${FOO "stupid"}''''. |
2690 | 2697 | Macros may call other macros. All macro arguments must be enclosed by double |
2691 | 2698 | quotes. In case the argument contains a double quote, it must be escaped by a |
2692 | slash (''''/''''). | |
2693 | ||
2694 | User defined macro IDs must have at least one uppercase letter as all | |
2699 | backslash (''''\''''). | |
2700 | ||
2701 | User defined macro IDs should start with one uppercase letter as all | |
2695 | 2702 | lowercase letter IDs are reserved for built-in macros. |
2696 | 2703 | |
2697 | 2704 | To terminate the macro definition, the ''''<nowiki>]</nowiki>'''' must be the |
3017 | 3024 | of list attributes is not recommended. User defined attributes are available |
3018 | 3025 | as well. |
3019 | 3026 | |
3020 | An operand can be a negated operand by prefixing a ~ charater or it can be | |
3027 | An operand can be a negated operand by prefixing a ~ character or it can be | |
3021 | 3028 | another logical expression enclosed in braces. |
3022 | 3029 | EOT |
3023 | 3030 | ) |
3036 | 3043 | [ @val[0], @val[1] ] |
3037 | 3044 | }) |
3038 | 3045 | arg(1, 'operand', <<'EOT' |
3039 | An operand can consist of a date, a text string or a numerical value. It can also be the name of a declared flag. Finally, an operand can be a negated operand by prefixing a ~ charater or it can be another operation enclosed in braces. | |
3046 | An operand can consist of a date, a text string or a numerical value. It can also be the name of a declared flag. Finally, an operand can be a negated operand by prefixing a ~ character or it can be another operation enclosed in braces. | |
3040 | 3047 | EOT |
3041 | 3048 | ) |
3042 | 3049 | end |
3074 | 3081 | }) |
3075 | 3082 | arg(0, 'id', <<"EOT" |
3076 | 3083 | An optional ID. If you ever want to reference this property, you must specify |
3077 | your own unique ID. If no ID is specified one will be automatically generated. | |
3084 | your own unique ID. If no ID is specified, one will be automatically generated. | |
3078 | 3085 | These IDs may become visible in reports, but may change at any time. You may |
3079 | 3086 | never rely on automatically generated IDs. |
3080 | 3087 | EOT |
3139 | 3146 | pattern(%w( _niku ), lambda { |
3140 | 3147 | :niku |
3141 | 3148 | }) |
3142 | descr('Generate a XOG XML file to be used with Clarity.') | |
3149 | descr('Generate an XOG XML file to be used with Clarity.') | |
3143 | 3150 | end |
3144 | 3151 | |
3145 | 3152 | def rule_outputFormats |
3237 | 3244 | doc('extend', <<'EOT' |
3238 | 3245 | Often it is desirable to collect more information in the project file than is |
3239 | 3246 | necessary for task scheduling and resource allocation. To add such information |
3240 | to tasks, resources or accounts the user can extend these properties with | |
3247 | to tasks, resources or accounts, the user can extend these properties with | |
3241 | 3248 | user-defined attributes. The new attributes can be of various types such as |
3242 | 3249 | text, date or reference to capture various types of data. Optionally the user |
3243 | 3250 | can specify if the attribute value should be inherited from the enclosing |
3266 | 3273 | arg(1, 'date', 'Alternative date to be used as current date for all ' + |
3267 | 3274 | 'computations') |
3268 | 3275 | |
3276 | pattern(%w( _markdate !date ), lambda { | |
3277 | @project['markdate'] = @val[1] | |
3278 | @scanner.addMacro(TextParser::Macro.new('markdate', @val[1].to_s, | |
3279 | @sourceFileInfo[0])) | |
3280 | @scanner.addMacro(TextParser::Macro.new( | |
3281 | 'today', @val[1].to_s(@project['timeFormat']), @sourceFileInfo[0])) | |
3282 | }) | |
3283 | doc('markdate', <<'EOT' | |
3284 | Specify the reference date that TaskJuggler uses as date that can be specified | |
3285 | and set by the user. It can be used as additional point in time to help with | |
3286 | tracking tasks. If no value is specified, the current value of the system clock is used. | |
3287 | EOT | |
3288 | ) | |
3289 | arg(1, 'date', 'Alternative date to be used as custom date specified by the user') | |
3290 | ||
3269 | 3291 | pattern(%w( !numberFormat ), lambda { |
3270 | 3292 | @project['numberFormat'] = @val[0] |
3271 | 3293 | }) |
3284 | 3306 | }) |
3285 | 3307 | doc('outputdir', |
3286 | 3308 | 'Specifies the directory into which the reports should be generated. ' + |
3287 | 'This will not affect reports whos name start with a slash. This ' + | |
3288 | 'setting can be overwritten by the command line option.') | |
3309 | 'This will not affect reports whose name start with a slash. This ' + | |
3310 | 'setting can be overwritten by the command line option -o or --output-dir.') | |
3289 | 3311 | arg(1, 'directory', 'Path to an existing directory') |
3290 | 3312 | |
3291 | 3313 | pattern(%w( !scenario )) |
3293 | 3315 | @project['shortTimeFormat'] = @val[1] |
3294 | 3316 | }) |
3295 | 3317 | doc('shorttimeformat', |
3296 | 'Specifies time format for time short specifications. This is normal' + | |
3297 | 'just the hour and minutes.') | |
3318 | 'Specifies time format for short time specifications. This is normal ' + | |
3319 | 'just hours and minutes.') | |
3298 | 3320 | arg(1, 'format', 'strftime like format string') |
3299 | 3321 | |
3300 | 3322 | pattern(%w( !timeformat ), lambda { |
3351 | 3373 | tracking scenario and may not have any bookings of their own. The tracking |
3352 | 3374 | scenario must also be specified to use time and status sheet reports. |
3353 | 3375 | |
3354 | The tracking scenario must be defined after all scenario have been defined. | |
3376 | The tracking scenario must be defined after all scenarios have been defined. | |
3355 | 3377 | |
3356 | 3378 | The tracking scenario and all scenarios derived from it will be scheduled in |
3357 | 3379 | projection mode. This means that the scheduler will only add bookings after |
3471 | 3493 | # documentation. |
3472 | 3494 | pattern(%w( !projectPropertiesBody )) |
3473 | 3495 | doc('properties', <<'EOT' |
3474 | The project properties. Every project must consists of at least one task. The other properties are optional. To save the scheduled data at least one output generating property should be used. | |
3496 | The project properties. Every project must consist of at least one task. The other properties are optional. To save the scheduled data at least one output generating property should be used. | |
3475 | 3497 | EOT |
3476 | 3498 | ) |
3477 | 3499 | end |
3488 | 3510 | doc('include.project', <<'EOT' |
3489 | 3511 | Includes the specified file name as if its contents would be written |
3490 | 3512 | instead of the include property. When the included files contains other |
3491 | include statements or report definitions, the filenames are relative to file | |
3513 | include statements or report definitions, the filenames are relative to the file | |
3492 | 3514 | where they are defined in. |
3493 | 3515 | |
3494 | 3516 | This version of the include directive may only be used inside the [[project]] |
3505 | 3527 | Includes the specified file name as if its contents would be written |
3506 | 3528 | instead of the include property. The only exception is the include |
3507 | 3529 | statement itself. When the included files contains other include |
3508 | statements or report definitions, the filenames are relative to file | |
3530 | statements or report definitions, the filenames are relative to the file | |
3509 | 3531 | where they are defined in. |
3510 | 3532 | |
3511 | 3533 | The included file may only contain macro definitions. This version of the |
3666 | 3688 | Includes the specified file name as if its contents would be written |
3667 | 3689 | instead of the include property. The only exception is the include |
3668 | 3690 | statement itself. When the included files contains other include |
3669 | statements or report definitions, the filenames are relative to file | |
3691 | statements or report definitions, the filenames are relative to the file | |
3670 | 3692 | where they are defined in. include commands can be used in the project |
3671 | 3693 | header, at global scope or between property declarations of tasks, |
3672 | 3694 | resources, and accounts. |
3688 | 3710 | end |
3689 | 3711 | if attributeDefinition.scenarioSpecific |
3690 | 3712 | @scenarioIdx = 0 unless @val[1] |
3691 | attr = @property[attrId, 0] | |
3692 | 3713 | else |
3693 | 3714 | if @val[1] |
3694 | 3715 | error('purge_non_sc_spec_attr', |
3695 | 3716 | 'Scenario specified for a non-scenario specific attribute') |
3696 | 3717 | end |
3697 | attr = @property.get(attrId) | |
3698 | 3718 | end |
3699 | 3719 | if @property.attributeDefinition(attrId).scenarioSpecific |
3700 | 3720 | @property.getAttribute(attrId, @scenarioIdx).reset |
3778 | 3798 | EOT |
3779 | 3799 | ) |
3780 | 3800 | |
3801 | singlePattern('_annualleavelist') | |
3802 | descr(<<'EOT' | |
3803 | A list with all annual leave intervals. The list can be customized with the | |
3804 | [[listtype.column|listtype]] attribute. | |
3805 | EOT | |
3806 | ) | |
3807 | ||
3781 | 3808 | singlePattern('_alert') |
3782 | 3809 | descr(<<'EOT' |
3783 | 3810 | The alert level of the property that was reported with the date closest to the |
3801 | 3828 | singlePattern('_alerttrend') |
3802 | 3829 | descr(<<'EOT' |
3803 | 3830 | Shows how the alert level at the end of the report period compares to the |
3804 | alert level at the begining of the report period. Possible values are | |
3831 | alert level at the beginning of the report period. Possible values are | |
3805 | 3832 | ''''Up'''', ''''Down'''' or ''''Flat''''. |
3806 | 3833 | EOT |
3807 | 3834 | ) |
3838 | 3865 | singlePattern('_closedtasks') |
3839 | 3866 | descr(<<'EOT' |
3840 | 3867 | The number of sub-tasks (including the current task) that have been closed |
3841 | during the reported time period. Closed means that they have and end date | |
3868 | during the reported time period. Closed means that they have an end date | |
3842 | 3869 | before the current time or [[now]] date. |
3843 | 3870 | EOT |
3844 | 3871 | ) |
3859 | 3886 | singlePattern('_complete') |
3860 | 3887 | descr(<<'EOT' |
3861 | 3888 | The completion degree of a task. Unless a completion degree is manually |
3862 | provided, this is a computed value relative the [[now]] date of the project. A | |
3889 | provided, this is a computed value relative to the [[now]] date of the project. A | |
3863 | 3890 | task that has ended before the now date is always 100% complete. A task that |
3864 | starts at or after the now date is always 0%. For [[effort]] based task the | |
3891 | starts at or after the now date is always 0%. For [[effort]] based tasks the | |
3865 | 3892 | computation degree is the percentage of done effort of the overall effort. For |
3866 | other leaf task, the completion degree is the percentage of the already passed | |
3867 | duration of the overall task duration. For container task, it's always the | |
3893 | other leaf tasks, the completion degree is the percentage of the already passed | |
3894 | duration of the overall task duration. For container tasks, it's always the | |
3868 | 3895 | average of the direct sub tasks. If the sub tasks consist of a mixture of |
3869 | 3896 | effort and non-effort tasks, the completion value is only of limited value. |
3870 | 3897 | EOT |
3878 | 3905 | descr('Deprecated alias for complete') |
3879 | 3906 | |
3880 | 3907 | singlePattern('_criticalness') |
3881 | descr('A measure for how much effort the resource is allocated for, or' + | |
3882 | 'how strained the allocated resources of a task are') | |
3908 | descr('A measure for how much effort the resource is allocated for, or ' + | |
3909 | 'how strained the allocated resources of a task are.') | |
3883 | 3910 | |
3884 | 3911 | singlePattern('_cost') |
3885 | 3912 | descr(<<'EOT' |
3931 | 3958 | descr(<<'EOT' |
3932 | 3959 | A list of tasks that depend on the current task. The list contains the names, |
3933 | 3960 | the IDs, the date and the type of dependency. For the type the following |
3934 | symbols are used for <nowiki><dep></nowiki>. | |
3961 | symbols are used for <nowiki><dep></nowiki>: | |
3935 | 3962 | |
3936 | 3963 | * '''<nowiki>]->[</nowiki>''': End-to-Start dependency |
3937 | 3964 | * '''<nowiki>[->[</nowiki>''': Start-to-Start dependency |
3940 | 3967 | |
3941 | 3968 | The list can be customized by the [[listitem.column|listitem]] and |
3942 | 3969 | [[listtype.column]] attributes. The dependency symbol can be generated via |
3943 | the ''''dependency'''' attribute inthe query, the target date via the | |
3970 | the ''''dependency'''' attribute in the query, the target date via the | |
3944 | 3971 | ''''date'''' attribute. |
3945 | 3972 | EOT |
3946 | 3973 | ) |
4018 | 4045 | singlePattern('_journal') |
4019 | 4046 | descr(<<'EOT' |
4020 | 4047 | The journal entries for the task or resource for the reported interval. The |
4021 | generated text can be customized with the [[journalmode]], | |
4048 | generated text can be customized with [[journalmode]], | |
4022 | 4049 | [[journalattributes]], [[hidejournalentry]] and [[sortjournalentries]]. If |
4023 | 4050 | used in queries without a property context, the journal for the complete |
4024 | 4051 | project is generated. |
4079 | 4106 | singlePattern('_opentasks') |
4080 | 4107 | descr(<<'EOT' |
4081 | 4108 | The number of sub-tasks (including the current task) that have not yet been |
4082 | closed during the reported time period. Closed means that they have and end | |
4109 | closed during the reported time period. Closed means that they have an end | |
4083 | 4110 | date before the current time or [[now]] date. |
4084 | 4111 | EOT |
4085 | 4112 | ) |
4101 | 4128 | |
4102 | 4129 | The list can be customized by the [[listitem.column|listitem]] and |
4103 | 4130 | [[listtype.column|listtype]] attributes. The dependency symbol can be |
4104 | generated via the ''''dependency'''' attribute inthe query, the target date | |
4131 | generated via the ''''dependency'''' attribute in the query, the target date | |
4105 | 4132 | via the ''''date'''' attribute. |
4106 | 4133 | EOT |
4107 | 4134 | ) |
4363 | 4390 | }) |
4364 | 4391 | doc('height', <<'EOT' |
4365 | 4392 | Set the height of the report in pixels. This attribute is only used for |
4366 | reports that cannot determine the height based on the content. Such report can | |
4393 | reports that cannot determine the height based on the content. Such reports can | |
4367 | 4394 | be freely resized to fit in. The vast majority of reports can determine their |
4368 | 4395 | height based on the provided content. These reports will simply ignore this |
4369 | 4396 | setting. |
4420 | 4447 | @property.set('rawHtmlHead', @val[1]) |
4421 | 4448 | }) |
4422 | 4449 | doc('rawhtmlhead', <<'EOT' |
4423 | Define a HTML fragment that will be inserted at the end of the HTML head | |
4450 | Define an HTML fragment that will be inserted at the end of the HTML head | |
4424 | 4451 | section. |
4425 | 4452 | EOT |
4426 | 4453 | ) |
4484 | 4511 | doc('resourceroot', <<'EOT' |
4485 | 4512 | Only resources below the specified root-level resources are exported. The |
4486 | 4513 | exported resources will have the ID of the root-level resource stripped from |
4487 | their ID, so that the sub-resourcess of the root-level resource become | |
4514 | their ID, so that the sub-resources of the root-level resource become | |
4488 | 4515 | top-level resources in the report file. |
4489 | 4516 | EOT |
4490 | 4517 | ) |
4533 | 4560 | }) |
4534 | 4561 | doc('width', <<'EOT' |
4535 | 4562 | Set the width of the report in pixels. This attribute is only used for |
4536 | reports that cannot determine the width based on the content. Such report can | |
4563 | reports that cannot determine the width based on the content. Such reports can | |
4537 | 4564 | be freely resized to fit in. The vast majority of reports can determine their |
4538 | 4565 | width based on the provided content. These reports will simply ignore this |
4539 | 4566 | setting. |
4795 | 4822 | }) |
4796 | 4823 | doc('resourcereport', <<'EOT' |
4797 | 4824 | The report lists resources and their respective values in a table. The task |
4798 | that are the resources are allocated to can be listed as well. To reduce the | |
4825 | that the resources are allocated to can be listed as well. To reduce the | |
4799 | 4826 | list of included resources, you can use the [[hideresource]], |
4800 | [[rollupresource]] or [[resourceroot]] attributes. The order of the task can | |
4827 | [[rollupresource]] or [[resourceroot]] attributes. The order of the tasks can | |
4801 | 4828 | be controlled with [[sortresources]]. If the first sorting criteria is tree |
4802 | 4829 | sorting, the parent resources will always be included to form the tree. |
4803 | 4830 | Tree sorting is the default. You need to change it if you do not want certain |
4856 | 4883 | efficiency of 5.0. Keep in mind that you cannot track the members of the team |
4857 | 4884 | individually if you use this feature. They always act as a group. |
4858 | 4885 | |
4859 | The other use is to model performance variations between your resources. Again, this is a fairly crude mechanism and should be used with care. A resource that isn't every good at some task might be pretty good at another. This can't be taken into account as the resource efficiency can only set globally for all tasks. | |
4886 | The other use is to model performance variations between your resources. Again, this is a fairly crude mechanism and should be used with care. A resource that isn't very good at some task might be pretty good at another. This can't be taken into account as the resource efficiency can only be set globally for all tasks. | |
4860 | 4887 | |
4861 | 4888 | All resources that do not contribute effort to the task, should have an |
4862 | 4889 | efficiency of 0.0. A typical example would be a conference room. It's necessary for a meeting, but it does not contribute any work. |
4873 | 4900 | pattern(%w( _booking !resourceBooking )) |
4874 | 4901 | doc('booking.resource', <<'EOT' |
4875 | 4902 | The booking attribute can be used to report actually completed work. A task |
4876 | with bookings must be [[scheduling|scheduled]] in ''''asap'''' mode. If the | |
4903 | with bookings must be [[scheduling|scheduled]] in ''''ASAP'''' mode. If the | |
4877 | 4904 | scenario is not the [[trackingscenario|tracking scenario]] or derived from it, |
4878 | 4905 | the scheduler will not allocate resources prior to the current date or the |
4879 | 4906 | date specified with [[now]] when a task has at least one booking. |
4959 | 4986 | @shiftAssignments = nil |
4960 | 4987 | }) |
4961 | 4988 | level(:deprecated) |
4962 | also('shift.resource') | |
4989 | also('shifts.resource') | |
4963 | 4990 | doc('shift.resource', <<'EOT' |
4964 | 4991 | This keyword has been deprecated. Please use [[shifts.resource|shifts |
4965 | 4992 | (resource)]] instead. |
5069 | 5096 | scenarios. A nested scenario uses all attributes from the enclosing scenario |
5070 | 5097 | unless the user has specified a different value for this attribute. |
5071 | 5098 | |
5072 | By default, the scheduler assigns resources to task beginning with the project | |
5099 | By default, the scheduler assigns resources to tasks beginning with the project | |
5073 | 5100 | start date. If the scenario is switched to projection mode, no assignments |
5074 | 5101 | will be made prior to the current date or the date specified by [[now]]. In |
5075 | this case, TaskJuggler assumes, that all assignements prior to the | |
5102 | this case, TaskJuggler assumes, that all assignments prior to the | |
5076 | 5103 | current date have been provided by [[booking.task]] statements. |
5077 | 5104 | EOT |
5078 | 5105 | ) |
5087 | 5114 | }) |
5088 | 5115 | doc('active', <<'EOT' |
5089 | 5116 | Enable the scenario to be scheduled or not. By default, all scenarios will be |
5090 | scheduled. If a scenario is marked as inactive, it not be scheduled and will | |
5117 | scheduled. If a scenario is marked as inactive, it cannot be scheduled and will | |
5091 | 5118 | be ignored in the reports. |
5092 | 5119 | EOT |
5093 | 5120 | ) |
5702 | 5729 | @property = @propertyStack.pop |
5703 | 5730 | }) |
5704 | 5731 | doc('task.statussheet', <<'EOT' |
5705 | Opens the task with the specified ID to add a status report. Child task can be | |
5732 | Opens the task with the specified ID to add a status report. Child tasks can be | |
5706 | 5733 | opened inside this context by specifying their relative ID to this parent. |
5707 | 5734 | EOT |
5708 | 5735 | ) |
6042 | 6069 | ) |
6043 | 6070 | |
6044 | 6071 | singlePattern('$ID') |
6045 | arg(0, 'ID', 'Just the ID of the task without and parent IDs.') | |
6072 | arg(0, 'ID', 'Just the ID of the task without any parent IDs.') | |
6046 | 6073 | |
6047 | 6074 | pattern(%w( !relativeId ), lambda { |
6048 | 6075 | task = @property |
6158 | 6185 | doc('taskreport', <<'EOT' |
6159 | 6186 | The report lists tasks and their respective values in a table. To reduce the |
6160 | 6187 | list of included tasks, you can use the [[hidetask]], [[rolluptask]] or |
6161 | [[taskroot]] attributes. The order of the task can be controlled with | |
6188 | [[taskroot]] attributes. The order of the tasks can be controlled with | |
6162 | 6189 | [[sorttasks]]. If the first sorting criteria is tree sorting, the parent tasks |
6163 | 6190 | will always be included to form the tree. Tree sorting is the default. You |
6164 | 6191 | need to change it if you do not want certain parent tasks to be included in |
6217 | 6244 | pattern(%w( _booking !taskBooking )) |
6218 | 6245 | doc('booking.task', <<'EOT' |
6219 | 6246 | The booking attribute can be used to report actually completed work. A task |
6220 | with bookings must be [[scheduling|scheduled]] in ''''asap'''' mode. If the | |
6247 | with bookings must be [[scheduling|scheduled]] in ''''ASAP'''' mode. If the | |
6221 | 6248 | scenario is not the [[trackingscenario|tracking scenario]] or derived from it, |
6222 | 6249 | the scheduler will not allocate resources prior to the current date or the |
6223 | 6250 | date specified with [[now]] when a task has at least one booking. |
6320 | 6347 | finished. |
6321 | 6348 | |
6322 | 6349 | By using the 'depends' attribute, the scheduling policy is automatically set |
6323 | to asap. If both depends and precedes are used, the last policy counts. | |
6350 | to ASAP. If both depends and precedes are used, the last policy counts. | |
6324 | 6351 | EOT |
6325 | 6352 | ) |
6326 | 6353 | example('Depends1') |
6417 | 6444 | The end attribute provides a guideline to the scheduler when the task should |
6418 | 6445 | end. It will never end later, but it may end earlier when allocated |
6419 | 6446 | resources are not available that long. When an end date is provided for a |
6420 | container task, it will be passed down to ALAP task that don't have a well | |
6447 | container task, it will be passed down to ALAP tasks that don't have a well | |
6421 | 6448 | defined end criteria. |
6422 | 6449 | |
6423 | Setting an end date will implicitely set the scheduling policy for this task | |
6450 | Setting an end date will implicitly set the scheduling policy for this task | |
6424 | 6451 | to ALAP. |
6425 | 6452 | EOT |
6426 | 6453 | ) |
6433 | 6460 | level(:deprecated) |
6434 | 6461 | doc('endcredit', <<'EOT' |
6435 | 6462 | Specifies an amount that is credited to the accounts specified by the |
6436 | [[chargeset]] attributes at the moment the tasks ends. | |
6463 | [[chargeset]] attributes at the moment the task ends. | |
6437 | 6464 | EOT |
6438 | 6465 | ) |
6439 | 6466 | also('charge') |
6465 | 6492 | For the length calculation, the global working hours and the global leaves |
6466 | 6493 | matter unless the task has [[shifts.task|shifts]] assigned. In the latter case |
6467 | 6494 | the working hours and leaves of the shift apply for the specified period to |
6468 | determine if a slot is working time or not. If a resource has additinal | |
6495 | determine if a slot is working time or not. If a resource has additional | |
6469 | 6496 | working hours defined, it's quite possible that a task with a length of 5d |
6470 | 6497 | will have an allocated effort larger than 40 hours. Resource working hours |
6471 | 6498 | only have an impact on whether an allocation is made or not for a particular |
6513 | 6540 | }) |
6514 | 6541 | doc('milestone', <<'EOT' |
6515 | 6542 | Turns the task into a special task that has no duration. You may not specify a |
6516 | duration, length, effort or subtasks for a milestone task. | |
6543 | duration, length, effort or subtask for a milestone task. | |
6517 | 6544 | |
6518 | 6545 | A task that only has a start or an end specification and no duration |
6519 | 6546 | specification, inherited start or end dates, no dependencies or sub tasks, |
6550 | 6577 | level(:deprecated) |
6551 | 6578 | doc('startcredit', <<'EOT' |
6552 | 6579 | Specifies an amount that is credited to the account specified by the |
6553 | [[chargeset]] attributes at the moment the tasks starts. | |
6580 | [[chargeset]] attributes at the moment the task starts. | |
6554 | 6581 | EOT |
6555 | 6582 | ) |
6556 | 6583 | also('charge') |
6565 | 6592 | end |
6566 | 6593 | }) |
6567 | 6594 | doc('precedes', <<'EOT' |
6568 | Specifies that the tasks with the specified IDs cannot start before the task | |
6595 | Specifies that the tasks with the specified IDs cannot start before this task | |
6569 | 6596 | has been finished. If multiple IDs are specified, they must be separated by |
6570 | 6597 | commas. IDs must be either global or relative. A relative ID starts with a |
6571 | 6598 | number of '!'. Each '!' moves the scope to the parent task. Global IDs do not |
6572 | 6599 | contain '!', but have IDs separated by dots. |
6573 | 6600 | |
6574 | 6601 | By using the 'precedes' attribute, the scheduling policy is automatically set |
6575 | to alap. If both depends and precedes are used within a task, the last policy | |
6602 | to ALAP. If both depends and precedes are used within a task, the last policy | |
6576 | 6603 | counts. |
6577 | 6604 | EOT |
6578 | 6605 | ) |
6588 | 6615 | Specifies the priority of the task. A task with higher priority is more |
6589 | 6616 | likely to get the requested resources. The default priority value of all tasks |
6590 | 6617 | is 500. Don't confuse the priority of a tasks with the importance or urgency |
6591 | of a task. It only increases the chances that the tasks gets the requested | |
6618 | of a task. It only increases the chances that the task gets the requested | |
6592 | 6619 | resources. It does not mean that the task happens earlier, though that is |
6593 | 6620 | usually the effect you will see. It also does not have any effect on tasks |
6594 | 6621 | that don't have any resources assigned (e.g. milestones). |
6595 | 6622 | |
6596 | For milestones it will raise or lower the chances that task leading up the | |
6597 | milestone will get their resources over task with equal priority that compete | |
6623 | For milestones, it will raise or lower the chances that tasks leading up the | |
6624 | milestone will get their resources over tasks with equal priority that compete | |
6598 | 6625 | for the same resources. |
6599 | 6626 | |
6600 | 6627 | This attribute is inherited by subtasks if specified prior to the definition |
6612 | 6639 | begin |
6613 | 6640 | @property['projectid', @scenarioIdx] = @val[1] |
6614 | 6641 | rescue AttributeOverwrite |
6615 | # This attribute always overwrites the implicitely provided ID. | |
6642 | # This attribute always overwrites the implicitly provided ID. | |
6616 | 6643 | end |
6617 | 6644 | }) |
6618 | 6645 | doc('projectid.task', <<'EOT' |
6619 | In larger projects it may be desireable to work with different project IDs for | |
6620 | parts of the project. This attribute assignes a new project ID to this task an | |
6646 | In larger projects it may be desirable to work with different project IDs for | |
6647 | parts of the project. This attribute assignes a new project ID to this task and | |
6621 | 6648 | all subsequently defined sub tasks. The project ID needs to be declared first using [[projectid]] or [[projectids]]. |
6622 | 6649 | EOT |
6623 | 6650 | ) |
6661 | 6688 | }) |
6662 | 6689 | doc('scheduling', <<'EOT' |
6663 | 6690 | Specifies the scheduling policy for the task. A task can be scheduled from |
6664 | start to end (As Soon As Possible, asap) or from end to start (As Late As | |
6665 | Possible, alap). | |
6691 | start to end (As Soon As Possible, ASAP) or from end to start (As Late As | |
6692 | Possible, ALAP). | |
6666 | 6693 | |
6667 | 6694 | A task can be scheduled from start to end (ASAP mode) when it has a hard |
6668 | 6695 | (start) or soft (depends) criteria for the start time. A task can be scheduled |
6671 | 6698 | |
6672 | 6699 | Some task attributes set the scheduling policy implicitly. This attribute can |
6673 | 6700 | be used to explicitly set the scheduling policy of the task to a certain |
6674 | direction. To avoid it being overwritten again by an implicit attribute this | |
6701 | direction. To avoid it being overwritten again by an implicit attribute, this | |
6675 | 6702 | attribute should always be the last attribute of the task. |
6676 | 6703 | |
6677 | 6704 | A random mixture of ASAP and ALAP tasks can have unexpected side effects on |
6678 | 6705 | the scheduling of the project. It increases significantly the scheduling |
6679 | 6706 | complexity and results in much longer scheduling times. Especially in projects |
6680 | with many hundreds of tasks the scheduling time of a project with a mixture of | |
6681 | ASAP and ALAP times can be 2 to 10 times longer. When the projects contains | |
6682 | chains of ALAP and ASAP tasks the tasks further down the dependency chain will | |
6683 | be served much later than other non-chained task even when they have a much | |
6707 | with many hundreds of tasks, the scheduling time of a project with a mixture of | |
6708 | ASAP and ALAP times can be 2 to 10 times longer. When the project contains | |
6709 | chains of ALAP and ASAP tasks, the tasks further down the dependency chain will | |
6710 | be served much later than other non-chained tasks, even when they have a much | |
6684 | 6711 | higher priority. This can result in situations where high priority tasks do |
6685 | not get their resources even though the parallel competing tasks have a much | |
6712 | not get their resources, even though the parallel competing tasks have a much | |
6686 | 6713 | lower priority. |
6687 | 6714 | |
6688 | ALAP tasks may not have [[booking.task|bookings]] since the first booked slot | |
6715 | ALAP tasks may not have [[booking.task|bookings]], since the first booked slot | |
6689 | 6716 | determines the start date of the task and prevents it from being scheduled |
6690 | 6717 | from end to start. |
6691 | 6718 | |
6744 | 6771 | Limits the working time for this task during the specified interval |
6745 | 6772 | to the working hours of the given shift. Multiple shifts can be defined, but |
6746 | 6773 | shift intervals may not overlap. This is an additional working time |
6747 | restriction ontop of the working hours of the allocated resources. It does not | |
6774 | restriction on top of the working hours of the allocated resources. It does not | |
6748 | 6775 | replace the resource working hour restrictions. For a resource to be assigned |
6749 | 6776 | to a time slot, both the respective task shift as well as the resource working |
6750 | 6777 | hours must declare the time slot as duty slot. |
6762 | 6789 | The start attribute provides a guideline to the scheduler when the task should |
6763 | 6790 | start. It will never start earlier, but it may start later when allocated |
6764 | 6791 | resources are not available immediately. When a start date is provided for a |
6765 | container task, it will be passed down to ASAP task that don't have a well | |
6792 | container task, it will be passed down to ASAP tasks that don't have a well | |
6766 | 6793 | defined start criteria. |
6767 | 6794 | |
6768 | Setting a start date will implicitely set the scheduling policy for this task | |
6795 | Setting a start date will implicitly set the scheduling policy for this task | |
6769 | 6796 | to ASAP. |
6770 | 6797 | EOT |
6771 | 6798 | ) |
6793 | 6820 | @property = @property.parent |
6794 | 6821 | }) |
6795 | 6822 | doc('textreport', <<'EOT' |
6796 | This report consists of 5 RichText sections, a header, a center section with a | |
6823 | This report consists of 5 [[Rich_Text_Attributes|Rich Text]] sections, a header, a center section with a | |
6797 | 6824 | left and right margin and a footer. The sections may contain the output of |
6798 | 6825 | other defined reports. |
6799 | 6826 | EOT |
6818 | 6845 | arg(1, 'format', <<'EOT' |
6819 | 6846 | Ordinary characters placed in the format string are copied without |
6820 | 6847 | conversion. Conversion specifiers are introduced by a `%' character, and are |
6821 | replaced in s as follows: | |
6848 | replaced as follows: | |
6822 | 6849 | |
6823 | 6850 | * ''''%a'''' The abbreviated weekday name according to the current locale. |
6824 | 6851 | |
6978 | 7005 | |
6979 | 7006 | The intended use for time sheets is to have all resources report a time sheet |
6980 | 7007 | every day, week or month. All time sheets can be added to the project plan. |
6981 | The status information is always used to determin the current status of the | |
7008 | The status information is always used to determine the current status of the | |
6982 | 7009 | project. The [[work]], [[remaining]] and [[end.timesheet|end]] attributes are |
6983 | 7010 | ignored if there are also [[booking.task|bookings]] for the resource in the |
6984 | 7011 | time sheet period. The non-ignored attributes of the time sheets will be |
7013 | 7040 | }) |
7014 | 7041 | doc('newtask', <<'EOT' |
7015 | 7042 | The keyword can be used to request a new task to the project. If the task ID |
7016 | requires further parent task that don't exist yet, these tasks will be | |
7043 | requires further parent tasks that don't exist yet, these tasks will be | |
7017 | 7044 | requested as well. If the task exists already, an error will be generated. The |
7018 | 7045 | newly requested task can be used immediately to report progress and status |
7019 | 7046 | against it. These tasks will not automatically be added to the project plan. |
7147 | 7174 | that are not hidden by [[hideaccount]], [[hideresource]] and [[hidetask]]. By |
7148 | 7175 | default, all properties are excluded. You must provide at least one of the |
7149 | 7176 | ''''hide...'''' attributes to select the properties you want to have included |
7150 | in the report. Please be aware that total number of columns is the product of | |
7177 | in the report. Please be aware that the total number of columns is the product of | |
7151 | 7178 | attributes defined with [[columns]] times the number of included properties. |
7152 | Select you values carefully or you will end up with very large reports. | |
7179 | Select your values carefully or you will end up with very large reports. | |
7153 | 7180 | |
7154 | 7181 | The column headers can be customized by using the [[title.column|title]] |
7155 | 7182 | attribute. When you include multiple properties, these headers are not unique |
7156 | unless you include mini-queries to modify them based on the property they | |
7157 | colum is represeting. You can use the queries | |
7183 | unless you include mini-queries to modify them based on the property the | |
7184 | column is representing. You can use the queries | |
7158 | 7185 | ''''<nowiki><-id-></nowiki>'''', ''''<nowiki><-name-></nowiki>'''', |
7159 | 7186 | ''''<nowiki><-scenario-></nowiki>'''' and |
7160 | 7187 | ''''<nowiki><-attribute-></nowiki>''''. ''''<nowiki><-id-></nowiki>'''' is |
7169 | 7196 | all kinds of values that are being tracked. Report formats that don't support |
7170 | 7197 | a mix of different values will just show the values of the second column. |
7171 | 7198 | |
7172 | The values in the CSV files are fixed units and cannot be formated. Effort | |
7199 | The values in the CSV files are fixed units and cannot be formatted. Effort | |
7173 | 7200 | values are always in resource-days. This allows other software to interpret |
7174 | 7201 | the file without any need for additional context information. |
7175 | 7202 | |
7176 | 7203 | The HTML version generates SVG graphs that are embedded in the HTML page. |
7177 | These graphs are only visble if the web browser supports HTML5. This is true | |
7204 | These graphs are only visible if the web browser supports HTML5. This is true | |
7178 | 7205 | for the latest generation of browsers, but older browsers may not support this |
7179 | 7206 | format. |
7180 | 7207 | EOT |
7186 | 7213 | pattern(%w( _tracereport !optionalID !reportName ), lambda { |
7187 | 7214 | newReport(@val[1], @val[2], :tracereport, @sourceFileInfo[0]) do |
7188 | 7215 | # The top-level always inherits the global timeFormat setting. This is |
7189 | # not desireable in this case, so we ignore this. | |
7216 | # not desirable in this case, so we ignore this. | |
7190 | 7217 | if (@property.level == 0 && !@property.provided('timeFormat')) || |
7191 | 7218 | (@property.level > 0 && !@property.modified?('timeFormat')) |
7192 | 7219 | # CSV readers such of Libre-/OpenOffice can't deal with time zones. We |
7369 | 7396 | }) |
7370 | 7397 | doc('end.timesheet', <<'EOT' |
7371 | 7398 | The expected end date for the task. This can only be used for duration based |
7372 | task. For effort based task [[remaining]] has to be used. | |
7399 | tasks. For effort based tasks [[remaining]] has to be used. | |
7373 | 7400 | EOT |
7374 | 7401 | ) |
7375 | 7402 | example('TimeSheet1', '5') |
7385 | 7412 | }) |
7386 | 7413 | doc('priority.timesheet', <<'EOT' |
7387 | 7414 | The priority is a value between 1 and 1000. It is used to determine the |
7388 | sequence of task when converting [[work]] to [[booking.task|bookings]]. Tasks | |
7415 | sequence of tasks when converting [[work]] to [[booking.task|bookings]]. Tasks | |
7389 | 7416 | that need to finish earlier in the period should have a high priority, tasks |
7390 | 7417 | that end later in the period should have a low priority. For tasks that don't |
7391 | 7418 | get finished in the reported period the priority should be set to 1. |
7399 | 7426 | The remaining effort for the task. This value is ignored if there are |
7400 | 7427 | [[booking.task|bookings]] for the resource that overlap with the time sheet |
7401 | 7428 | period. If there are no bookings, the value is compared with the [[effort]] |
7402 | specification of the task. If there a mismatch between the accumulated effort | |
7429 | specification of the task. If there is a mismatch between the accumulated effort | |
7403 | 7430 | specified with bookings, [[work]] and [[remaining]] on one side and the |
7404 | 7431 | specified [[effort]] on the other, a warning is generated. |
7405 | 7432 | |
7415 | 7442 | @timeSheetRecord.work = @val[1] |
7416 | 7443 | }) |
7417 | 7444 | doc('work', <<'EOT' |
7418 | The amount of time that the resource has spend with the task during the | |
7445 | The amount of time that the resource has spent with the task during the | |
7419 | 7446 | reported period. This value is ignored when there are |
7420 | 7447 | [[booking.task|bookings]] for the resource overlapping with the time sheet |
7421 | 7448 | period. If there are no bookings, TaskJuggler will try to convert the work |
7551 | 7578 | midnight that day. So the day of the end date is not included in the interval! |
7552 | 7579 | The start and end dates must be separated by a hyphen character. |
7553 | 7580 | |
7554 | In the second form specifies the start date and an interval duration. The | |
7581 | The second form specifies the start date and an interval duration. The | |
7555 | 7582 | duration must be prefixed by a plus character. |
7556 | 7583 | EOT |
7557 | 7584 | ) |
7571 | 7598 | doc('warn', <<'EOT' |
7572 | 7599 | The warn attribute adds a [[logicalexpression|logical expression]] to the |
7573 | 7600 | property. The condition described by the logical expression is checked after |
7574 | the scheduling and an warning is generated if the condition evaluates to true. | |
7601 | the scheduling and a warning is generated if the condition evaluates to true. | |
7575 | 7602 | This attribute is primarily intended for testing purposes. |
7576 | 7603 | EOT |
7577 | 7604 | ) |
7707 | 7734 | pattern(%w( !workinghours )) |
7708 | 7735 | doc('workinghours.project', <<'EOT' |
7709 | 7736 | Set the default working hours for all subsequent resource definitions. The |
7710 | standard working hours are 9:00am - 12:00am, 1:00pm - 18:00pm, Monday to | |
7737 | standard working hours are 9:00am - 12:00am, 1:00pm - 6:00pm, Monday to | |
7711 | 7738 | Friday. The working hours specification limits the availability of resources |
7712 | 7739 | to certain time slots of week days. |
7713 | 7740 |
17 | 17 | # This is an extension and modification of the standard String class. We do a |
18 | 18 | # lot of UTF-8 character processing in the parser. Ruby 1.8 does not have good |
19 | 19 | # enough UTF-8 support and Ruby 1.9 only handles UTF-8 characters as Strings. |
20 | # This is very inefficient compared to representing them as Fixnum objects. | |
20 | # This is very inefficient compared to representing them as Integer objects. | |
21 | 21 | # Some of these hacks can be removed once we have switched to 1.9 support |
22 | 22 | # only. |
23 | 23 | class String |
57 | 57 | alias old_double_left_angle << |
58 | 58 | |
59 | 59 | # Replacement for the existing << operator that also works for characters |
60 | # above Fixnum 255 (UTF-8 characters). | |
61 | def << (obj) | |
60 | # above Integer 255 (UTF-8 characters). | |
61 | def <<(obj) | |
62 | 62 | if obj.is_a?(String) || (obj < 256) |
63 | 63 | # In this case we can use the built-in concat. |
64 | 64 | concat(obj) |
16 | 16 | class TaskJuggler |
17 | 17 | |
18 | 18 | # Class to store the working hours for each day of the week. The working hours |
19 | # are stored as Arrays of Fixnum intervals for each day of the week. A day off | |
19 | # are stored as Arrays of Integer intervals for each day of the week. A day off | |
20 | 20 | # is modelled as empty Array for that week day. The start end end times of |
21 | 21 | # each working period are stored as seconds after midnight. |
22 | 22 | class WorkingHours |
99 | 99 | |
100 | 100 | # Set the working hours for a given week day. +dayOfWeek+ must be 0 for |
101 | 101 | # Sunday, 1 for Monday and so on. +intervals+ must be an Array that |
102 | # contains an Array with 2 Fixnums for each working period. Each value | |
102 | # contains an Array with 2 Integers for each working period. Each value | |
103 | 103 | # specifies the time of day as minutes after midnight. The first value is |
104 | 104 | # the start time of the interval, the second the end time. |
105 | 105 | def setWorkingHours(dayOfWeek, intervals) |
132 | 132 | |
133 | 133 | # Return the working hour intervals for a given day of the week. |
134 | 134 | # +dayOfWeek+ must 0 for Sunday, 1 for Monday and so on. The result is an |
135 | # Array that contains Arrays of 2 Fixnums. | |
135 | # Array that contains Arrays of 2 Integers. | |
136 | 136 | def getWorkingHours(dayOfWeek) |
137 | 137 | @days[dayOfWeek] |
138 | 138 | end |
203 | 203 | end |
204 | 204 | |
205 | 205 | def to_s(indent) |
206 | '<!-- ' + @text + " -->\n#{' ' * indent}" | |
206 | '<!-- ' + canonicalize_comment(@text) + " -->\n#{' ' * indent}" | |
207 | end | |
208 | ||
209 | private | |
210 | ||
211 | # It is crucial to canonicalize xml comment text because xml | |
212 | # comment syntax forbids having a -- in the comment body. I | |
213 | # picked emacs's "M-x comment-region" approach of putting a | |
214 | # backslash between the two. | |
215 | def canonicalize_comment(text) | |
216 | new_text = text.gsub("--", "-\\-") | |
217 | new_text | |
207 | 218 | end |
208 | 219 | |
209 | 220 | end |
67 | 67 | |
68 | 68 | def processArguments(argv) |
69 | 69 | super do |
70 | @opts.banner += <<'EOT' | |
70 | @opts.banner.prepend(<<'EOT' | |
71 | 71 | This is the main application. It reads in your project files, schedules the |
72 | 72 | project and generates the reports. |
73 | ||
73 | 74 | EOT |
75 | ) | |
74 | 76 | @opts.on('--debuglevel N', Integer, |
75 | 77 | format("Verbosity of debug output")) do |arg| |
76 | 78 | TaskJuggler::Log.level = arg |
99 | 99 | |
100 | 100 | def processArguments(argv) |
101 | 101 | super do |
102 | @opts.banner += <<'EOT' | |
102 | prebanner = <<'EOT' | |
103 | 103 | The TaskJuggler client is used to send commands and data to the TaskJuggler |
104 | 104 | daemon. The communication is done via TCP/IP. |
105 | 105 | |
124 | 124 | end |
125 | 125 | end |
126 | 126 | args = args.join(' ') |
127 | @opts.banner += " #{cmd[:label] + ' ' + args + tail}" + | |
127 | prebanner += " #{cmd[:label] + ' ' + args + tail}" + | |
128 | 128 | "\n\n#{' ' * 10 + format(cmd[:descr], 10)}\n" |
129 | 129 | end |
130 | @opts.banner.prepend(prebanner) | |
130 | 131 | @opts.on('-p', '--port <NUMBER>', Integer, |
131 | 132 | format('Use the specified TCP/IP port')) do |arg| |
132 | 133 | @port = arg |
41 | 41 | |
42 | 42 | def processArguments(argv) |
43 | 43 | super do |
44 | @opts.banner += <<'EOT' | |
44 | @opts.banner.prepend(<<'EOT' | |
45 | 45 | The TaskJuggler daemon can be used to quickly generate reports for a number |
46 | 46 | of scheduled projects that are resident in memory. Once the daemon has been |
47 | 47 | started tj3client can be used to control it. |
48 | ||
48 | 49 | EOT |
50 | ) | |
49 | 51 | @opts.on('-d', '--dont-daemonize', |
50 | 52 | format("Don't put program into daemon mode. Keep it " + |
51 | 53 | 'connected to the terminal and show debug output.')) do |
35 | 35 | |
36 | 36 | def processArguments(argv) |
37 | 37 | super do |
38 | @opts.banner += <<'EOT' | |
38 | @opts.banner.prepend(<<'EOT' | |
39 | 39 | This program can be used to generate the user manual in HTML format or to get |
40 | 40 | a textual help for individual keywords. |
41 | ||
41 | 42 | EOT |
43 | ) | |
42 | 44 | @opts.on('-d', '--dir <directory>', String, |
43 | 45 | format('directory to put the manual')) do |dir| |
44 | 46 | @directory = dir |
45 | 47 | end |
46 | 48 | @opts.on('--html', |
47 | 49 | format('Show the user manual in your local web browser. ' + |
48 | 'By default, Firefox is used or the brower specified ' + | |
50 | 'By default, Firefox is used or the browser specified ' + | |
49 | 51 | 'with the $BROWSER environment variable.')) do |
50 | 52 | @showHtml = true |
51 | 53 | end |
26 | 26 | |
27 | 27 | def processArguments(argv) |
28 | 28 | super do |
29 | @opts.banner += <<'EOT' | |
29 | @opts.banner.prepend(<<'EOT' | |
30 | 30 | This program can be used to receive filled-out status sheets via email. |
31 | 31 | It reads the emails from STDIN and extracts the status sheet from the |
32 | 32 | attached files. The status sheet is checked for correctness. Good status |
33 | 33 | sheets are filed away. The sender be informed by email that the status |
34 | 34 | sheets was accepted or rejected. |
35 | ||
35 | 36 | EOT |
37 | ) | |
36 | 38 | end |
37 | 39 | end |
38 | 40 |
37 | 37 | |
38 | 38 | def processArguments(argv) |
39 | 39 | super do |
40 | @opts.banner += <<'EOT' | |
40 | @opts.banner.prepend(<<'EOT' | |
41 | 41 | This program can be used to out status sheets templates via email. It will |
42 | 42 | generate status sheet templates for managers of the project. The project data |
43 | 43 | will be accesses via tj3client from a running TaskJuggler server process. |
44 | ||
44 | 45 | EOT |
46 | ) | |
45 | 47 | @opts.on('-r', '--resource <ID>', String, |
46 | 48 | format('Only generate template for given resource')) do |arg| |
47 | 49 | @resourceList << arg |
29 | 29 | |
30 | 30 | def processArguments(argv) |
31 | 31 | super do |
32 | @opts.banner += <<'EOT' | |
32 | @opts.banner.prepend(<<'EOT' | |
33 | 33 | This program can be used to receive filled-out time sheets via email. It |
34 | 34 | reads the emails from STDIN and extracts the time sheet from the attached |
35 | 35 | files. The time sheet is checked for correctness. Good time sheets are filed |
36 | 36 | away. The sender will be informed by email that the time sheets was accepted |
37 | 37 | or rejected. |
38 | ||
38 | 39 | EOT |
40 | ) | |
39 | 41 | end |
40 | 42 | end |
41 | 43 |
36 | 36 | |
37 | 37 | def processArguments(argv) |
38 | 38 | super do |
39 | @opts.banner += <<'EOT' | |
39 | @opts.banner.prepend(<<'EOT' | |
40 | 40 | This program can be used to send out time sheets templates via email. It will |
41 | 41 | generate time sheet templates for all resources of the project. The project |
42 | 42 | data will be accesses via tj3client from a running TaskJuggler server process. |
43 | ||
43 | 44 | EOT |
45 | ) | |
44 | 46 | @opts.on('-r', '--resource <ID>', String, |
45 | 47 | format('Only generate template for given resource')) do |arg| |
46 | 48 | @resourceList << arg |
35 | 35 | |
36 | 36 | def processArguments(argv) |
37 | 37 | super do |
38 | @opts.banner += <<'EOT' | |
38 | @opts.banner.prepend(<<'EOT' | |
39 | 39 | This program can be used to send out individual copies and a summary of all |
40 | 40 | accepted time sheets a list of email addresses. The directory structures for |
41 | 41 | templates and submitted time sheets must be present. The project data will be |
42 | 42 | accesses via tj3client from a running TaskJuggler server process. |
43 | ||
43 | 44 | EOT |
45 | ) | |
44 | 46 | @opts.on('-r', '--resource <ID>', String, |
45 | 47 | format('Only generate summary for given resource')) do |arg| |
46 | 48 | @resourceList << arg |
39 | 39 | |
40 | 40 | def processArguments(argv) |
41 | 41 | super do |
42 | @opts.banner += <<'EOT' | |
42 | @opts.banner.prepend(<<'EOT' | |
43 | 43 | The TaskJuggler web server can be used to serve the HTTP reports of |
44 | 44 | TaskJuggler projects to be viewed by any HTML5 compliant web browser. It uses |
45 | 45 | the TaskJuggler daemon (tj3d) for data hosting and report generation. |
46 | ||
46 | 47 | EOT |
48 | ) | |
47 | 49 | @opts.on('-d', '--dont-daemonize', |
48 | 50 | format("Don't put program into daemon mode. Keep it " + |
49 | 51 | 'connected to the terminal and show debug output.')) do |
36 | 36 | # We can't clone frozen objects. So just return a reference to them. |
37 | 37 | # Built-in classed can't be cloned either. The check below is probably |
38 | 38 | # cheaper than the frequent (hiddent) exceptions from those objects. |
39 | return self if frozen? || nil? || is_a?(Fixnum) || is_a?(Float) || | |
39 | return self if frozen? || nil? || is_a?(Integer) || is_a?(Float) || | |
40 | 40 | is_a?(TrueClass) || is_a?(FalseClass) || is_a?(Symbol) |
41 | 41 | |
42 | 42 | # In case we have loops in our graph, we return references, not |
156 | 156 | end |
157 | 157 | when :fieldEnd |
158 | 158 | # We've completed processing a field. Add the field to the list of |
159 | # fields. Convert Fixnums and Floats in native types. | |
159 | # fields. Convert Integers and Floats in native types. | |
160 | 160 | fields << unMarshal(field, quoted) |
161 | 161 | |
162 | 162 | if c == "\n" |
197 | 197 | if str.nil? |
198 | 198 | nil |
199 | 199 | elsif /^[-+]?\d+$/ =~ str |
200 | # field is a Fixnum | |
200 | # field is an Integer | |
201 | 201 | str.to_i |
202 | 202 | elsif /^[-+]?\d*\.?\d+([eE][-+]?\d+)?$/ =~ str |
203 | 203 | # field is a Float |
215 | 215 | def marshal(field) |
216 | 216 | if field.nil? |
217 | 217 | '' |
218 | elsif field.is_a?(Fixnum) || field.is_a?(Float) || field.is_a?(Bignum) | |
218 | elsif field.is_a?(Integer) || field.is_a?(Float) | |
219 | 219 | # Numbers don't have to be quoted. |
220 | 220 | field.to_s |
221 | 221 | else |
162 | 162 | |
163 | 163 | @yMinDate = cell if @yMinDate.nil? || cell < @yMinDate |
164 | 164 | @yMaxDate = cell if @yMaxDate.nil? || cell > @yMaxDate |
165 | elsif cell.is_a?(Fixnum) || cell.is_a?(Float) | |
165 | elsif cell.is_a?(Integer) || cell.is_a?(Float) | |
166 | 166 | if @dataType && @dataType != :number |
167 | 167 | error("Column #{colIdx} contains non-number (#{cell}). " + |
168 | 168 | "The columns will be ignored.") |
34 | 34 | include HTMLGraphics |
35 | 35 | |
36 | 36 | attr_reader :start, :end, :now, :weekStartsMonday, :header, :width, |
37 | :scale, :scales, :table | |
37 | :scale, :scales, :table, :markdate | |
38 | 38 | attr_writer :viewWidth |
39 | 39 | |
40 | 40 | # Create the GanttChart object, but don't do much right now. We still need |
42 | 42 | # is the date that should be used as current date. _weekStartsMonday_ is |
43 | 43 | # true if the weeks should start on Mondays instead of Sundays. _table_ is a |
44 | 44 | # reference to the TableReport that the chart is part of. |
45 | def initialize(now, weekStartsMonday, columnDef, table = nil) | |
45 | def initialize(now, weekStartsMonday, columnDef, table = nil, markdate = nil) | |
46 | 46 | # The start and end dates of the reported interval. |
47 | 47 | @start = nil |
48 | 48 | @end = nil |
49 | 49 | @now = now |
50 | 50 | @columnDef = columnDef |
51 | 51 | @table = table |
52 | @markdate = markdate | |
52 | 53 | |
53 | 54 | # This defines the possible horizontal scales that the Gantt chart can |
54 | 55 | # have. The scales differ in their resolution and the amount of detail |
255 | 256 | # Also protect the current date line from other vertical lines. |
256 | 257 | @router.addZone(@header.nowLineX - 1, 0, 3, @height - 1, false, true) |
257 | 258 | |
259 | # Protect the date set in custom reference line from other vertical lines. | |
260 | if @header.markdateLineX | |
261 | @router.addZone(@header.markdateLineX - 1, 0, 3, @height - 1, false, true) | |
262 | end | |
263 | ||
258 | 264 | # Generate the dependency arrows for all visible tasks. |
259 | 265 | @tasks.each do |task, lines| |
260 | 266 | generateDepLines(task, lines) |
20 | 20 | # holds the small scale (e. g. week or day). |
21 | 21 | class GanttHeader |
22 | 22 | |
23 | attr_reader :gridLines, :nowLineX, :cellStartDates | |
23 | attr_reader :gridLines, :nowLineX, :cellStartDates, :markdateLineX | |
24 | 24 | attr_accessor :height |
25 | 25 | |
26 | 26 | # Create a GanttHeader object and generate the scales for the header. |
37 | 37 | |
38 | 38 | # X coordinate of the "now" line. nil if "now" is off-chart. |
39 | 39 | @nowLineX = nil |
40 | ||
41 | # X coordinate of the custom "markdate" line with date specified by user. | |
42 | # nil if "markdate" is off-chart. | |
43 | @markdateLineX = nil | |
40 | 44 | |
41 | 45 | # The x coordinates and width of the cells created by the small scale. The |
42 | 46 | # values are stored as [ x, w ]. |
102 | 106 | |
103 | 107 | nlx = @chart.dateToX(@chart.now) |
104 | 108 | @nowLineX = nlx if nlx |
109 | ||
110 | if @chart.markdate | |
111 | flx = @chart.dateToX(@chart.markdate) | |
112 | @markdateLineX = flx if flx | |
113 | end | |
114 | ||
105 | 115 | end |
106 | 116 | |
107 | 117 | # Generate the actual scale cells. |
48 | 48 | @y = y + chart.header.height + 1 |
49 | 49 | # The height of the line in screen pixels. |
50 | 50 | @height = height |
51 | ||
51 | 52 | # The index of the line in the chart. It starts with 0 and is |
52 | 53 | # incremented for each line by one. |
53 | 54 | @lineIndex = lineIndex |
92 | 93 | # Render the 'now' line |
93 | 94 | if @chart.header.nowLineX |
94 | 95 | div << rectToHTML(@chart.header.nowLineX, 0, 1, @height, 'nowline') |
96 | end | |
97 | ||
98 | # Render the 'markdate' line | |
99 | if @chart.header.markdateLineX | |
100 | div << rectToHTML(@chart.header.markdateLineX, 0, 1, @height, 'markdateline') | |
95 | 101 | end |
96 | 102 | |
97 | 103 | div |
95 | 95 | |
96 | 96 | # Generate an additional VEVENT entry for all leaf tasks that aren't |
97 | 97 | # milestones. |
98 | if task.leaf? && !task['milestone', scenarioIdx] | |
98 | if task.leaf? && !task['milestone', scenarioIdx] && @report.get('novevents') == [false] | |
99 | 99 | event = ICalendar::Event.new( |
100 | 100 | @ical, "#{task['projectid', scenarioIdx]}-#{task.fullId}", |
101 | 101 | task.name, task['start', scenarioIdx], task['end', scenarioIdx]) |
296 | 296 | if @name == '.' |
297 | 297 | $stdout.write(@content.to_tjp) |
298 | 298 | else |
299 | fileName = absoluteFileName(@name) | |
299 | fileName = @name | |
300 | 300 | fileName += a('definitions').include?('project') ? '.tjp' : '.tji' |
301 | 301 | File.open(fileName, 'w') { |f| f.write(@content.to_tjp) } |
302 | 302 | end |
59 | 59 | @alignment = :center |
60 | 60 | # Horizontal padding between frame and cell content |
61 | 61 | @padding = 3 |
62 | # Whether or not to indent the cell. If not nil, it is a Fixnum | |
62 | # Whether or not to indent the cell. If not nil, it is an Integer | |
63 | 63 | # indicating the indentation level. |
64 | 64 | @indent = nil |
65 | 65 | # The basename of the icon file |
31 | 31 | 'activetasks' => [ 'Active Tasks', true, :right, true ], |
32 | 32 | 'annualleave' => [ 'Annual Leave', true, :right, true ], |
33 | 33 | 'annualleavebalance'=> [ 'Annual Leave Balance', false, :right, true ], |
34 | 'annualleavelist' => [ 'Annual Leave List', false, :left, true ], | |
34 | 35 | 'alert' => [ 'Alert', true, :left, false ], |
35 | 36 | 'alertmessages' => [ 'Alert Messages', false, :left, false ], |
36 | 37 | 'alertsummaries' => [ 'Alert Summaries', false, :left, false ], |
78 | 79 | @@propertiesByType = { |
79 | 80 | # Type Indent Align |
80 | 81 | DateAttribute => [ false, :left ], |
81 | FixnumAttribute => [ false, :right ], | |
82 | IntegerAttribute => [ false, :right ], | |
82 | 83 | FloatAttribute => [ false, :right ], |
83 | 84 | ResourceListAttribute => [ false, :left ], |
84 | 85 | RichTextAttribute => [ false, :left ], |
337 | 338 | when 'chart' |
338 | 339 | # For the 'chart' column we generate a GanttChart object. The sizes are |
339 | 340 | # set so that the lines of the Gantt chart line up with the lines of the |
340 | # table. | |
341 | # table | |
341 | 342 | gantt = GanttChart.new(a('now'), |
342 | a('weekStartsMonday'), columnDef, self) | |
343 | a('weekStartsMonday'), columnDef, self, a('markdate')) | |
343 | 344 | |
344 | 345 | gantt.generateByScale(rStart, rEnd, columnDef.scale) |
345 | 346 | # The header consists of 2 lines separated by a 1 pixel boundary. |
866 | 867 | # the next cell. |
867 | 868 | def genCalChartTaskCell(query, line, columnDef, t, sameTimeNextFunc) |
868 | 869 | task = line.property |
869 | # Find out if we have an enclosing resource scope. | |
870 | if line.scopeLine && line.scopeLine.property.is_a?(Resource) | |
871 | resource = line.scopeLine.property | |
872 | else | |
873 | resource = nil | |
874 | end | |
875 | 870 | |
876 | 871 | # Get the interval of the task. In case a date is invalid due to a |
877 | 872 | # scheduling problem, we use the full project interval. |
1047 | 1042 | 'busy' |
1048 | 1043 | elsif workLoad > 0.0 && freeLoad > 0.0 |
1049 | 1044 | 'loaded' |
1050 | elsif workLoad == 0.0 && freeLoad > 0.0 | |
1051 | 'free' | |
1052 | else | |
1045 | elsif workLoad == 0.0 && freeLoad == 0.0 | |
1053 | 1046 | cell.tooltip = nil |
1054 | 1047 | 'offduty' |
1048 | else | |
1049 | 'free' | |
1055 | 1050 | end |
1056 | 1051 | end |
1057 | 1052 | cell.category += line.subLineNo % 2 == 1 ? '1' : '2' |
264 | 264 | if isLeafTask |
265 | 265 | a('scenarios').each do |scenarioIdx| |
266 | 266 | generateAttribute(task, 'start', indent + 2, scenarioIdx) |
267 | if task['milestone', scenarioIdx] | |
268 | if task['scheduled', scenarioIdx] | |
269 | generateAttributeText('milestone', indent + 2, scenarioIdx) | |
270 | end | |
271 | else | |
267 | if !task['milestone', scenarioIdx] | |
272 | 268 | generateAttribute(task, 'end', indent + 2, scenarioIdx) |
273 | 269 | generateAttributeText('scheduling ' + |
274 | 270 | (task['forward', scenarioIdx] ? |
0 | VERSION = '3.7.1' |
3 | 3 | |
4 | 4 | To analyze the impact that a small variation can have on a project, |
5 | 5 | TaskJuggler supports an unlimited amount of scenarios. Each |
6 | additional scenario is a slight derivation of the it's parent. The | |
6 | additional scenario is a slight derivation of it's parent. The | |
7 | 7 | task tree structure needs to be the same for all scenarios, but most |
8 | 8 | attributes can vary from one scenario to another. Several report |
9 | 9 | types support comparative listing of multiple [[scenarios]]. |
222 | 222 | contributors that have not submitted their report. |
223 | 223 | |
224 | 224 | # On Monday the project managers need to review the time sheets and |
225 | update the plan accordingly. TaskJuggler can compile a list changes | |
225 | update the plan accordingly. TaskJuggler can compile a list of changes | |
226 | 226 | compared to the plan. This makes it easy to update the plan according |
227 | 227 | to the actual progress that was made. The closer the actuals match the |
228 | 228 | plan the less work this is. The project managers now generate |
229 | 229 | bookings for the last week and add them to the database with previous |
230 | bookings. Doing so, will prevent changes to the plan to affect the | |
230 | bookings. Doing so will prevent changes to the plan to affect the | |
231 | 231 | past. Only the future will be modified. |
232 | 232 | |
233 | 233 | # Once the plan has been updated, managers will receive their status |
695 | 695 | |
696 | 696 | When you run ''''tj3 --freeze'''' again, it will update the header |
697 | 697 | and booking files. Since you have included your booking file, any |
698 | modifications you have made, will be preserved. That is, the actual | |
698 | modifications you have made will be preserved. That is, the actual | |
699 | 699 | data will be preserved, not the formatting since the file will be |
700 | 700 | completely re-generated again. |
701 | 701 | |
721 | 721 | report template. Each manager will get one template that includes the |
722 | 722 | status reports for the tasks they are responsible for. |
723 | 723 | |
724 | It's not the managers task to prepare the report for the next level | |
724 | It's the managers task to prepare the report for the next level | |
725 | 725 | of management. To do this, the manager has 3 options: |
726 | 726 | |
727 | 727 | * Forward the status report of a task directly to the next level. The |
728 | original authorship can be keep or removed. The content can also be | |
728 | original authorship can be kept or removed. The content can also be | |
729 | 729 | edited if needed. |
730 | 730 | |
731 | 731 | * Similar reports for a task or a whole task sub-tree can be combined |
746 | 746 | ==== The Status Sheet Template Sender ==== |
747 | 747 | |
748 | 748 | To send out the time sheets, the command ''''tj3ts_sender'''' must be |
749 | used. It will use the ''''tj3client'''' program to do retrieve the | |
749 | used. It will use the ''''tj3client'''' program to retrieve the | |
750 | 750 | necessary data from the TaskJuggler server. |
751 | 751 | |
752 | 752 | Before the program can be used, a new section must be added to the |
812 | 812 | |
813 | 813 | ==== The Status Sheet Receiver ==== |
814 | 814 | |
815 | Similarly to the time sheets a the completed status sheets must be | |
815 | Similarly to the time sheets, the completed status sheets must be | |
816 | 816 | send back by email. We already described how the necessary email |
817 | 817 | aliases should be configured. For status sheets the address |
818 | 818 | ''''statussheets@taskjuggler.your_company.com'''' can be used. |
87 | 87 | you can also install it into your home or data directory. This does |
88 | 88 | not require root or admin permissions. |
89 | 89 | |
90 | The following steps are describe the installation on a Linux system | |
90 | The following steps describe the installation on a Linux system | |
91 | 91 | with the bash shell. You may have to use slightly different commands |
92 | 92 | on a different operating system. |
93 | 93 | |
118 | 118 | The last two settings should also be added to your .profile file to |
119 | 119 | make them permanent. |
120 | 120 | |
121 | That's it. You now should be run TaskJuggler. | |
121 | That's it. You now should run TaskJuggler. | |
122 | 122 | |
123 | 123 | tj3 --version |
124 | 124 | |
186 | 186 | |
187 | 187 | git clone git@github.com/taskjuggler/TaskJuggler.git |
188 | 188 | |
189 | Make sure, you have removed all previously installed instances of | |
189 | Make sure you have removed all previously installed instances of | |
190 | 190 | TaskJuggler from your system before doing so. It is a common mistake |
191 | 191 | to have an old version of the TaskJuggler installed and then use parts |
192 | 192 | of the old and new version together. |
322 | 322 | |
323 | 323 | which ruby |
324 | 324 | |
325 | should show return the path to the link to your | |
325 | should return the path to the link to your | |
326 | 326 | ''''${HOME}/bin/ruby''''. You now have the latest Ruby installed and |
327 | 327 | are ready to use TaskJuggler. |
328 | 328 | |
342 | 342 | file editing. If you don't have a preference yet, we recommend to try |
343 | 343 | the [http://www.vim.org Vim] text editor. It's a very powerful editor |
344 | 344 | and it has been customized for better integration with TaskJuggler. |
345 | This section describes, how to activate and use the Vim integration. | |
345 | This section describes how to activate and use the Vim integration. | |
346 | 346 | Vim is provided by pretty much any Linux distribution and also works |
347 | 347 | well on MacOX and Windows. See the web page for how to install it if |
348 | 348 | you don't have it yet. |
365 | 365 | |
366 | 366 | cp `gem contents taskjuggler | fgrep tjp.vim` .vim/syntax |
367 | 367 | |
368 | Now we have to make sure, Vim detects the file. Edit the | |
368 | Now we have to make sure Vim detects the file. Edit the | |
369 | 369 | ''''.vim/filetype.vim'''' file to contain the following section. |
370 | 370 | |
371 | 371 | augroup filetypedetect |
28 | 28 | ''''f2'''' assigned. |
29 | 29 | |
30 | 30 | The same works for scenarios as well. Even though the syntax may not |
31 | look like inheritance is at play the scenario ''''s2'''' inherits all | |
31 | look like inheritance is at play, the scenario ''''s2'''' inherits all | |
32 | 32 | values from ''''s1''''. |
33 | 33 | |
34 | 34 | <[example file="ListAttributes" tag="scenario"]> |
125 | 125 | You can also insert raw HTML code by enclosing it in |
126 | 126 | '''<nowiki><html>...</html></nowiki>''' tags. For all other output |
127 | 127 | formats, this content will be ignored. There is also no error checking |
128 | if the code is valid! Use this feature very carefully. | |
128 | whether the code is valid! Use this feature very carefully. | |
129 | 129 | |
130 | 130 | ==== Block and Inline Generators ==== |
131 | 131 | |
178 | 178 | |
179 | 179 | * ''''attributes'''': A set of attributes that override the original |
180 | 180 | attributes of the referenced report. All report attributes |
181 | are supported. Since the value of attributes already must be enclosed | |
181 | are supported. Since the values of attributes already must be enclosed | |
182 | 182 | by single or double quotes, all single or double quotes contained in |
183 | 183 | the string must be escaped with backslashes. This feature enables |
184 | 184 | reports with content that is customized based on where they have been |
185 | 185 | referenced from. It requires the reports to be dynamically generated |
186 | and is only available when used with the ''''tj3d'''' web server. | |
186 | and is only available when used with the ''''tj3d'''' web server | |
187 | ''''tj3webd''''. | |
187 | 188 | The ''''tj3'''' application will ignore the attributes setting. |
188 | 189 | |
189 | 190 | taskreport "All" { |
253 | 254 | predefined values. When used in the header section of a report, the |
254 | 255 | context does not provide a property or scope property. Start and end |
255 | 256 | dates as well the formatting options are taken from the report |
256 | context. But when used e. g. in [[celltext.column]] the cell | |
257 | provides, that property and the attribute and possibly even the scope | |
257 | context. But when used e. g. in [[celltext.column]], the cell | |
258 | provides that property and the attribute and possibly even the scope | |
258 | 259 | property. |
259 | 260 | |
260 | 261 |
0 | 0 | == The TaskJuggler Software == |
1 | 1 | |
2 | After the installation of a software package the first questions that | |
2 | After the installation of a software package the first question that | |
3 | 3 | most users have is ''"How do I run it?"''. Many users expect to find |
4 | 4 | an icon on their desktop or an entry in the start menu hierarchy. |
5 | 5 | Don't bother looking for them, you won't find any for TaskJuggler. As |
79 | 79 | |
80 | 80 | The latter defaults to using the |
81 | 81 | [http://www.mozilla.com/en-US/firefox/new/ Mozilla Firefox] web |
82 | browser . Please see | |
82 | browser. Please see | |
83 | 83 | |
84 | 84 | tj3man --help |
85 | 85 | |
101 | 101 | automatically disconnects from the terminal and runs in the |
102 | 102 | background. All interactions with the server are done via the TCP/IP |
103 | 103 | protocol. For security reasons, only connections from the same |
104 | machine (localhost) are accepted. To get access all clients must | |
104 | machine (localhost) are accepted. To get access, all clients must | |
105 | 105 | provide an authentication key. A TaskJuggler server can serve any |
106 | 106 | number of projects. Once a project has been loaded successfully, |
107 | 107 | clients can retrieve the data in form of reports. Projects are |
108 | 108 | identified by their project ID. If a newly added project has the same |
109 | ID such as an already loaded project, the new project will replace | |
109 | ID as an already loaded project, the new project will replace | |
110 | 110 | the old project once it was scheduled successfully. Before you start |
111 | 111 | the server, you need to provide a configuration file with some basic |
112 | 112 | settings. |
146 | 146 | * 3: Like 2, but additionally with information messages |
147 | 147 | * 4: Like 3, but additionally with debug messages |
148 | 148 | |
149 | The configuration file will be searched in the current directory, | |
149 | The configuration file will be searched for in the current directory, | |
150 | 150 | the current user's home directory or ''''/etc''''. You can also |
151 | 151 | explicitly tell the server where to find the configuration file with |
152 | 152 | the ''''-c'''' option. See |
209 | 209 | authKey: topsecret |
210 | 210 | webServerPort: 8080 |
211 | 211 | |
212 | To access the HTML reports point your web browser to | |
212 | To access the HTML reports, point your web browser to | |
213 | 213 | ''''http://localhost:8080/taskjuggler''''. This assumes that the |
214 | 214 | server is running on your local machine. You will then see a list of |
215 | 215 | all loaded projects. Click on the project name to get a list of all |
25 | 25 | The scheduler needs to determine the start and end date for all tasks |
26 | 26 | that don't have such dates yet. To deal with multiple concurrent time |
27 | 27 | zones, all time related events are stored internally as UTC |
28 | time.Additionally, it allocates resources to tasks. All events such | |
28 | time. Additionally, it allocates resources to tasks. All events such | |
29 | 29 | as start or end of a task, or allocation of a resource can only happen |
30 | 30 | aligned with the [[timingresolution|timing resolution]]. This |
31 | 31 | determines the smallest possible allocation period that we call a time |
56 | 56 | resources have been assigned for all time slots. |
57 | 57 | |
58 | 58 | The goal of the scheduler is to transfer all tasks in the completed |
59 | state. Until this goal has been reached, at least one tasks needs to | |
59 | state. Until this goal has been reached, at least one task needs to | |
60 | 60 | be in the ready state. If that's not the case, the project schedule |
61 | 61 | cannot be determined and an error is raised. In case there are more |
62 | 62 | than one task in the ready state, we need to have a well defined |
102 | 102 | the tasks of the path is computed. The largest sum is the path |
103 | 103 | criticalness of that task. |
104 | 104 | |
105 | This heuristic will favor allocations to task with critical resources | |
105 | This heuristic will favor allocations to tasks with critical resources | |
106 | 106 | and long dependency chains. As a result, the critical paths of the |
107 | 107 | project are tried to be kept short. The user can use the |
108 | 108 | '''criticalness''' and '''pathcriticalness''' [[columnid|columns]] to |
110 | 110 | |
111 | 111 | When the criticalness and pathcriticalness for all leaf resources and |
112 | 112 | tasks has been determined, the leaf tasks are sorted by priority |
113 | (hight to low), then by pathcricialness (high to low) and then by the | |
113 | (high to low), then by pathcricialness (high to low) and then by the | |
114 | 114 | index (low to high). In a loop that is terminated when all tasks have |
115 | 115 | been scheduled or an error condition has been detected, the first |
116 | 116 | task that is ready for scheduling is completely scheduled. This means |
33 | 33 | keyword ( foo | bar | foobar ) |
34 | 34 | |
35 | 35 | Some keywords take one or more arguments. These are known as list |
36 | attributes. The arguments are comma separated. The tree dots in the | |
36 | attributes. The arguments are comma separated. The three dots in the | |
37 | 37 | syntax description mean that the sequence before the dots can be |
38 | 38 | repeated if needed. Inheritable list attributes will append the new |
39 | 39 | list values to the inherited list. Use can use the [[purge]] |
72 | 72 | |
73 | 73 | Strings are character sequences that are enclosed by special |
74 | 74 | character marks. There are three different marks supported. For |
75 | short strings that fit on one lines, you can either use single or | |
75 | short strings that fit on one line, you can either use single or | |
76 | 76 | double quotes. |
77 | 77 | |
78 | 78 | 'This is a single quoted string.' |
111 | 111 | === Predefined Macros === |
112 | 112 | |
113 | 113 | TaskJuggler supports a few predefined macros. These are available |
114 | after the project header. They values correspond to the values | |
114 | after the project header. Their values correspond to the values | |
115 | 115 | provided in the project header. |
116 | 116 | |
117 | 117 | * ''''projectstart'''' The start date of the project. |
127 | 127 | === Environment Variable Expansions === |
128 | 128 | |
129 | 129 | By using the $(VAR) syntax, you can insert the value of the |
130 | environment variable name VAR. The name of the variable must consists | |
131 | only of uppercase ASCII letters, underscore or decimal digits. | |
130 | environment variable name VAR. The name of the variable must consist | |
131 | only of uppercase ASCII letters, underscores or decimal digits. | |
132 | 132 |
12 | 12 | TaskJuggler software installation. You can use the following command |
13 | 13 | to find the base directory of the example projects. |
14 | 14 | |
15 | ruby19 -e "puts Gem::Specification.find_by_name('taskjuggler').gem_dir" | |
15 | ruby -e "puts Gem::Specification.find_by_name('taskjuggler').gem_dir" | |
16 | 16 | |
17 | 17 | The file for the tutorial project is called |
18 | 18 | ''''examples/Tutorial/tutorial.tjp''''. You can use any plain text |
30 | 30 | |
31 | 31 | <[example file="tutorial" tag="header1"]> |
32 | 32 | |
33 | All TaskJuggler properties have a unique ID ,a name, and a set of | |
33 | All TaskJuggler properties have a unique ID, a name, and a set of | |
34 | 34 | optional attributes. The name must always be specified. The ID can be |
35 | 35 | omitted if you never have to reference the property from another |
36 | 36 | context. If you omit the ID, TaskJuggler will automatically generate a |
74 | 74 | <[example file="tutorial" tag="currency"]> |
75 | 75 | |
76 | 76 | Because each culture has its own way of specifying dates and numbers, |
77 | the format for these are configurable. Use the [[timeformat]] | |
77 | the format for these is configurable. Use the [[timeformat]] | |
78 | 78 | attribute to specify the default format for dates. This format is used |
79 | 79 | for reports, it does not affect the way you specify dates in the |
80 | 80 | project files. Here you always need to use the [[date|TaskJuggler date |
147 | 147 | |
148 | 148 | Use the [[leaves]] attribute to define a global holiday. Global |
149 | 149 | holidays may have a name and must have a date or date range. Other leaves for |
150 | individual resources or groups of resources can be defines similarly. | |
150 | individual resources or groups of resources can be defined similarly. | |
151 | 151 | |
152 | 152 | === Macros === |
153 | 153 | |
188 | 188 | [[account|accounts]] to credit the amounts to. We create one account |
189 | 189 | for the development costs, one for the documentation costs, and one |
190 | 190 | for the customer payments. |
191 | Actually, there is a fourth account consisting of two accounts nested | |
192 | into it. | |
191 | 193 | |
192 | 194 | <[example file="tutorial" tag="accounts"]> |
193 | 195 | |
307 | 309 | resources could be allocated long enough to reach the specified |
308 | 310 | effort. Tasks with ''''length'''' or ''''duration'''' criteria and |
309 | 311 | allocated resources will last exactly as long as requested. Resources |
310 | will be allocated only if available. It's possible that such a tasks | |
312 | will be allocated only if available. It's possible that such a task | |
311 | 313 | ends up with no allocations at all if the resources are always |
312 | 314 | assigned to other tasks for that period. Each task can only have one |
313 | 315 | of the three duration criteria. Container tasks may never have a |
330 | 332 | specification. The start and end criteria can either be fixed dates or |
331 | 333 | relative dates. Relative dates are specifications of the type ''task B |
332 | 334 | starts after task A has finished''. Or in other words, task B depends |
333 | on task A. In this example the spec task depends on a subtasks of the | |
335 | on task A. In this example the spec task depends on a subtask of the | |
334 | 336 | deliveries task. We have not specified it yet, but it has the local ID |
335 | 337 | ''''start''''. |
336 | 338 | |
346 | 348 | Relative IDs always start with one or more exclamation marks. Each |
347 | 349 | exclamation mark moves the scope to the next enclosing task. So |
348 | 350 | ''''!deliveries.start'''' is expanded to ''''AcSo.deliveries.start'''' |
349 | since ''''AcSo'''' is the enclosing task of deliveries. Relative task | |
351 | since ''''AcSo'''' is the enclosing task of ''''deliveries''''. Relative task | |
350 | 352 | IDs are a little bit confusing at first, but have a real advantage |
351 | 353 | over absolute IDs. Sooner or later you want to move tasks around in |
352 | 354 | your project and then it's a lot less likely that you have to fix |
361 | 363 | the tasks. 500 is the default priority of top-level tasks. Setting the |
362 | 364 | priority to 1000 marks the task as most important task, since the |
363 | 365 | possible range is 1 (not important at all) to 1000 (ultimately |
364 | important). priority is an attribute that is passed down to subtasks | |
366 | important). ''''priority'''' is an attribute that is passed down to subtasks | |
365 | 367 | if specified before the subtasks' declaration. So all subtasks of |
366 | 368 | software have a priority of 1000 as well, unless they have their own |
367 | 369 | priority definition. |
485 | 487 | |
486 | 488 | === Visualizing the Project === |
487 | 489 | |
488 | To see and share the project data you reports can be generated. You | |
490 | To see and share the project data, reports can be generated. You | |
489 | 491 | can generate any number of reports and you can select from a variety |
490 | 492 | of report types and output formats. To have a report generated after |
491 | 493 | the project scheduling has been completed, you need include a report |
644 | 646 | report file. |
645 | 647 | |
646 | 648 | For the [[footer]] we can proceed accordingly. We just add a few more |
647 | paragraphs of text the describe certain aspects of the project. By | |
649 | paragraphs of text to describe certain aspects of the project. By | |
648 | 650 | putting it all together, we end up with the following report |
649 | 651 | definition. |
650 | 652 | |
652 | 654 | |
653 | 655 | The generated report can be found |
654 | 656 | [http://www.taskjuggler.org/tj3/examples/Tutorial/Overview.html |
655 | here]. It servers as an entry page for the other reports. While it | |
657 | here]. It serves as an entry page for the other reports. While it | |
656 | 658 | already contains some references, a navigator bar would be handy as |
657 | 659 | well. Fortunately, there is a block generator called 'navigator' to |
658 | 660 | take care of this. But before we can include the navigator in the |
81 | 81 | |
82 | 82 | it "should fail with bad authentication key" do |
83 | 83 | TaskJuggler::runBroker(@pb, @authKey) do |
84 | @pbi.command('bad key', :status, []).should be_false | |
84 | @pbi.command('bad key', :status, []).should be false | |
85 | 85 | end |
86 | 86 | end |
87 | 87 | |
104 | 104 | stdOut = StringIO.new |
105 | 105 | stdErr = StringIO.new |
106 | 106 | args = [ Dir.getwd, [ '.' ], stdOut, stdErr, stdIn, true ] |
107 | @pbi.command(@authKey, :addProject, args).should be_true | |
107 | @pbi.command(@authKey, :addProject, args).should be true | |
108 | 108 | stdErr.string.should be_empty |
109 | 109 | |
110 | 110 | # Can't remove non-existing project bar |
111 | @pbi.command(@authKey, :removeProject, 'bar').should be_false | |
112 | @pbi.command(@authKey, :removeProject, 'foo').should be_true | |
111 | @pbi.command(@authKey, :removeProject, 'bar').should be false | |
112 | @pbi.command(@authKey, :removeProject, 'foo').should be true | |
113 | 113 | # Can't remove foo twice |
114 | @pbi.command(@authKey, :removeProject, 'foo').should be_false | |
114 | @pbi.command(@authKey, :removeProject, 'foo').should be false | |
115 | 115 | end |
116 | 116 | end |
117 | 117 | |
122 | 122 | it "should fail with bad authentication key" do |
123 | 123 | TaskJuggler::runBroker(@pb, @authKey) do |
124 | 124 | @pbi.updateState('bad key', 'foo', 'foo', :status, true).should \ |
125 | be_false | |
125 | be false | |
126 | 126 | end |
127 | 127 | end |
128 | 128 |
229 | 229 | it 'should have matching status sheets in body and attachment' do |
230 | 230 | @sss_mails.each do |mail| |
231 | 231 | bodySheet = extractStatusSheet(mail.parts[0].decoded) |
232 | attachedSheet = extractStatusSheet(mail.part[1].decoded) | |
232 | attachedSheet = extractStatusSheet(mail.part[1].decoded).tr("\r", '') | |
233 | 233 | bodySheet.should == attachedSheet |
234 | 234 | end |
235 | 235 | end |
215 | 215 | it 'should have matching timesheets in body and attachment' do |
216 | 216 | @tss_mails.each do |mail| |
217 | 217 | bodySheet = extractTimeSheet(mail.parts[0].decoded) |
218 | attachedSheet = extractTimeSheet(mail.part[1].decoded) | |
218 | attachedSheet = extractTimeSheet(mail.part[1].decoded).tr("\r", '') | |
219 | 219 | bodySheet.should == attachedSheet |
220 | 220 | end |
221 | 221 | end |
34 | 34 | s.summary = 'A Project Management Software' |
35 | 35 | s.description = <<'EOT' |
36 | 36 | TaskJuggler is a modern and powerful, Free and Open Source Software project |
37 | management tool. Its new approach to project planing and tracking is more | |
37 | management tool. It's new approach to project planning and tracking is more | |
38 | 38 | flexible and superior to the commonly used Gantt chart editing tools. |
39 | 39 | |
40 | 40 | TaskJuggler is project management software for serious project managers. It |
41 | 41 | covers the complete spectrum of project management tasks from the first idea |
42 | 42 | to the completion of the project. It assists you during project scoping, |
43 | resource assignment, cost and revenue planing, risk and communication | |
43 | resource assignment, cost and revenue planning, risk and communication | |
44 | 44 | management. |
45 | 45 | EOT |
46 | ||
46 | s.license = 'GPL-2.0' | |
47 | 47 | s.require_path = 'lib' |
48 | 48 | s.files = (`git ls-files -- lib`).split("\n") + |
49 | 49 | (`git ls-files -- data`).split("\n") + |
52 | 52 | (`git ls-files -- tasks`).split("\n") + |
53 | 53 | %w( .gemtest taskjuggler.gemspec Rakefile ) + |
54 | 54 | # Generated files, not contained in Git repository. |
55 | %w( data/tjp.vim ) + Dir.glob('manual/html/**/*') | |
55 | %w( data/tjp.vim ) + Dir.glob('manual/html/**/*') + Dir.glob('man/*.1') | |
56 | 56 | s.bindir = 'bin' |
57 | 57 | s.executables = (`git ls-files -- bin`).split("\n"). |
58 | 58 | map { |fn| File.basename(fn) } |
62 | 62 | s.has_rdoc = true |
63 | 63 | s.extra_rdoc_files = %w( README.rdoc COPYING CHANGELOG ) |
64 | 64 | |
65 | s.add_dependency('mail', '>= 2.4.3') | |
66 | s.add_dependency('term-ansicolor', '>= 1.0.7') | |
67 | s.add_development_dependency('rspec', '>= 2.5.0') | |
65 | s.add_dependency('mail', '~> 2.7', '>= 2.7.1') | |
66 | s.add_runtime_dependency('term-ansicolor', '~> 1.7', '>= 1.7.1') | |
67 | s.add_development_dependency('rspec', '~> 2.5', '>= 2.5.0') | |
68 | 68 | s.platform = Gem::Platform::RUBY |
69 | 69 | s.required_ruby_version = '>= 2.0.0' |
70 | 70 | } |
0 | 0 | require 'time' |
1 | ||
2 | CLOBBER.include "CHANGELOG" | |
1 | 3 | |
2 | 4 | desc 'Generate the CHANGELOG file' |
3 | 5 | task :changelog do |
1 | 1 | require 'find' |
2 | 2 | require 'rubygems' |
3 | 3 | require 'rubygems/package' |
4 | ||
5 | CLOBBER.include "pkg/" | |
4 | 6 | |
5 | 7 | # Unfortunately Rake::GemPackageTest cannot deal with files that are generated |
6 | 8 | # by Rake targets. So we have to write our own packaging task. |
10 | 12 | Rake::Task[:manual].invoke |
11 | 13 | Rake::Task[:changelog].invoke |
12 | 14 | Rake::Task[:permissions].invoke |
15 | Rake::Task[:help2man].invoke | |
13 | 16 | |
14 | 17 | load 'taskjuggler.gemspec'; |
15 | 18 |
0 | # TASK MAN GENERATE | |
1 | ||
2 | CLOBBER.include "man" | |
3 | ||
4 | directory "man" | |
5 | ||
6 | desc 'Generate man pages from help' | |
7 | task :help2man => 'man' do | |
8 | help2man = %x{which help2man} | |
9 | help2man.chomp! | |
10 | Dir.foreach('bin') do |prog| | |
11 | next if prog == '.' or prog == '..' | |
12 | system help2man,"--output=man/#{prog}.1","--no-info","--manual=TaskJuggler",*("--include=h2m/#{prog}.h2m" unless !File.exists?("h2m/#{prog}.h2m")),"bin/#{prog}" | |
13 | FileUtils.chmod(0644, "man/#{prog}.1") | |
14 | end | |
15 | FileUtils.chmod(0755, 'man') | |
16 | end | |
17 |
0 | 0 | # TASK Kate SYNTAX |
1 | 1 | |
2 | 2 | require 'taskjuggler/KateSyntax' |
3 | ||
4 | CLOBBER.include "data/kate-tjp.xml" | |
3 | 5 | |
4 | 6 | desc 'Generate kate-tjp.xml Kate syntax file' |
5 | 7 | task :kate do |
0 | 0 | # TASK MANUAL |
1 | 1 | |
2 | 2 | require 'taskjuggler/apps/Tj3Man' |
3 | ||
4 | CLOBBER.include "manual/html/" | |
3 | 5 | |
4 | 6 | desc 'Generate User Manual' |
5 | 7 | task :manual do |
0 | 0 | $:.unshift File.join(File.dirname(__FILE__), '..', 'test') |
1 | 1 | |
2 | 2 | require 'rake/testtask' |
3 | ||
4 | CLEAN.include "test/TestSuite/Export-Reports/refs/Leave.tjp" | |
5 | CLEAN.include "test/TestSuite/Export-Reports/refs/ListAttributes.tjp" | |
6 | CLEAN.include "test/TestSuite/Export-Reports/refs/Macro-4.tjp" | |
7 | CLEAN.include "test/TestSuite/Export-Reports/refs/TraceReport.tjp" | |
3 | 8 | |
4 | 9 | # TEST TASK |
5 | 10 | desc 'Run all unit tests in the test directory' |
0 | 0 | # TASK VIM SYNTAX |
1 | 1 | |
2 | 2 | require 'taskjuggler/VimSyntax' |
3 | ||
4 | CLOBBER.include "data/tjp.vim" | |
3 | 5 | |
4 | 6 | desc 'Generate vim.tjp Vim syntax file' |
5 | 7 | task :vim do |
44 | 44 | task _Task_6 "Final Payment" { |
45 | 45 | depends _Task_1.mf |
46 | 46 | start 2012-10-22-17:00-+0000 |
47 | milestone | |
48 | 47 | scheduled |
49 | 48 | } |
50 | 49 | } |
9 | 9 | |
10 | 10 | task t1 "T1" { |
11 | 11 | start 2011-03-05-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | task t2 "T2" { |
16 | 15 | start 2011-03-05-00:00-+0000 |
17 | milestone | |
18 | 16 | scheduled |
19 | 17 | } |
20 | 18 | task t3 "T3" { |
14 | 14 | |
15 | 15 | task _Task_1 "Holiday Season" { |
16 | 16 | start 2011-11-24-00:00-+0000 |
17 | milestone | |
18 | 17 | scheduled |
19 | 18 | } |
20 | 19 | supplement task _Task_1 { |
24 | 24 | } |
25 | 25 | task m1 "Milestone 1" { |
26 | 26 | start 2003-06-05-06:00-+0000 |
27 | milestone | |
28 | 27 | scheduled |
29 | 28 | } |
30 | 29 | } |
31 | 31 | task _Task_1 "Foo" { |
32 | 32 | task _Task_2 "Bar" { |
33 | 33 | start 2009-10-04-00:00-+0000 |
34 | milestone | |
35 | 34 | scheduled |
36 | 35 | } |
37 | 36 | } |
9 | 9 | |
10 | 10 | task items "Project breakdown" { |
11 | 11 | start 2006-09-22-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task items { |
9 | 9 | |
10 | 10 | task t "Task" { |
11 | 11 | start 2007-01-01-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task t { |
37 | 37 | |
38 | 38 | task _Task_1 "T" { |
39 | 39 | start 2013-04-24-00:00-+0000 |
40 | milestone | |
41 | 40 | scheduled |
42 | two:milestone | |
43 | 41 | } |
44 | 42 | supplement task _Task_1 { |
45 | 43 | Claim "A '''big''' statement." |
10 | 10 | task foo1 "foo1" { |
11 | 11 | task foo2 "foo2" { |
12 | 12 | start 2007-12-04-07:00-+0000 |
13 | milestone | |
14 | 13 | scheduled |
15 | 14 | } |
16 | 15 | task foo3 "foo3" { |
17 | 17 | } |
18 | 18 | task intervalTask "Interval Task" { |
19 | 19 | start 2007-06-17-06:00-+0000 |
20 | milestone | |
21 | 20 | scheduled |
22 | 21 | } |
23 | 22 | task lengthTask "Length Task" { |
13 | 13 | |
14 | 14 | task t "An important date" { |
15 | 15 | start 2007-07-21-06:00-+0000 |
16 | milestone | |
17 | 16 | scheduled |
18 | 17 | } |
19 | 18 | supplement task t { |
9 | 9 | |
10 | 10 | task t1 "Task 1" { |
11 | 11 | start 2005-05-29-06:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | task t2 "Task 2" { |
16 | 15 | depends t1 |
17 | 16 | start 2005-06-03-06:00-+0000 |
18 | milestone | |
19 | 17 | scheduled |
20 | 18 | } |
21 | 19 | task t3 "Task 3" { |
22 | 20 | depends t1 |
23 | 21 | start 2005-06-03-23:00-+0000 |
24 | milestone | |
25 | 22 | scheduled |
26 | 23 | } |
27 | 24 | supplement task t1 { |
13 | 13 | |
14 | 14 | task _Task_1 "Foo" { |
15 | 15 | start 2010-02-26-00:00-+0000 |
16 | milestone | |
17 | 16 | scheduled |
18 | 17 | } |
19 | 18 | supplement task _Task_1 { |
10 | 10 | |
11 | 11 | task t1 "Task1" { |
12 | 12 | start 2009-05-05-06:00-+0000 |
13 | milestone | |
14 | 13 | scheduled |
15 | 14 | } |
16 | 15 | supplement task t1 { |
11 | 11 | |
12 | 12 | task t1 "Task1" { |
13 | 13 | start 2008-01-18-00:00-+0000 |
14 | milestone | |
15 | 14 | scheduled |
16 | 15 | } |
17 | 16 | task t2 "Task2" { |
9 | 9 | |
10 | 10 | task _Task_1 " Crème brûlée Prepare " { |
11 | 11 | start 2010-04-28-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | task _Task_2 "task" { |
16 | 15 | start 2010-04-28-00:00-+0000 |
17 | milestone | |
18 | 16 | scheduled |
19 | 17 | } |
20 | 18 | supplement task _Task_1 { |
9 | 9 | |
10 | 10 | task _Task_1 "foo" { |
11 | 11 | start 2009-12-01-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task _Task_1 { |
22 | 22 | |
23 | 23 | task _Task_1 "T" { |
24 | 24 | start 2010-04-03-00:00-+0000 |
25 | milestone | |
26 | 25 | scheduled |
27 | 26 | } |
28 | 27 | supplement task _Task_1 { |
9 | 9 | |
10 | 10 | task project_start "Project Start" { |
11 | 11 | start 2005-07-15-06:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | task deadline "Important Deadline" { |
16 | 15 | start 2005-07-20-06:00-+0000 |
17 | milestone | |
18 | 16 | scheduled |
19 | 17 | } |
20 | 18 | supplement task project_start { |
9 | 9 | |
10 | 10 | task t "Task" { |
11 | 11 | start 2000-01-01-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task t { |
10 | 10 | task foo1 "foo1" { |
11 | 11 | task foo2 "foo2" { |
12 | 12 | start 2003-12-04-07:00-+0000 |
13 | milestone | |
14 | 13 | scheduled |
15 | 14 | } |
16 | 15 | task foo3 "foo3" { |
9 | 9 | |
10 | 10 | task t "Task" { |
11 | 11 | start 2007-01-01-07:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task t { |
9 | 9 | |
10 | 10 | task t1 "Task 1" { |
11 | 11 | start 2006-08-22-06:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | task t2 "Task 2" { |
16 | 15 | start 2006-08-22-06:00-+0000 |
17 | milestone | |
18 | 16 | scheduled |
19 | 17 | } |
20 | 18 | task t3 "Task 3" { |
21 | 19 | start 2006-08-22-06:00-+0000 |
22 | milestone | |
23 | 20 | scheduled |
24 | 21 | } |
25 | 22 | supplement task t1 { |
29 | 29 | } |
30 | 30 | task t3 "FooTask3" { |
31 | 31 | start 2000-01-01-07:00-+0000 |
32 | milestone | |
33 | 32 | scheduled |
34 | 33 | } |
35 | 34 | supplement task t1 { |
14 | 14 | |
15 | 15 | task t "An important date" { |
16 | 16 | start 2005-06-10-06:00-+0000 |
17 | milestone | |
18 | 17 | scheduled |
19 | 18 | } |
20 | 19 | supplement task t { |
18 | 18 | |
19 | 19 | task _Task_1 "T" { |
20 | 20 | start 2010-11-10-00:00-+0000 |
21 | milestone | |
22 | 21 | scheduled |
23 | 22 | } |
24 | 23 | supplement task _Task_1 { |
18 | 18 | |
19 | 19 | task _Task_1 "T" { |
20 | 20 | start 2010-11-10-00:00-+0000 |
21 | milestone | |
22 | 21 | scheduled |
23 | 22 | } |
24 | 23 | supplement task _Task_1 { |
15 | 15 | |
16 | 16 | task t "Task" { |
17 | 17 | start 2007-05-29-06:00-+0000 |
18 | milestone | |
19 | 18 | scheduled |
20 | 19 | actual:start 2007-06-03-06:00-+0000 |
21 | actual:milestone | |
22 | 20 | } |
23 | 21 | supplement task t { |
24 | 22 | priority 500 |
9 | 9 | |
10 | 10 | task item "Project" { |
11 | 11 | start 2005-06-06-09:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task item { |
15 | 15 | |
16 | 16 | task t "An important date" { |
17 | 17 | start 2005-07-22-06:00-+0000 |
18 | milestone | |
19 | 18 | scheduled |
20 | 19 | } |
21 | 20 | supplement task t { |
10 | 10 | task foo "Foo" { |
11 | 11 | task _Task_2 "Foo 1" { |
12 | 12 | start 2011-12-12-00:00-+0000 |
13 | milestone | |
14 | 13 | scheduled |
15 | 14 | } |
16 | 15 | task _Task_3 "Foo 2" { |
17 | 16 | start 2011-12-12-00:00-+0000 |
18 | milestone | |
19 | 17 | scheduled |
20 | 18 | } |
21 | 19 | } |
22 | 20 | task bar "Bar" { |
23 | 21 | task _Task_5 "Bar 1" { |
24 | 22 | start 2011-12-12-00:00-+0000 |
25 | milestone | |
26 | 23 | scheduled |
27 | 24 | } |
28 | 25 | task _Task_6 "Bar 2" { |
29 | 26 | start 2011-12-12-00:00-+0000 |
30 | milestone | |
31 | 27 | scheduled |
32 | 28 | } |
33 | 29 | } |
17 | 17 | task wp1 "Workpackage 1" { |
18 | 18 | task t1 "Task 1" { |
19 | 19 | start 2011-11-11-05:00-+0000 |
20 | milestone | |
21 | 20 | scheduled |
22 | 21 | } |
23 | 22 | task t2 "Task 2" { |
24 | 23 | start 2011-11-11-05:00-+0000 |
25 | milestone | |
26 | 24 | scheduled |
27 | 25 | } |
28 | 26 | } |
30 | 28 | depends project.wp1 |
31 | 29 | task t1 "Task 1" { |
32 | 30 | start 2011-11-11-05:00-+0000 |
33 | milestone | |
34 | 31 | scheduled |
35 | 32 | } |
36 | 33 | task t2 "Task 2" { |
37 | 34 | start 2011-11-11-05:00-+0000 |
38 | milestone | |
39 | 35 | scheduled |
40 | 36 | } |
41 | 37 | } |
43 | 39 | task _Task_9 "Item 1" { |
44 | 40 | depends project.wp1 |
45 | 41 | start 2011-11-11-05:00-+0000 |
46 | milestone | |
47 | 42 | scheduled |
48 | 43 | } |
49 | 44 | task _Task_10 "Item 2" { |
50 | 45 | depends project.wp2 |
51 | 46 | start 2011-11-11-05:00-+0000 |
52 | milestone | |
53 | 47 | scheduled |
54 | 48 | } |
55 | 49 | } |
9 | 9 | |
10 | 10 | task _Task_1 "Foo" { |
11 | 11 | start 2011-12-11-00:00-+0000 |
12 | milestone | |
13 | 12 | scheduled |
14 | 13 | } |
15 | 14 | supplement task _Task_1 { |
103 | 103 | task deliveries "Milestones" { |
104 | 104 | task start "Project start" { |
105 | 105 | start 2002-01-16-00:00-+0000 |
106 | milestone | |
107 | 106 | scheduled |
108 | 107 | delayed:start 2002-01-19-23:00-+0000 |
109 | delayed:milestone | |
110 | 108 | } |
111 | 109 | task prev "Technology Preview" { |
112 | 110 | depends AcSo.software.backend |
113 | 111 | start 2002-02-28-14:00-+0000 |
114 | milestone | |
115 | 112 | scheduled |
116 | 113 | delayed:start 2002-03-05-14:00-+0000 |
117 | delayed:milestone | |
118 | 114 | } |
119 | 115 | task beta "Beta version" { |
120 | 116 | depends AcSo.test.alpha |
121 | 117 | start 2002-04-03-10:00-+0000 |
122 | milestone | |
123 | 118 | scheduled |
124 | 119 | delayed:start 2002-04-11-09:00-+0000 |
125 | delayed:milestone | |
126 | 120 | } |
127 | 121 | task done "Ship Product to Customer" { |
128 | 122 | depends AcSo.test.beta, AcSo.manual |
129 | 123 | start 2002-04-18-13:00-+0000 |
130 | milestone | |
131 | 124 | scheduled |
132 | 125 | delayed:start 2002-04-26-12:00-+0000 |
133 | delayed:milestone | |
134 | 126 | } |
135 | 127 | } |
136 | 128 | } |
19 | 19 | 2007-01-09-13:00 +4h |
20 | 20 | # This is a common mistake. With standard working hours, this will |
21 | 21 | # yield a zero time booking! The interval is midnight to 8am. So |
22 | # it's outside of the working hours and 'sloppy 2' surpresses the | |
22 | # it's outside of the working hours and 'sloppy 2' suppresses the | |
23 | 23 | # warning. |
24 | 24 | booking test 2007-01-11 +8h { sloppy 2 } |
25 | 25 | # Use 'overtime' to book off-hour slots. This booking will book the |
0 | 0 | project prj "Project" "1.0" 2007-01-01 - 2007-03-01 { |
1 | 1 | timezone "Europe/Berlin" |
2 | 2 | # German currency format: e. g. -10.000,20 5.014,11 |
3 | numberformat "-" "" "." "," 2 | |
3 | currencyformat "-" "" "." "," 2 | |
4 | 4 | |
5 | 5 | # US currency format: e. g. (10,000.20) 5,014.11 |
6 | 6 | currencyformat "(" ")" "," "." 2 |
32 | 32 | # *** EXAMPLE: now + |
33 | 33 | now 2002-03-05-13:00 |
34 | 34 | # *** EXAMPLE: now - |
35 | # The date that is used to show additional line on a Gannt chart | |
36 | # and can be specified by the user. | |
37 | # *** EXAMPLE: markdate + | |
38 | markdate 2002-08-07-03:00 | |
39 | # *** EXAMPLE: markdate - | |
35 | 40 | # The currency for all money values is the Euro. |
36 | 41 | # *** EXAMPLE: currency + |
37 | 42 | currency "USD" |
55 | 55 | [:LITERAL, '-', 6], |
56 | 56 | [:LITERAL, '$', 6], |
57 | 57 | [:MACRO, 'A Macro', 6], |
58 | [:TIME, time(15, 23), 7], | |
58 | [:TIME, mktime(15, 23), 7], | |
59 | 59 | [:STRING, 'A string', 7], |
60 | 60 | [:STRING, "It's a string", 8], |
61 | 61 | [:STRING, "A\nmult\"i line\nstring", 9], |
100 | 100 | 24:00 |
101 | 101 | EOT |
102 | 102 | ref = [ |
103 | [:TIME, time(0, 0), 1], | |
104 | [:TIME, time(0, 0), 2], | |
105 | [:TIME, time(1, 0), 3], | |
106 | [:TIME, time(11, 59), 4], | |
107 | [:TIME, time(12, 1), 5], | |
108 | [:TIME, time(24, 0), 6], | |
103 | [:TIME, mktime(0, 0), 1], | |
104 | [:TIME, mktime(0, 0), 2], | |
105 | [:TIME, mktime(1, 0), 3], | |
106 | [:TIME, mktime(11, 59), 4], | |
107 | [:TIME, mktime(12, 1), 5], | |
108 | [:TIME, mktime(24, 0), 6], | |
109 | 109 | [:eof, '<END>', 7] |
110 | 110 | ] |
111 | 111 | |
171 | 171 | |
172 | 172 | private |
173 | 173 | |
174 | def time(h, m) | |
174 | def mktime(h, m) | |
175 | 175 | (h * 60 + m) * 60 |
176 | 176 | end |
177 | 177 |