taskjuggler 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (320) hide show
  1. data/CHANGELOG +30 -0
  2. data/README.rdoc +1 -0
  3. data/data/tjp.vim +13 -9
  4. data/lib/taskjuggler/Allocation.rb +2 -2
  5. data/lib/taskjuggler/AttributeBase.rb +10 -0
  6. data/lib/taskjuggler/Attributes.rb +2 -8
  7. data/lib/taskjuggler/Journal.rb +20 -19
  8. data/lib/taskjuggler/PTNProxy.rb +14 -1
  9. data/lib/taskjuggler/ProjectFileParser.rb +3 -0
  10. data/lib/taskjuggler/ProjectFileScanner.rb +54 -44
  11. data/lib/taskjuggler/PropertyList.rb +32 -0
  12. data/lib/taskjuggler/PropertyTreeNode.rb +4 -0
  13. data/lib/taskjuggler/ResourceScenario.rb +53 -20
  14. data/lib/taskjuggler/RichText/Document.rb +7 -5
  15. data/lib/taskjuggler/RichText/Scanner.rb +38 -38
  16. data/lib/taskjuggler/RichText/TOCEntry.rb +1 -1
  17. data/lib/taskjuggler/TaskScenario.rb +78 -62
  18. data/lib/taskjuggler/TextParser.rb +4 -3
  19. data/lib/taskjuggler/TextParser/MacroTable.rb +3 -1
  20. data/lib/taskjuggler/TextParser/Scanner.rb +73 -58
  21. data/lib/taskjuggler/Tj3Config.rb +1 -1
  22. data/lib/taskjuggler/TjpSyntaxRules.rb +215 -67
  23. data/lib/taskjuggler/apps/Tj3Client.rb +1 -1
  24. data/lib/taskjuggler/daemon/ReportServer.rb +8 -1
  25. data/lib/taskjuggler/reports/ExportRE.rb +46 -0
  26. data/lib/taskjuggler/reports/MspXmlRE.rb +409 -0
  27. data/lib/taskjuggler/reports/Report.rb +29 -4
  28. data/lib/taskjuggler/reports/ReportBase.rb +0 -8
  29. data/lib/taskjuggler/reports/TableReport.rb +13 -3
  30. data/lib/taskjuggler/reports/TaskListRE.rb +1 -0
  31. data/lib/taskjuggler/reports/TjpExportRE.rb +1 -1
  32. data/manual/Rich_Text_Attributes +2 -2
  33. data/manual/Tutorial +15 -11
  34. data/manual/html/Day_To_Day_Juggling.html +1 -1
  35. data/manual/html/Getting_Started.html +1 -1
  36. data/manual/html/How_To_Contribute.html +1 -1
  37. data/manual/html/Installation.html +1 -1
  38. data/manual/html/Intro.html +1 -1
  39. data/manual/html/Reporting_Bugs.html +1 -1
  40. data/manual/html/Rich_Text_Attributes.html +1 -1
  41. data/manual/html/Software.html +1 -1
  42. data/manual/html/TaskJuggler_2x_Migration.html +1 -1
  43. data/manual/html/TaskJuggler_Internals.html +1 -1
  44. data/manual/html/The_TaskJuggler_Syntax.html +1 -1
  45. data/manual/html/Tutorial.html +5 -2
  46. data/manual/html/account.html +1 -1
  47. data/manual/html/account.task.html +1 -1
  48. data/manual/html/accountprefix.html +1 -1
  49. data/manual/html/accountreport.html +9 -3
  50. data/manual/html/accountroot.html +1 -1
  51. data/manual/html/active.html +1 -1
  52. data/manual/html/adopt.task.html +3 -3
  53. data/manual/html/aggregate.html +1 -1
  54. data/manual/html/alert.html +1 -1
  55. data/manual/html/alertlevels.html +1 -1
  56. data/manual/html/allocate.html +5 -2
  57. data/manual/html/alphabet.html +1 -1
  58. data/manual/html/alternative.html +1 -1
  59. data/manual/html/author.html +1 -1
  60. data/manual/html/balance.html +1 -1
  61. data/manual/html/booking.resource.html +1 -1
  62. data/manual/html/booking.task.html +1 -1
  63. data/manual/html/caption.html +1 -1
  64. data/manual/html/cellcolor.column.html +1 -1
  65. data/manual/html/celltext.column.html +43 -4
  66. data/manual/html/center.html +1 -1
  67. data/manual/html/charge.html +1 -1
  68. data/manual/html/chargeset.html +2 -2
  69. data/manual/html/columnid.html +6 -6
  70. data/manual/html/columns.html +1 -1
  71. data/manual/html/complete.html +1 -1
  72. data/manual/html/copyright.html +1 -1
  73. data/manual/html/credits.html +1 -1
  74. data/manual/html/currency.html +1 -1
  75. data/manual/html/currencyformat.html +1 -1
  76. data/manual/html/dailymax.html +1 -1
  77. data/manual/html/dailymin.html +1 -1
  78. data/manual/html/dailyworkinghours.html +1 -1
  79. data/manual/html/date.extend.html +1 -1
  80. data/manual/html/date.html +2 -2
  81. data/manual/html/definitions.html +1 -1
  82. data/manual/html/depends.html +1 -1
  83. data/manual/html/details.html +1 -1
  84. data/manual/html/disabled.html +1 -1
  85. data/manual/html/duration.html +1 -1
  86. data/manual/html/efficiency.html +1 -1
  87. data/manual/html/effort.html +1 -1
  88. data/manual/html/email.html +1 -1
  89. data/manual/html/enabled.html +1 -1
  90. data/manual/html/end.column.html +1 -1
  91. data/manual/html/end.html +1 -1
  92. data/manual/html/end.limit.html +1 -1
  93. data/manual/html/end.report.html +9 -3
  94. data/manual/html/end.timesheet.html +1 -1
  95. data/manual/html/endcredit.html +1 -1
  96. data/manual/html/epilog.html +1 -1
  97. data/manual/html/export.html +73 -5
  98. data/manual/html/extend.html +1 -1
  99. data/manual/html/fail.html +1 -1
  100. data/manual/html/fdl.html +1 -1
  101. data/manual/html/flags.account.html +1 -1
  102. data/manual/html/flags.html +1 -1
  103. data/manual/html/flags.journalentry.html +1 -1
  104. data/manual/html/flags.report.html +1 -1
  105. data/manual/html/flags.resource.html +1 -1
  106. data/manual/html/flags.statussheet.html +1 -1
  107. data/manual/html/flags.task.html +1 -1
  108. data/manual/html/flags.timesheet.html +1 -1
  109. data/manual/html/fontcolor.column.html +1 -1
  110. data/manual/html/footer.html +1 -1
  111. data/manual/html/formats.export.html +72 -0
  112. data/manual/html/formats.html +3 -3
  113. data/manual/html/functions.html +3 -3
  114. data/manual/html/gapduration.html +2 -2
  115. data/manual/html/gaplength.html +1 -1
  116. data/manual/html/halign.center.html +1 -1
  117. data/manual/html/halign.column.html +1 -1
  118. data/manual/html/halign.left.html +1 -1
  119. data/manual/html/halign.right.html +1 -1
  120. data/manual/html/hasalert.html +1 -1
  121. data/manual/html/header.html +1 -1
  122. data/manual/html/headline.html +1 -1
  123. data/manual/html/height.html +1 -1
  124. data/manual/html/hideaccount.html +1 -1
  125. data/manual/html/hidejournalentry.html +1 -1
  126. data/manual/html/hidereport.html +1 -1
  127. data/manual/html/hideresource.html +1 -1
  128. data/manual/html/hidetask.html +1 -1
  129. data/manual/html/icalreport.html +1 -1
  130. data/manual/html/include.macro.html +1 -1
  131. data/manual/html/include.project.html +1 -1
  132. data/manual/html/include.properties.html +1 -1
  133. data/manual/html/index.html +1 -1
  134. data/manual/html/inherit.extend.html +1 -1
  135. data/manual/html/interval1.html +2 -2
  136. data/manual/html/interval2.html +2 -2
  137. data/manual/html/interval3.html +2 -2
  138. data/manual/html/interval4.html +2 -2
  139. data/manual/html/isactive.html +1 -1
  140. data/manual/html/ischildof.html +1 -1
  141. data/manual/html/isdependencyof.html +1 -1
  142. data/manual/html/isdutyof.html +1 -1
  143. data/manual/html/isfeatureof.html +1 -1
  144. data/manual/html/isleaf.html +1 -1
  145. data/manual/html/ismilestone.html +1 -1
  146. data/manual/html/isongoing.html +1 -1
  147. data/manual/html/isresource.html +1 -1
  148. data/manual/html/isresponsibilityof.html +1 -1
  149. data/manual/html/istask.html +1 -1
  150. data/manual/html/journalattributes.html +1 -1
  151. data/manual/html/journalentry.html +1 -1
  152. data/manual/html/journalmode.html +11 -3
  153. data/manual/html/leaveallowance.html +1 -1
  154. data/manual/html/leaves.html +1 -1
  155. data/manual/html/left.html +1 -1
  156. data/manual/html/length.html +1 -1
  157. data/manual/html/limits.allocate.html +1 -1
  158. data/manual/html/limits.html +1 -1
  159. data/manual/html/limits.resource.html +1 -1
  160. data/manual/html/limits.task.html +1 -1
  161. data/manual/html/listitem.column.html +1 -1
  162. data/manual/html/listtype.column.html +1 -1
  163. data/manual/html/loadunit.html +2 -2
  164. data/manual/html/logicalexpression.html +1 -1
  165. data/manual/html/logicalflagexpression.html +1 -1
  166. data/manual/html/macro.html +1 -1
  167. data/manual/html/managers.html +1 -1
  168. data/manual/html/mandatory.html +1 -1
  169. data/manual/html/maxend.html +1 -1
  170. data/manual/html/maximum.html +1 -1
  171. data/manual/html/maxstart.html +1 -1
  172. data/manual/html/milestone.html +1 -1
  173. data/manual/html/minend.html +1 -1
  174. data/manual/html/minimum.html +1 -1
  175. data/manual/html/minstart.html +1 -1
  176. data/manual/html/monthlymax.html +1 -1
  177. data/manual/html/monthlymin.html +1 -1
  178. data/manual/html/navbar.html +5 -1
  179. data/manual/html/navigator.html +1 -1
  180. data/manual/html/newtask.html +1 -1
  181. data/manual/html/nikureport.html +1 -1
  182. data/manual/html/note.task.html +1 -1
  183. data/manual/html/now.html +1 -1
  184. data/manual/html/numberformat.html +1 -1
  185. data/manual/html/onend.html +1 -1
  186. data/manual/html/onstart.html +1 -1
  187. data/manual/html/opennodes.html +1 -1
  188. data/manual/html/overtime.booking.html +1 -1
  189. data/manual/html/period.column.html +1 -1
  190. data/manual/html/period.limit.html +1 -1
  191. data/manual/html/period.report.html +1 -1
  192. data/manual/html/period.task.html +1 -1
  193. data/manual/html/persistent.html +1 -1
  194. data/manual/html/precedes.html +1 -1
  195. data/manual/html/priority.html +1 -1
  196. data/manual/html/priority.timesheet.html +1 -1
  197. data/manual/html/project.html +1 -1
  198. data/manual/html/projectid.html +1 -1
  199. data/manual/html/projectid.task.html +1 -1
  200. data/manual/html/projectids.html +1 -1
  201. data/manual/html/projection.html +1 -1
  202. data/manual/html/prolog.html +1 -1
  203. data/manual/html/properties.html +1 -1
  204. data/manual/html/purge.html +8 -5
  205. data/manual/html/rate.html +1 -1
  206. data/manual/html/rate.resource.html +1 -1
  207. data/manual/html/reference.extend.html +1 -1
  208. data/manual/html/remaining.html +1 -1
  209. data/manual/html/replace.html +1 -1
  210. data/manual/html/reportprefix.html +1 -1
  211. data/manual/html/resource.html +1 -1
  212. data/manual/html/resourceattributes.html +1 -1
  213. data/manual/html/resourceprefix.html +1 -1
  214. data/manual/html/resourcereport.html +9 -3
  215. data/manual/html/resourceroot.html +1 -1
  216. data/manual/html/resources.limit.html +1 -1
  217. data/manual/html/responsible.html +1 -1
  218. data/manual/html/richtext.extend.html +1 -1
  219. data/manual/html/right.html +1 -1
  220. data/manual/html/rollupaccount.html +1 -1
  221. data/manual/html/rollupresource.html +1 -1
  222. data/manual/html/rolluptask.html +1 -1
  223. data/manual/html/scale.column.html +1 -1
  224. data/manual/html/scenario.html +1 -1
  225. data/manual/html/scenario.ical.html +1 -1
  226. data/manual/html/scenarios.export.html +1 -1
  227. data/manual/html/scenarios.html +1 -1
  228. data/manual/html/scenariospecific.extend.html +1 -1
  229. data/manual/html/scheduled.html +2 -2
  230. data/manual/html/scheduling.html +1 -1
  231. data/manual/html/select.html +1 -1
  232. data/manual/html/selfcontained.html +1 -1
  233. data/manual/html/shift.allocate.html +1 -1
  234. data/manual/html/shift.html +1 -1
  235. data/manual/html/shift.resource.html +1 -1
  236. data/manual/html/shift.task.html +1 -1
  237. data/manual/html/shift.timesheet.html +1 -1
  238. data/manual/html/shifts.allocate.html +1 -1
  239. data/manual/html/shifts.resource.html +1 -1
  240. data/manual/html/shifts.task.html +1 -1
  241. data/manual/html/shorttimeformat.html +1 -1
  242. data/manual/html/sloppy.booking.html +1 -1
  243. data/manual/html/sloppy.projection.html +1 -1
  244. data/manual/html/sortaccounts.html +1 -1
  245. data/manual/html/sortjournalentries.html +1 -1
  246. data/manual/html/sortresources.html +1 -1
  247. data/manual/html/sorttasks.html +1 -1
  248. data/manual/html/start.column.html +1 -1
  249. data/manual/html/start.html +1 -1
  250. data/manual/html/start.limit.html +1 -1
  251. data/manual/html/start.report.html +1 -1
  252. data/manual/html/startcredit.html +1 -1
  253. data/manual/html/status.statussheet.html +1 -1
  254. data/manual/html/status.timesheet.html +1 -1
  255. data/manual/html/statussheet.html +1 -1
  256. data/manual/html/statussheetreport.html +1 -1
  257. data/manual/html/strict.projection.html +1 -1
  258. data/manual/html/summary.html +1 -1
  259. data/manual/html/supplement.html +1 -1
  260. data/manual/html/supplement.resource.html +1 -1
  261. data/manual/html/supplement.task.html +1 -1
  262. data/manual/html/tagfile.html +1 -1
  263. data/manual/html/task.html +1 -1
  264. data/manual/html/task.statussheet.html +1 -1
  265. data/manual/html/task.timesheet.html +1 -1
  266. data/manual/html/taskattributes.html +1 -1
  267. data/manual/html/taskprefix.html +1 -1
  268. data/manual/html/taskreport.html +9 -3
  269. data/manual/html/taskroot.export.html +104 -0
  270. data/manual/html/taskroot.html +3 -3
  271. data/manual/html/text.extend.html +3 -3
  272. data/manual/html/textreport.html +9 -3
  273. data/manual/html/timeformat.html +1 -1
  274. data/manual/html/timeoff.nikureport.html +1 -1
  275. data/manual/html/timesheet.html +1 -1
  276. data/manual/html/timesheetreport.html +1 -1
  277. data/manual/html/timezone.export.html +1 -1
  278. data/manual/html/timezone.html +1 -1
  279. data/manual/html/timezone.report.html +1 -1
  280. data/manual/html/timezone.shift.html +1 -1
  281. data/manual/html/timingresolution.html +1 -1
  282. data/manual/html/title.column.html +1 -1
  283. data/manual/html/title.html +1 -1
  284. data/manual/html/toc.html +203 -189
  285. data/manual/html/tooltip.column.html +1 -1
  286. data/manual/html/tracereport.html +9 -3
  287. data/manual/html/trackingscenario.html +1 -1
  288. data/manual/html/treelevel.html +1 -1
  289. data/manual/html/vacation.html +1 -1
  290. data/manual/html/vacation.resource.html +1 -1
  291. data/manual/html/vacation.shift.html +1 -1
  292. data/manual/html/warn.html +1 -1
  293. data/manual/html/weeklymax.html +1 -1
  294. data/manual/html/weeklymin.html +1 -1
  295. data/manual/html/weekstartsmonday.html +1 -1
  296. data/manual/html/weekstartssunday.html +1 -1
  297. data/manual/html/width.column.html +1 -1
  298. data/manual/html/width.html +1 -1
  299. data/manual/html/work.html +1 -1
  300. data/manual/html/workinghours.project.html +1 -1
  301. data/manual/html/workinghours.resource.html +1 -1
  302. data/manual/html/workinghours.shift.html +1 -1
  303. data/manual/html/yearlyworkingdays.html +1 -1
  304. data/test/TestSuite/CSV-Reports/project-1.tji +0 -6
  305. data/test/TestSuite/CSV-Reports/refs/alert.csv +0 -7
  306. data/test/TestSuite/CSV-Reports/refs/celltext.csv +0 -7
  307. data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +0 -3
  308. data/test/TestSuite/CSV-Reports/refs/sortByTree.csv +0 -7
  309. data/test/TestSuite/CSV-Reports/refs/sortBy_duration.down.csv +0 -7
  310. data/test/TestSuite/CSV-Reports/refs/sortBy_effort.up.csv +0 -7
  311. data/test/TestSuite/CSV-Reports/refs/sortBy_plan.start.down.csv +0 -7
  312. data/test/TestSuite/CSV-Reports/refs/taskreport.csv +0 -7
  313. data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +0 -18
  314. data/test/TestSuite/CSV-Reports/refs/weekly.csv +0 -1
  315. data/test/TestSuite/HTML-Reports/Alerts-2.tjp +46 -0
  316. data/test/TestSuite/Scheduler/Correct/purge.tjp +30 -0
  317. data/test/TestSuite/Syntax/Correct/Export.tjp +8 -2
  318. data/test/TestSuite/Syntax/Correct/tutorial.tjp +0 -1
  319. metadata +16 -10
  320. data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +0 -9
@@ -339,7 +339,8 @@ class TaskJuggler
339
339
  # the syntax rules.
340
340
  error("no_reduce",
341
341
  "Unexpected token '#{token[1]}' found. " +
342
- "Expecting one of " +
342
+ "Expecting #{@stack.last.state.expectedTokens.length > 1 ?
343
+ 'one of ' : ''}" +
343
344
  "#{@stack.last.state.expectedTokens.join(', ')}",
344
345
  @scanner.sourceFileInfo)
345
346
  end
@@ -428,8 +429,8 @@ class TaskJuggler
428
429
  end
429
430
  end
430
431
  end
431
- print " -> #{sl.state ? sl.state.to_s(true) : 'nil'} #{sl.function.nil? ? '' : '(Called)'}"
432
- puts ""
432
+ puts " -> #{sl.state ? sl.state.to_s(true) : 'nil'}" +
433
+ "#{sl.function.nil? ? '' : '(Called)'}"
433
434
  end
434
435
  end
435
436
 
@@ -62,9 +62,11 @@ class TaskJuggler::TextParser
62
62
  resolved = @macros[name].value.dup
63
63
  i = 0
64
64
  args.each do |arg|
65
- resolved.gsub!("${#{i}}", arg)
65
+ resolved.gsub!(Regexp.new("(([^$]|^))\\$\\{#{i}\\}"), "\\1#{arg}")
66
66
  i += 1
67
67
  end
68
+ # Remove the escape character from all the escaped '${...}'.
69
+ resolved.gsub!('$${', '${')
68
70
  [ @macros[name], resolved ]
69
71
  end
70
72
 
@@ -84,12 +84,11 @@ class TaskJuggler::TextParser
84
84
  @line = preCall + text + @scanner.post_match
85
85
  # Start the StringScanner again at the first character of the injected
86
86
  # text.
87
- @scanner = StringScanner.new(@line)
87
+ @scanner.string = @line
88
88
  @scanner.pos = preCall.bytesize
89
89
  end
90
90
 
91
91
  def injectMacro(macro, args, text, callLength)
92
- # We add 3 chars more for the ${}.
93
92
  injectText(text, callLength)
94
93
 
95
94
  # Simple detection for recursive macro calls.
@@ -99,7 +98,7 @@ class TaskJuggler::TextParser
99
98
  true
100
99
  end
101
100
 
102
- def scan(re)
101
+ def readyNextLine
103
102
  # We read the file line by line with gets(). If we don't have a line
104
103
  # yet or we've reached the end of a line, we get the next one.
105
104
  if @scanner.nil? || @scanner.eos?
@@ -109,15 +108,20 @@ class TaskJuggler::TextParser
109
108
  else
110
109
  # We've reached the end of the current file.
111
110
  @scanner = nil
112
- # Return special EOF symbol.
113
- return :scannerEOF
111
+ return false
114
112
  end
115
113
  @scanner = StringScanner.new(@line)
116
114
  @wrapped = @line[-1] == ?\n
117
115
  end
118
- return nil if (token = @scanner.scan(re)).nil?
119
- #puts "#{re.to_s[0..20]}: [#{token}]"
120
116
 
117
+ true
118
+ end
119
+
120
+ def scan(re)
121
+ @scanner.scan(re)
122
+ end
123
+
124
+ def cleanupMacroStack
121
125
  if @nextMacroEnd
122
126
  pos = @scanner.pos
123
127
  while @nextMacroEnd && @nextMacroEnd < pos
@@ -125,8 +129,6 @@ class TaskJuggler::TextParser
125
129
  @nextMacroEnd = @macroStack.empty? ? nil : @macroStack.last.endPos
126
130
  end
127
131
  end
128
-
129
- token
130
132
  end
131
133
 
132
134
  def peek(n)
@@ -240,9 +242,9 @@ class TaskJuggler::TextParser
240
242
  tokenPatterns.each do |pat|
241
243
  type = pat[0]
242
244
  regExp = pat[1]
243
- mode = pat[2] || :tjp
244
- postProc = pat[3]
245
- addPattern(type, regExp, mode, postProc)
245
+ mode = pat[3] || :tjp
246
+ postProc = pat[4]
247
+ addPattern(type, Regexp.new(regExp), mode, postProc)
246
248
  end
247
249
  self.mode = defaultMode
248
250
  end
@@ -415,52 +417,7 @@ class TaskJuggler::TextParser
415
417
  end
416
418
  end
417
419
 
418
- # Start processing characters from the input.
419
- @startOfToken = sourceFileInfo
420
- loop do
421
- match = nil
422
- begin
423
- @activePatterns.each do |type, re, postProc|
424
- if (match = @cf.scan(re))
425
- if match == :scannerEOF
426
- if @scannerMode != @defaultMode
427
- # The stream resets the line number to 1. Since we still
428
- # know the start of the token, we setup @lineDelta so that
429
- # sourceFileInfo() returns the proper line number.
430
- @lineDelta = -(@startOfToken.lineNo - 1)
431
- error('runaway_token',
432
- "Unterminated token starting at #{@startOfToken}")
433
- end
434
- # We've found the end of an input file. Return a special token
435
- # that describes the end of a file.
436
- @finishLastFile = true
437
- return [ :eof, '<END>', @startOfToken ]
438
- end
439
-
440
- raise "#{re} matches empty string" if match.empty?
441
- # If we have a post processing method, call it now. It may modify
442
- # the type or the found token String.
443
- type, match = postProc.call(type, match) if postProc
444
-
445
- break if type.nil? # Ignore certain tokens with nil type.
446
-
447
- return [ type, match, @startOfToken ]
448
- end
449
- end
450
- rescue ArgumentError
451
- error('scan_encoding_error', $!.to_s)
452
- end
453
-
454
- if match.nil?
455
- if @cf.eof?
456
- error('unexpected_eof',
457
- "Unexpected end of file found")
458
- else
459
- error('no_token_match',
460
- "Unexpected characters found: '#{@cf.peek(10)}...'")
461
- end
462
- end
463
- end
420
+ scanToken
464
421
  end
465
422
 
466
423
  # Return a token to retrieve it with the next nextToken() call again. Only 1
@@ -515,6 +472,64 @@ class TaskJuggler::TextParser
515
472
 
516
473
  private
517
474
 
475
+ def scanToken
476
+ @startOfToken = sourceFileInfo
477
+ begin
478
+ match = nil
479
+ loop do
480
+ # First make sure that the line buffer has been filled and we have a
481
+ # line to parse.
482
+ unless @cf.readyNextLine
483
+ if @scannerMode != @defaultMode
484
+ # The stream resets the line number to 1. Since we still
485
+ # know the start of the token, we setup @lineDelta so that
486
+ # sourceFileInfo() returns the proper line number.
487
+ @lineDelta = -(@startOfToken.lineNo - 1)
488
+ error('runaway_token',
489
+ "Unterminated token starting at line #{@startOfToken}")
490
+ end
491
+ # We've found the end of an input file. Return a special token
492
+ # that describes the end of a file.
493
+ @finishLastFile = true
494
+ return [ :eof, '<END>', @startOfToken ]
495
+ end
496
+
497
+ @activePatterns.each do |type, re, postProc|
498
+ if (match = @cf.scan(re))
499
+ #raise "#{re} matches empty string" if match.empty?
500
+ # If we have a post processing method, call it now. It may modify
501
+ # the type or the found token String.
502
+ type, match = postProc.call(type, match) if postProc
503
+
504
+ break if type.nil? # Ignore certain tokens with nil type.
505
+
506
+ @cf.cleanupMacroStack
507
+ return [ type, match, @startOfToken ]
508
+ end
509
+ end
510
+
511
+ if match.nil?
512
+ # If we haven't found a match, we either hit EOF or a token we did
513
+ # not expect.
514
+ if @cf.eof?
515
+ error('unexpected_eof',
516
+ "Unexpected end of file found")
517
+ else
518
+ error('no_token_match',
519
+ "Unexpected characters found: '#{@cf.peek(10)}...'")
520
+ end
521
+ else
522
+ # Remove completely scanned expanded macros from stack.
523
+ @cf.cleanupMacroStack
524
+ end
525
+ end
526
+ rescue ArgumentError
527
+ # This is triggered by StringScanner.scan, but we don't want to put
528
+ # the block in the inner loops for performance reasons.
529
+ error('scan_encoding_error', $!.to_s)
530
+ end
531
+ end
532
+
518
533
  def message(type, id, text, sfi, data)
519
534
  unless text.empty?
520
535
  line = @cf ? @cf.line : nil
@@ -14,7 +14,7 @@
14
14
  require 'taskjuggler/UTF8String'
15
15
  require 'taskjuggler/AppConfig'
16
16
 
17
- AppConfig.version = '3.2.0'
17
+ AppConfig.version = '3.3.0'
18
18
  AppConfig.packageName = 'taskjuggler'
19
19
  AppConfig.softwareName = 'TaskJuggler'
20
20
  AppConfig.packageInfo = 'A Project Management Software'
@@ -247,6 +247,11 @@ exactly it will be assigned to the task. Shifts and limits can be used to
247
247
  restrict the allocation to certain time intervals or to limit them to a
248
248
  certain maximum per time period. The purge statement can be used to remove
249
249
  inherited allocations or flags.
250
+
251
+ For effort-based tasks the task duration is clipped to only extend from the
252
+ begining of the first allocation to the end of the last allocation. This is
253
+ done to optimize for an overall minimum project duration as dependent tasks
254
+ can potentially use the unallocated, clipped slots.
250
255
  EOT
251
256
  )
252
257
  example('Allocate-1', '1')
@@ -611,7 +616,7 @@ consists of one or more accounts. Each account must be a leaf account. The
611
616
  account ID may be followed by a percentage value that determines the share for
612
617
  this account. The total percentage of all accounts must be exactly 100%. If
613
618
  some accounts don't have a percentage specification, the remainder to 100% is
614
- distributed evenly to them.
619
+ distributed evenly between them.
615
620
  EOT
616
621
  )
617
622
  end
@@ -731,7 +736,7 @@ which cells the text should be used. If multiple celltext patterns are
731
736
  provided for a column, the first matching one is taken for each cell.
732
737
  EOT
733
738
  )
734
- arg(1, 'text',
739
+ arg(2, 'text',
735
740
  'Alterntive cell text specified as [[Rich_Text_Attributes|Rich Text]]')
736
741
 
737
742
  pattern(%w( _cellcolor !logicalExpression !color ), lambda {
@@ -1012,7 +1017,7 @@ EOT
1012
1017
 
1013
1018
  def rule_export
1014
1019
  pattern(%w( !exportHeader !exportBody ), lambda {
1015
- @property = nil
1020
+ @property = @property.parent
1016
1021
  })
1017
1022
  doc('export', <<'EOT'
1018
1023
  The export report looks like a regular TaskJuggler file with the provided
@@ -1033,30 +1038,6 @@ EOT
1033
1038
  example('Export')
1034
1039
  end
1035
1040
 
1036
- def rule_exportHeader
1037
- pattern(%w( _export !optionalID $STRING ), lambda {
1038
- newReport(@val[1], @val[2], :export, @sourceFileInfo[0])
1039
- @property.set('formats', [ :tjp ])
1040
-
1041
- # By default, we export all scenarios.
1042
- scenarios = Array.new(@project.scenarios.items) { |i| i }
1043
- scenarios.delete_if { |sc| !@project.scenario(sc).get('active') }
1044
- @property.set('scenarios', scenarios)
1045
- # Show all tasks, sorted by seqno-up.
1046
- @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
1047
- @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
1048
- # Show all resources, sorted by seqno-up.
1049
- @property.set('hideResource',
1050
- LogicalExpression.new(LogicalOperation.new(0)))
1051
- @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
1052
- })
1053
- arg(2, 'file name', <<'EOT'
1054
- The name of the report file to generate. It must end with a .tjp or .tji
1055
- extension, or use . to use the standard output channel.
1056
- EOT
1057
- )
1058
- end
1059
-
1060
1041
  def rule_exportAttributes
1061
1042
  optional
1062
1043
  repeatable
@@ -1078,10 +1059,26 @@ EOT
1078
1059
  'projecids' => 'Include project IDs',
1079
1060
  'tasks' => 'Include task definitions',
1080
1061
  'resources' => 'Include resource definitions' })
1062
+
1063
+ pattern(%w( _formats !exportFormats ), lambda {
1064
+ @property.set('formats', @val[1])
1065
+ })
1066
+ level(:beta)
1067
+ doc('formats.export', <<'EOT'
1068
+ This attribute defines for which output formats the export report should be
1069
+ generated. By default, the TJP format will be used.
1070
+ EOT
1071
+ )
1072
+
1081
1073
  pattern(%w( !hideresource ))
1082
1074
  pattern(%w( !hidetask ))
1075
+
1076
+ pattern(%w( !loadunit ))
1077
+
1078
+ pattern(%w( !purge ))
1083
1079
  pattern(%w( !reportEnd ))
1084
1080
  pattern(%w( !reportPeriod ))
1081
+ pattern(%w( !reports ))
1085
1082
  pattern(%w( !reportStart ))
1086
1083
 
1087
1084
  pattern(%w( _resourceattributes !exportableResourceAttributes ), lambda {
@@ -1131,6 +1128,24 @@ EOT
1131
1128
  'priority' => 'Include priorities',
1132
1129
  'responsible' => 'Include responsible resource' })
1133
1130
 
1131
+ pattern(%w( _taskroot !taskId), lambda {
1132
+ if @val[1].leaf?
1133
+ error('taskroot_leaf',
1134
+ "#{@val[1].fullId} is not a container task",
1135
+ @sourceFileInfo[1])
1136
+ end
1137
+ @property.set('taskroot', @val[1])
1138
+ })
1139
+ level(:experimental)
1140
+ doc('taskroot.export', <<'EOT'
1141
+ Only tasks below the specified root-level tasks are exported. The exported
1142
+ tasks will have the ID of the root-level task stripped from their ID, so that
1143
+ the sub-tasks of the root-level task become top-level tasks in the report
1144
+ file.
1145
+ EOT
1146
+ )
1147
+ example('TaskRoot')
1148
+
1134
1149
  pattern(%w( _timezone !validTimeZone ), lambda {
1135
1150
  @property.set('timezone', @val[1])
1136
1151
  })
@@ -1142,6 +1157,72 @@ EOT
1142
1157
  optionsRule('exportAttributes')
1143
1158
  end
1144
1159
 
1160
+ def rule_exportFormat
1161
+ pattern(%w( _tjp ), lambda {
1162
+ :tjp
1163
+ })
1164
+ descr('Export of the scheduled project in TJP syntax.')
1165
+
1166
+ pattern(%w( _mspxml ), lambda {
1167
+ :mspxml
1168
+ })
1169
+ descr(<<'EOT'
1170
+ Export of the scheduled project in Microsoft Project XML format. This will
1171
+ export the data of the fully scheduled project. The exported data include the
1172
+ tasks, resources and the assignments of resources to task. This is only a
1173
+ small subset of the data that TaskJuggler can manage. This export is intended
1174
+ to share resource assignment data with other teams using Microsoft Project.
1175
+ TaskJuggler manages assignments with a larger accuracy than the Microsft
1176
+ Project XML format can represent. This will inevitably lead to some rounding
1177
+ errors and different interpretation of the data. The numbers you will see in
1178
+ Project are not necessarily an exact match of the numbers you see in
1179
+ TaskJuggler.
1180
+ EOT
1181
+ )
1182
+ end
1183
+
1184
+ def rule_exportFormats
1185
+ pattern(%w( !exportFormat !moreExportFormats ), lambda {
1186
+ [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
1187
+ })
1188
+ end
1189
+
1190
+ def rule_exportHeader
1191
+ pattern(%w( _export !optionalID $STRING ), lambda {
1192
+ newReport(@val[1], @val[2], :export, @sourceFileInfo[0])
1193
+ unless @property.modified?('formats')
1194
+ @property.set('formats', [ :tjp ])
1195
+ end
1196
+
1197
+ # By default, we export all scenarios.
1198
+ unless @property.modified?('scenarios')
1199
+ scenarios = Array.new(@project.scenarios.items) { |i| i }
1200
+ scenarios.delete_if { |sc| !@project.scenario(sc).get('active') }
1201
+ @property.set('scenarios', scenarios)
1202
+ end
1203
+ # Show all tasks, sorted by seqno-up.
1204
+ unless @property.modified?('hideTask')
1205
+ @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
1206
+ end
1207
+ unless @property.modified?('sortTasks')
1208
+ @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
1209
+ end
1210
+ # Show all resources, sorted by seqno-up.
1211
+ unless @property.modified?('hideResource')
1212
+ @property.set('hideResource',
1213
+ LogicalExpression.new(LogicalOperation.new(0)))
1214
+ end
1215
+ unless @property.modified?('sortResources')
1216
+ @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
1217
+ end
1218
+ })
1219
+ arg(2, 'file name', <<'EOT'
1220
+ The name of the report file to generate. It must end with a .tjp or .tji
1221
+ extension, or use . to use the standard output channel.
1222
+ EOT
1223
+ )
1224
+ end
1225
+
1145
1226
  def rule_extendAttributes
1146
1227
  optional
1147
1228
  repeatable
@@ -1912,12 +1993,23 @@ EOT
1912
1993
  error('zero_duration', "The interval duration may not be 0.",
1913
1994
  @sourceFileInfo[1])
1914
1995
  end
1915
- duration = @val[0] * convFactors[@val[1]]
1996
+ duration = (@val[0] * convFactors[@val[1]]).to_i
1916
1997
  resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
1998
+ if @val[1] == 4
1999
+ # If the duration unit is months, we have to align the duration with
2000
+ # the timing resolution of the project.
2001
+ duration = (duration / resolution).to_i * resolution
2002
+ end
1917
2003
  # Make sure the interval aligns with the timing resolution.
1918
- (duration / resolution).to_i * resolution
2004
+ if duration % resolution != 0
2005
+ error('iv_duration_not_aligned',
2006
+ "The interval duration must be a multiple of the specified " +
2007
+ "timing resolution (#{resolution / 60} min) of the project.")
2008
+ end
2009
+ duration
1919
2010
  })
1920
- arg(0, 'duration', 'The duration of the interval. May not be 0.')
2011
+ arg(0, 'duration', 'The duration of the interval. May not be 0 and must ' +
2012
+ 'be a multiple of [[timingresolution]].')
1921
2013
  end
1922
2014
 
1923
2015
  def rule_intervalEnd
@@ -1993,6 +2085,14 @@ EOT
1993
2085
  This mode only yields entries if used in the context of a task. It contains
1994
2086
  all journal entries that are dated in the query interval for the task and all
1995
2087
  its sub tasks.
2088
+ EOT
2089
+ )
2090
+ pattern(%w( _status_dep ), lambda { :status_dep })
2091
+ descr(<<'EOT'
2092
+ In this mode only the last entries before the report end date for each
2093
+ property and all its sub-properties and their dependencies are included. If
2094
+ there are multiple entries at the exact same date, then all these entries are
2095
+ included.
1996
2096
  EOT
1997
2097
  )
1998
2098
  pattern(%w( _status_down ), lambda { :status_down })
@@ -2009,6 +2109,16 @@ property are included. If there are multiple entries at the exact same date,
2009
2109
  then all these entries are included. If any of the parent properties has a
2010
2110
  more recent entry that is still before the report end date, no entries will be
2011
2111
  included.
2112
+ EOT
2113
+ )
2114
+ pattern(%w( _alerts_dep ), lambda { :alerts_dep })
2115
+ descr(<<'EOT'
2116
+ In this mode only the last entries before the report end date for the context
2117
+ property and all its sub-properties and their dependencies is included. If
2118
+ there are multiple entries at the exact same date, then all these entries are
2119
+ included. In contrast to the ''''status_down'''' mode, only entries with an
2120
+ alert level above the default level, and only those with the highest overall
2121
+ alert level are included.
2012
2122
  EOT
2013
2123
  )
2014
2124
  pattern(%w( _alerts_down ), lambda { :alerts_down })
@@ -2412,6 +2522,16 @@ EOT
2412
2522
  end
2413
2523
 
2414
2524
  def rule_loadunit
2525
+ pattern(%w( _loadunit !loadunitName ), lambda {
2526
+ @property.set('loadUnit', @val[1])
2527
+ })
2528
+ doc('loadunit', <<'EOT'
2529
+ Determines what unit should be used to display all load values in this report.
2530
+ EOT
2531
+ )
2532
+ end
2533
+
2534
+ def rule_loadunitName
2415
2535
  pattern([ '_days' ], lambda { :days })
2416
2536
  descr('Display all load and duration values as days.')
2417
2537
 
@@ -2455,7 +2575,7 @@ EOT
2455
2575
  LogicalExpression.new(@val[0], sourceFileInfo)
2456
2576
  })
2457
2577
  pattern(%w( _@ !allOrNone ), lambda {
2458
- LogicalOperation.new(@val[1])
2578
+ LogicalExpression.new(LogicalOperation.new(@val[1]), sourceFileInfo)
2459
2579
  })
2460
2580
  doc('logicalexpression', <<'EOT'
2461
2581
  A logical expression is a combination of operands and mathematical operations.
@@ -2559,6 +2679,10 @@ EOT
2559
2679
  commaListRule('!taskDep')
2560
2680
  end
2561
2681
 
2682
+ def rule_moreExportFormats
2683
+ commaListRule('!exportFormat')
2684
+ end
2685
+
2562
2686
  def rule_moreJournalSortCriteria
2563
2687
  commaListRule('!journalSortCriterium')
2564
2688
  end
@@ -2909,6 +3033,17 @@ EOT
2909
3033
  @val[0] / 100.0
2910
3034
  })
2911
3035
  end
3036
+ def rule_optionalScenarioIdCol
3037
+ optional
3038
+ pattern(%w( $ID_WITH_COLON ), lambda {
3039
+ if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
3040
+ error('unknown_scenario_id', "Unknown scenario: #{@val[0]}",
3041
+ @sourceFileInfo[0])
3042
+ end
3043
+ @scenarioIdx
3044
+ })
3045
+ end
3046
+
2912
3047
 
2913
3048
  def rule_optionalVersion
2914
3049
  optional
@@ -3447,21 +3582,27 @@ EOT
3447
3582
  end
3448
3583
 
3449
3584
  def rule_purge
3450
- pattern(%w( _purge $ID ), lambda {
3451
- if (attributeDefinition = @property.attributeDefinition(@val[1])).nil?
3585
+ pattern(%w( _purge !optionalScenarioIdCol $ID ), lambda {
3586
+ attrId = @val[2]
3587
+ if (attributeDefinition = @property.attributeDefinition(attrId)).nil?
3452
3588
  error('purge_unknown_id',
3453
- "#{@val[1]} is not a known attribute for this property",
3454
- @sourceFileInfo[1])
3589
+ "#{attrId} is not a known attribute for this property",
3590
+ @sourceFileInfo[2])
3455
3591
  end
3456
3592
  if attributeDefinition.scenarioSpecific
3457
- attr = @property[@val[1], 0]
3593
+ @scenarioIdx = 0 unless @val[1]
3594
+ attr = @property[attrId, 0]
3458
3595
  else
3459
- attr = @property.get(@val[1])
3596
+ if @val[1]
3597
+ error('purge_non_sc_spec_attr',
3598
+ 'Scenario specified for a non-scenario specific attribute')
3599
+ end
3600
+ attr = @property.get(attrId)
3460
3601
  end
3461
- if @property.attributeDefinition(@val[1]).scenarioSpecific
3462
- @property.getAttribute(@val[1], @scenarioIdx).reset
3602
+ if @property.attributeDefinition(attrId).scenarioSpecific
3603
+ @property.getAttribute(attrId, @scenarioIdx).reset
3463
3604
  else
3464
- @property.getAttribute(@val[1]).reset
3605
+ @property.getAttribute(attrId).reset
3465
3606
  end
3466
3607
  })
3467
3608
  doc('purge', <<'EOT'
@@ -3475,6 +3616,10 @@ the list that was inherited from the enclosing property. The purge
3475
3616
  attribute resets any attribute to its default value. A subsequent definition
3476
3617
  for the attribute within the property will then add their values to an empty
3477
3618
  list. The value of the enclosing property is not affected by purge.
3619
+
3620
+ For scenario specific attributes, an optional scenario ID can be specified
3621
+ before the attribute ID. If it's missing, the default (first) scenario will be
3622
+ used.
3478
3623
  EOT
3479
3624
  )
3480
3625
  arg(1, 'attribute', 'Any name of a list attribute')
@@ -3506,6 +3651,7 @@ EOT
3506
3651
 
3507
3652
  def rule_reports
3508
3653
  pattern(%w( !accountReport ))
3654
+ pattern(%w( !export ))
3509
3655
  pattern(%w( !resourceReport ))
3510
3656
  pattern(%w( !taskReport ))
3511
3657
  pattern(%w( !textReport ))
@@ -3524,14 +3670,14 @@ EOT
3524
3670
  singlePattern('_annualleave')
3525
3671
  descr(<<'EOT'
3526
3672
  The number of annual leave units within the reported time period. The unit
3527
- can be adjusted with [[loadunit]].
3673
+ can be adjusted with [[loadunit.report]].
3528
3674
  EOT
3529
3675
  )
3530
3676
 
3531
3677
  singlePattern('_annualleavebalance')
3532
3678
  descr(<<'EOT'
3533
3679
  The balance of the annual leave at the end of the reporting interval. The unit
3534
- can be adjusted with [[loadunit]].
3680
+ can be adjusted with [[loadunit.report]].
3535
3681
  EOT
3536
3682
  )
3537
3683
 
@@ -3880,14 +4026,14 @@ EOT
3880
4026
  singlePattern('_sickleave')
3881
4027
  descr(<<'EOT'
3882
4028
  The number of sick leave units within the reported time period. The unit can
3883
- be adjusted with [[loadunit]].
4029
+ be adjusted with [[loadunit.report]].
3884
4030
  EOT
3885
4031
  )
3886
4032
 
3887
4033
  singlePattern('_specialleave')
3888
4034
  descr(<<'EOT'
3889
4035
  The number of special leave units within the reported time period. The unit
3890
- can be adjusted with [[loadunit]].
4036
+ can be adjusted with [[loadunit.report]].
3891
4037
  EOT
3892
4038
  )
3893
4039
 
@@ -3921,7 +4067,7 @@ EOT
3921
4067
  singlePattern('_unpaidleave')
3922
4068
  descr(<<'EOT'
3923
4069
  The number of unpaid leave units within the reported time period. The unit
3924
- can be adjusted with [[loadunit]].
4070
+ can be adjusted with [[loadunit.report]].
3925
4071
  EOT
3926
4072
  )
3927
4073
 
@@ -4084,13 +4230,7 @@ EOT
4084
4230
  )
4085
4231
  example('textreport')
4086
4232
 
4087
- pattern(%w( _loadunit !loadunit ), lambda {
4088
- @property.set('loadUnit', @val[1])
4089
- })
4090
- doc('loadunit', <<'EOT'
4091
- Determines what unit should be used to display all load values in this report.
4092
- EOT
4093
- )
4233
+ pattern(%w( !loadunit ))
4094
4234
 
4095
4235
  pattern(%w( !numberFormat ), lambda {
4096
4236
  @property.set('numberFormat', @val[0])
@@ -4308,7 +4448,6 @@ EOT
4308
4448
  end
4309
4449
 
4310
4450
  def rule_reportProperties
4311
- pattern(%w( !export ))
4312
4451
  pattern(%w( !iCalReport ))
4313
4452
  pattern(%w( !nikuReport ))
4314
4453
  pattern(%w( !reports ))
@@ -4393,7 +4532,7 @@ EOT
4393
4532
  })
4394
4533
 
4395
4534
  pattern(%w( _supplement !resourceId !resourceBody ), lambda {
4396
- @property = @property.parent
4535
+ @property = @idStack.pop
4397
4536
  })
4398
4537
  doc('supplement.resource', <<'EOT'
4399
4538
  The supplement keyword provides a mechanism to add more attributes to already
@@ -5416,21 +5555,22 @@ EOT
5416
5555
 
5417
5556
  def rule_supplement
5418
5557
  pattern(%w( !supplementAccount !accountBody ), lambda {
5419
- @property = nil
5558
+ @property = @idStack.pop
5420
5559
  })
5421
5560
  pattern(%w( !supplementReport !reportBody ), lambda {
5422
- @property = nil
5561
+ @property = @idStack.pop
5423
5562
  })
5424
5563
  pattern(%w( !supplementResource !resourceBody ), lambda {
5425
- @property = nil
5564
+ @property = @idStack.pop
5426
5565
  })
5427
5566
  pattern(%w( !supplementTask !taskBody ), lambda {
5428
- @property = nil
5567
+ @property = @idStack.pop
5429
5568
  })
5430
5569
  end
5431
5570
 
5432
5571
  def rule_supplementAccount
5433
5572
  pattern(%w( _account !accountId ), lambda {
5573
+ @idStack.push(@property)
5434
5574
  @property = @val[1]
5435
5575
  })
5436
5576
  arg(1, 'account ID', 'The ID of an already defined account.')
@@ -5438,6 +5578,7 @@ EOT
5438
5578
 
5439
5579
  def rule_supplementReport
5440
5580
  pattern(%w( _report !reportId ), lambda {
5581
+ @idStack.push(@property)
5441
5582
  @property = @val[1]
5442
5583
  })
5443
5584
  arg(1, 'report ID', 'The absolute ID of an already defined report.')
@@ -5445,6 +5586,7 @@ EOT
5445
5586
 
5446
5587
  def rule_supplementResource
5447
5588
  pattern(%w( _resource !resourceId ), lambda {
5589
+ @idStack.push(@property)
5448
5590
  @property = @val[1]
5449
5591
  })
5450
5592
  arg(1, 'resource ID', 'The ID of an already defined resource.')
@@ -5452,6 +5594,7 @@ EOT
5452
5594
 
5453
5595
  def rule_supplementTask
5454
5596
  pattern(%w( _task !taskId ), lambda {
5597
+ @idStack.push(@property)
5455
5598
  @property = @val[1]
5456
5599
  })
5457
5600
  arg(1, 'task ID', 'The absolute ID of an already defined task.')
@@ -5533,13 +5676,16 @@ EOT
5533
5676
  })
5534
5677
  level(:experimental)
5535
5678
  doc('adopt.task', <<'EOT'
5536
- Add a previously defined task to the sub-tasks of this task. This can be used
5537
- to create virtual sub projects that contain of task trees that were defined as
5538
- sub tasks of other tasks. Adopted tasks don't inherit anything from their step
5539
- parents. However, the adopting task is scheduled to fit all adopted childs as
5540
- well.
5679
+ Add a previously defined task and its sub-tasks to this task. This can be used
5680
+ to create virtual projects that contain task (sub-)trees that are originally
5681
+ defined in another task context. Adopted tasks don't inherit anything from
5682
+ their step parents. However, the adopting task is scheduled to fit all adopted
5683
+ sub-tasks.
5541
5684
 
5542
- A top-level tasks must never include the same task more than once.
5685
+ A top-level task and all its sub-tasks must never contain the same task more
5686
+ than once. All reports must use appropriate filters by setting [[taskroot]],
5687
+ [[hidetask]] or [[rolluptask]] to ensure that no tasks are contained more than
5688
+ once in the report.
5543
5689
  EOT
5544
5690
  )
5545
5691
 
@@ -5557,7 +5703,7 @@ EOT
5557
5703
  pattern(%w( !purge ))
5558
5704
 
5559
5705
  pattern(%w( _supplement !supplementTask !taskBody ), lambda {
5560
- @property = @property.parent
5706
+ @property = @idStack.pop
5561
5707
  })
5562
5708
  doc('supplement.task', <<'EOT'
5563
5709
  The supplement keyword provides a mechanism to add more attributes to already
@@ -6245,8 +6391,10 @@ EOT
6245
6391
  @property['scheduled', @scenarioIdx] = true
6246
6392
  })
6247
6393
  doc('scheduled', <<'EOT'
6248
- This is mostly for internal use. It specifies that the task can be ignored for
6249
- scheduling in the scenario.
6394
+ This is mostly for internal use. It specifies that the task should be ignored
6395
+ for scheduling in the scenario. This option only makes sense if you provide
6396
+ all resource [[booking.resource|bookings]] manually. Without booking
6397
+ statements, the task will be reported with 0 effort and no resources assigned.
6250
6398
  EOT
6251
6399
  )
6252
6400