taskjuggler 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (338) hide show
  1. data/CHANGELOG +35 -0
  2. data/data/tjp.vim +21 -7
  3. data/lib/taskjuggler/Allocation.rb +27 -3
  4. data/lib/taskjuggler/Attributes.rb +3 -2
  5. data/lib/taskjuggler/HTMLDocument.rb +3 -1
  6. data/lib/taskjuggler/KateSyntax.rb +213 -0
  7. data/lib/taskjuggler/Limits.rb +22 -0
  8. data/lib/taskjuggler/Log.rb +1 -1
  9. data/lib/taskjuggler/MessageHandler.rb +20 -10
  10. data/lib/taskjuggler/PTNProxy.rb +6 -1
  11. data/lib/taskjuggler/Project.rb +10 -4
  12. data/lib/taskjuggler/ProjectFileParser.rb +1 -2
  13. data/lib/taskjuggler/ProjectFileScanner.rb +41 -42
  14. data/lib/taskjuggler/ResourceScenario.rb +41 -1
  15. data/lib/taskjuggler/RichText/Element.rb +8 -0
  16. data/lib/taskjuggler/RichText/Parser.rb +1 -1
  17. data/lib/taskjuggler/RichText/RTFReportLink.rb +20 -10
  18. data/lib/taskjuggler/RichText/Scanner.rb +54 -38
  19. data/lib/taskjuggler/RichText/SyntaxRules.rb +12 -0
  20. data/lib/taskjuggler/SheetReceiver.rb +1 -1
  21. data/lib/taskjuggler/TableColumnDefinition.rb +5 -1
  22. data/lib/taskjuggler/TaskJuggler.rb +2 -2
  23. data/lib/taskjuggler/TaskScenario.rb +117 -33
  24. data/lib/taskjuggler/TextParser.rb +2 -4
  25. data/lib/taskjuggler/TextParser/MacroTable.rb +7 -0
  26. data/lib/taskjuggler/TextParser/Scanner.rb +10 -9
  27. data/lib/taskjuggler/Tj3Config.rb +1 -1
  28. data/lib/taskjuggler/TjTime.rb +5 -28
  29. data/lib/taskjuggler/TjpSyntaxRules.rb +85 -13
  30. data/lib/taskjuggler/UTF8String.rb +5 -0
  31. data/lib/taskjuggler/XMLElement.rb +2 -1
  32. data/lib/taskjuggler/apps/Tj3.rb +29 -5
  33. data/lib/taskjuggler/daemon/ProcessIntercom.rb +1 -1
  34. data/lib/taskjuggler/daemon/ProjectServer.rb +5 -2
  35. data/lib/taskjuggler/daemon/ReportServer.rb +7 -4
  36. data/lib/taskjuggler/reports/AccountListRE.rb +2 -0
  37. data/lib/taskjuggler/reports/CSVFile.rb +24 -2
  38. data/lib/taskjuggler/reports/GanttChart.rb +3 -2
  39. data/lib/taskjuggler/reports/GanttHeader.rb +18 -18
  40. data/lib/taskjuggler/reports/GanttLoadStack.rb +1 -1
  41. data/lib/taskjuggler/reports/MspXmlRE.rb +5 -1
  42. data/lib/taskjuggler/reports/Report.rb +29 -18
  43. data/lib/taskjuggler/reports/ReportTable.rb +5 -1
  44. data/lib/taskjuggler/reports/ReportTableCell.rb +16 -10
  45. data/lib/taskjuggler/reports/ResourceListRE.rb +2 -0
  46. data/lib/taskjuggler/reports/TableReport.rb +23 -16
  47. data/lib/taskjuggler/reports/TaskListRE.rb +2 -0
  48. data/lib/taskjuggler/reports/TraceReport.rb +1 -1
  49. data/manual/Installation +5 -1
  50. data/manual/Intro +1 -0
  51. data/manual/Rich_Text_Attributes +5 -0
  52. data/manual/TaskJuggler_Internals +82 -34
  53. data/manual/Tutorial +1 -1
  54. data/manual/html/Day_To_Day_Juggling.html +1 -1
  55. data/manual/html/Getting_Started.html +1 -1
  56. data/manual/html/How_To_Contribute.html +1 -1
  57. data/manual/html/Installation.html +3 -2
  58. data/manual/html/Intro.html +2 -1
  59. data/manual/html/Reporting_Bugs.html +1 -1
  60. data/manual/html/Rich_Text_Attributes.html +2 -1
  61. data/manual/html/Software.html +1 -1
  62. data/manual/html/TaskJuggler_2x_Migration.html +1 -1
  63. data/manual/html/TaskJuggler_Internals.html +15 -13
  64. data/manual/html/The_TaskJuggler_Syntax.html +1 -1
  65. data/manual/html/Tutorial.html +2 -2
  66. data/manual/html/account.html +1 -1
  67. data/manual/html/account.task.html +1 -1
  68. data/manual/html/accountprefix.html +1 -1
  69. data/manual/html/accountreport.html +14 -2
  70. data/manual/html/accountroot.html +1 -1
  71. data/manual/html/active.html +1 -1
  72. data/manual/html/adopt.task.html +1 -1
  73. data/manual/html/aggregate.html +1 -1
  74. data/manual/html/alert.html +1 -1
  75. data/manual/html/alertlevels.html +1 -1
  76. data/manual/html/allocate.html +1 -1
  77. data/manual/html/alphabet.html +1 -1
  78. data/manual/html/alternative.html +1 -1
  79. data/manual/html/author.html +3 -3
  80. data/manual/html/auxdir.html +69 -0
  81. data/manual/html/balance.html +3 -3
  82. data/manual/html/booking.resource.html +1 -1
  83. data/manual/html/booking.task.html +1 -1
  84. data/manual/html/caption.html +1 -1
  85. data/manual/html/cellcolor.column.html +1 -1
  86. data/manual/html/celltext.column.html +1 -1
  87. data/manual/html/center.html +1 -1
  88. data/manual/html/charge.html +1 -1
  89. data/manual/html/chargeset.html +1 -1
  90. data/manual/html/columnid.html +21 -9
  91. data/manual/html/columns.html +2 -2
  92. data/manual/html/complete.html +1 -1
  93. data/manual/html/copyright.html +1 -1
  94. data/manual/html/credits.html +1 -1
  95. data/manual/html/currency.html +1 -1
  96. data/manual/html/currencyformat.html +1 -1
  97. data/manual/html/dailymax.html +1 -1
  98. data/manual/html/dailymin.html +1 -1
  99. data/manual/html/dailyworkinghours.html +1 -1
  100. data/manual/html/date.extend.html +1 -1
  101. data/manual/html/date.html +1 -1
  102. data/manual/html/definitions.html +1 -1
  103. data/manual/html/depends.html +1 -1
  104. data/manual/html/details.html +1 -1
  105. data/manual/html/disabled.html +1 -1
  106. data/manual/html/duration.html +1 -1
  107. data/manual/html/efficiency.html +1 -1
  108. data/manual/html/effort.html +1 -1
  109. data/manual/html/email.html +1 -1
  110. data/manual/html/enabled.html +1 -1
  111. data/manual/html/end.column.html +1 -1
  112. data/manual/html/end.html +1 -1
  113. data/manual/html/end.limit.html +1 -1
  114. data/manual/html/end.report.html +1 -1
  115. data/manual/html/end.timesheet.html +1 -1
  116. data/manual/html/endcredit.html +1 -1
  117. data/manual/html/epilog.html +1 -1
  118. data/manual/html/export.html +1 -1
  119. data/manual/html/extend.html +1 -1
  120. data/manual/html/fail.html +1 -1
  121. data/manual/html/fdl.html +1 -1
  122. data/manual/html/flags.account.html +1 -1
  123. data/manual/html/flags.html +1 -1
  124. data/manual/html/flags.journalentry.html +1 -1
  125. data/manual/html/flags.report.html +1 -1
  126. data/manual/html/flags.resource.html +1 -1
  127. data/manual/html/flags.statussheet.html +1 -1
  128. data/manual/html/flags.task.html +1 -1
  129. data/manual/html/flags.timesheet.html +1 -1
  130. data/manual/html/fontcolor.column.html +1 -1
  131. data/manual/html/footer.html +1 -1
  132. data/manual/html/formats.export.html +1 -1
  133. data/manual/html/formats.html +1 -1
  134. data/manual/html/functions.html +1 -1
  135. data/manual/html/gapduration.html +1 -1
  136. data/manual/html/gaplength.html +1 -1
  137. data/manual/html/halign.center.html +1 -1
  138. data/manual/html/halign.column.html +1 -1
  139. data/manual/html/halign.left.html +1 -1
  140. data/manual/html/halign.right.html +1 -1
  141. data/manual/html/hasalert.html +1 -1
  142. data/manual/html/header.html +1 -1
  143. data/manual/html/headline.html +1 -1
  144. data/manual/html/height.html +1 -1
  145. data/manual/html/hideaccount.html +1 -1
  146. data/manual/html/hidejournalentry.html +1 -1
  147. data/manual/html/hidereport.html +1 -1
  148. data/manual/html/hideresource.html +1 -1
  149. data/manual/html/hidetask.html +1 -1
  150. data/manual/html/icalreport.html +1 -1
  151. data/manual/html/include.macro.html +1 -1
  152. data/manual/html/include.project.html +1 -1
  153. data/manual/html/include.properties.html +1 -1
  154. data/manual/html/index.html +1 -1
  155. data/manual/html/inherit.extend.html +1 -1
  156. data/manual/html/interval1.html +1 -1
  157. data/manual/html/interval2.html +1 -1
  158. data/manual/html/interval3.html +1 -1
  159. data/manual/html/interval4.html +1 -1
  160. data/manual/html/isactive.html +1 -1
  161. data/manual/html/ischildof.html +1 -1
  162. data/manual/html/isdependencyof.html +1 -1
  163. data/manual/html/isdutyof.html +1 -1
  164. data/manual/html/isfeatureof.html +1 -1
  165. data/manual/html/isleaf.html +1 -1
  166. data/manual/html/ismilestone.html +1 -1
  167. data/manual/html/isongoing.html +1 -1
  168. data/manual/html/isresource.html +1 -1
  169. data/manual/html/isresponsibilityof.html +1 -1
  170. data/manual/html/istask.html +1 -1
  171. data/manual/html/journalattributes.html +1 -1
  172. data/manual/html/journalentry.html +1 -1
  173. data/manual/html/journalmode.html +1 -1
  174. data/manual/html/leaveallowance.html +1 -1
  175. data/manual/html/leaves.html +1 -1
  176. data/manual/html/left.html +1 -1
  177. data/manual/html/length.html +1 -1
  178. data/manual/html/limits.allocate.html +1 -1
  179. data/manual/html/limits.html +1 -1
  180. data/manual/html/limits.resource.html +1 -1
  181. data/manual/html/limits.task.html +1 -1
  182. data/manual/html/listitem.column.html +1 -1
  183. data/manual/html/listtype.column.html +1 -1
  184. data/manual/html/loadunit.html +1 -1
  185. data/manual/html/logicalexpression.html +1 -1
  186. data/manual/html/logicalflagexpression.html +1 -1
  187. data/manual/html/macro.html +1 -1
  188. data/manual/html/managers.html +1 -1
  189. data/manual/html/mandatory.html +1 -1
  190. data/manual/html/maxend.html +1 -1
  191. data/manual/html/maximum.html +1 -1
  192. data/manual/html/maxstart.html +1 -1
  193. data/manual/html/milestone.html +1 -1
  194. data/manual/html/minend.html +1 -1
  195. data/manual/html/minimum.html +1 -1
  196. data/manual/html/minstart.html +1 -1
  197. data/manual/html/monthlymax.html +1 -1
  198. data/manual/html/monthlymin.html +1 -1
  199. data/manual/html/navbar.html +9 -1
  200. data/manual/html/navigator.html +1 -1
  201. data/manual/html/newtask.html +1 -1
  202. data/manual/html/nikureport.html +1 -1
  203. data/manual/html/note.task.html +1 -1
  204. data/manual/html/now.html +1 -1
  205. data/manual/html/numberformat.html +1 -1
  206. data/manual/html/onend.html +1 -1
  207. data/manual/html/onstart.html +1 -1
  208. data/manual/html/opennodes.html +1 -1
  209. data/manual/html/overtime.booking.html +1 -1
  210. data/manual/html/period.column.html +1 -1
  211. data/manual/html/period.limit.html +1 -1
  212. data/manual/html/period.report.html +1 -1
  213. data/manual/html/period.task.html +1 -1
  214. data/manual/html/persistent.html +1 -1
  215. data/manual/html/precedes.html +1 -1
  216. data/manual/html/priority.html +1 -1
  217. data/manual/html/priority.timesheet.html +1 -1
  218. data/manual/html/project.html +1 -1
  219. data/manual/html/projectid.html +1 -1
  220. data/manual/html/projectid.task.html +1 -1
  221. data/manual/html/projectids.html +1 -1
  222. data/manual/html/projection.html +1 -1
  223. data/manual/html/prolog.html +1 -1
  224. data/manual/html/properties.html +1 -1
  225. data/manual/html/purge.html +1 -1
  226. data/manual/html/rate.html +1 -1
  227. data/manual/html/rate.resource.html +3 -3
  228. data/manual/html/rawhtmlhead.html +68 -0
  229. data/manual/html/reference.extend.html +3 -3
  230. data/manual/html/remaining.html +1 -1
  231. data/manual/html/replace.html +1 -1
  232. data/manual/html/reportprefix.html +1 -1
  233. data/manual/html/resource.html +1 -1
  234. data/manual/html/resourceattributes.html +1 -1
  235. data/manual/html/resourceprefix.html +1 -1
  236. data/manual/html/resourcereport.html +14 -2
  237. data/manual/html/resourceroot.html +1 -1
  238. data/manual/html/resources.limit.html +1 -1
  239. data/manual/html/responsible.html +1 -1
  240. data/manual/html/richtext.extend.html +1 -1
  241. data/manual/html/right.html +1 -1
  242. data/manual/html/rollupaccount.html +1 -1
  243. data/manual/html/rollupresource.html +1 -1
  244. data/manual/html/rolluptask.html +1 -1
  245. data/manual/html/scale.column.html +1 -1
  246. data/manual/html/scenario.html +1 -1
  247. data/manual/html/scenario.ical.html +1 -1
  248. data/manual/html/scenarios.export.html +1 -1
  249. data/manual/html/scenarios.html +1 -1
  250. data/manual/html/scenariospecific.extend.html +1 -1
  251. data/manual/html/scheduled.html +1 -1
  252. data/manual/html/scheduling.html +2 -1
  253. data/manual/html/select.html +1 -1
  254. data/manual/html/selfcontained.html +1 -1
  255. data/manual/html/shift.allocate.html +1 -1
  256. data/manual/html/shift.html +1 -1
  257. data/manual/html/shift.resource.html +1 -1
  258. data/manual/html/shift.task.html +1 -1
  259. data/manual/html/shift.timesheet.html +1 -1
  260. data/manual/html/shifts.allocate.html +1 -1
  261. data/manual/html/shifts.resource.html +1 -1
  262. data/manual/html/shifts.task.html +1 -1
  263. data/manual/html/shorttimeformat.html +1 -1
  264. data/manual/html/sloppy.booking.html +1 -1
  265. data/manual/html/sloppy.projection.html +1 -1
  266. data/manual/html/sortaccounts.html +1 -1
  267. data/manual/html/sortjournalentries.html +1 -1
  268. data/manual/html/sortresources.html +1 -1
  269. data/manual/html/sorttasks.html +1 -1
  270. data/manual/html/start.column.html +1 -1
  271. data/manual/html/start.html +1 -1
  272. data/manual/html/start.limit.html +1 -1
  273. data/manual/html/start.report.html +1 -1
  274. data/manual/html/startcredit.html +1 -1
  275. data/manual/html/status.statussheet.html +1 -1
  276. data/manual/html/status.timesheet.html +1 -1
  277. data/manual/html/statussheet.html +1 -1
  278. data/manual/html/statussheetreport.html +1 -1
  279. data/manual/html/strict.projection.html +1 -1
  280. data/manual/html/summary.html +1 -1
  281. data/manual/html/supplement.html +1 -1
  282. data/manual/html/supplement.resource.html +1 -1
  283. data/manual/html/supplement.task.html +1 -1
  284. data/manual/html/tagfile.html +2 -2
  285. data/manual/html/task.html +1 -1
  286. data/manual/html/task.statussheet.html +1 -1
  287. data/manual/html/task.timesheet.html +1 -1
  288. data/manual/html/taskattributes.html +1 -1
  289. data/manual/html/taskprefix.html +1 -1
  290. data/manual/html/taskreport.html +14 -2
  291. data/manual/html/taskroot.export.html +1 -1
  292. data/manual/html/taskroot.html +1 -1
  293. data/manual/html/text.extend.html +1 -1
  294. data/manual/html/textreport.html +14 -2
  295. data/manual/html/timeformat.html +3 -3
  296. data/manual/html/timeformat1.html +67 -0
  297. data/manual/html/timeformat2.html +67 -0
  298. data/manual/html/timeoff.nikureport.html +3 -3
  299. data/manual/html/timesheet.html +1 -1
  300. data/manual/html/timesheetreport.html +1 -1
  301. data/manual/html/timezone.export.html +1 -1
  302. data/manual/html/timezone.html +1 -1
  303. data/manual/html/timezone.report.html +1 -1
  304. data/manual/html/timezone.shift.html +1 -1
  305. data/manual/html/timingresolution.html +1 -1
  306. data/manual/html/title.column.html +1 -1
  307. data/manual/html/title.html +1 -1
  308. data/manual/html/toc.html +270 -242
  309. data/manual/html/tooltip.column.html +1 -1
  310. data/manual/html/tracereport.html +14 -2
  311. data/manual/html/trackingscenario.html +1 -1
  312. data/manual/html/treelevel.html +1 -1
  313. data/manual/html/vacation.html +1 -1
  314. data/manual/html/vacation.resource.html +1 -1
  315. data/manual/html/vacation.shift.html +1 -1
  316. data/manual/html/warn.html +1 -1
  317. data/manual/html/weeklymax.html +1 -1
  318. data/manual/html/weeklymin.html +1 -1
  319. data/manual/html/weekstartsmonday.html +1 -1
  320. data/manual/html/weekstartssunday.html +1 -1
  321. data/manual/html/width.column.html +1 -1
  322. data/manual/html/width.html +1 -1
  323. data/manual/html/work.html +1 -1
  324. data/manual/html/workinghours.project.html +1 -1
  325. data/manual/html/workinghours.resource.html +1 -1
  326. data/manual/html/workinghours.shift.html +1 -1
  327. data/manual/html/yearlyworkingdays.html +1 -1
  328. data/tasks/kate.rake +8 -0
  329. data/test/TestSuite/HTML-Reports/Calendars.tjp +10 -0
  330. data/test/TestSuite/Scheduler/Correct/PersistentResources-2.tjp +33 -0
  331. data/test/TestSuite/Scheduler/Correct/PersistentResources.tjp +30 -0
  332. data/test/TestSuite/Scheduler/Correct/PriorityInversion.tjp +2 -0
  333. data/test/TestSuite/Syntax/Correct/Macro-4.tjp +4 -0
  334. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
  335. data/test/test_BatchProcessor.rb +1 -1
  336. data/test/test_CSVFile.rb +10 -0
  337. data/test/test_RichText.rb +20 -0
  338. metadata +38 -9
@@ -36,7 +36,7 @@ class TaskJuggler
36
36
  @variables = [ :LINEBREAK, :SPACE, :WORD,
37
37
  :BOLD, :ITALIC, :CODE, :BOLDITALIC, :PRE,
38
38
  :HREF, :HREFEND, :REF, :REFEND, :HLINE,
39
- :FCOLSTART, :FCOLEND,
39
+ :HTMLBLOB, :FCOLSTART, :FCOLEND,
40
40
  :QUERY,
41
41
  :INLINEFUNCSTART, :INLINEFUNCEND,
42
42
  :BLOCKFUNCSTART, :BLOCKFUNCEND, :ID, :STRING,
@@ -31,20 +31,14 @@ class TaskJuggler
31
31
 
32
32
  # Not supported for this function
33
33
  def to_s(args)
34
- ''
34
+ report = checkArgs(args)
35
+
36
+ report.name
35
37
  end
36
38
 
37
39
  # Return a HTML tree for the report.
38
40
  def to_html(args)
39
- if args.nil? || (id = args['id']).nil?
40
- error('rtp_report_id',
41
- "Argument 'id' missing to specify the report to be used.")
42
- return nil
43
- end
44
- unless (report = @project.report(id))
45
- error('rtp_report_unknown_id', "Unknown report #{id}")
46
- return nil
47
- end
41
+ report = checkArgs(args)
48
42
 
49
43
  # The URL for interactive reports is different than for static reports.
50
44
  if report.interactive?
@@ -71,6 +65,22 @@ class TaskJuggler
71
65
  nil
72
66
  end
73
67
 
68
+ private
69
+
70
+ def checkArgs(args)
71
+ if args.nil? || (id = args['id']).nil?
72
+ error('rtp_report_id',
73
+ "Argument 'id' missing to specify the report to be used.")
74
+ return nil
75
+ end
76
+ unless (report = @project.report(id))
77
+ error('rtp_report_unknown_id', "Unknown report #{id}")
78
+ return nil
79
+ end
80
+
81
+ report
82
+ end
83
+
74
84
  end
75
85
 
76
86
  end
@@ -25,6 +25,7 @@ class TaskJuggler
25
25
  # :bol : at the begining of a line.
26
26
  # :inline : in the middle of a line
27
27
  # :nowiki : ignoring all MediaWiki special tokens
28
+ # :html : read anything until </html>
28
29
  # :ref : inside of a REF [[ .. ]]
29
30
  # :href : inside of an HREF [ .. ]
30
31
  # :func : inside of a block <[ .. ]> or inline <- .. -> function
@@ -33,66 +34,71 @@ class TaskJuggler
33
34
  def initialize(masterFile, log)
34
35
  tokenPatterns = [
35
36
  # :bol mode rules
36
- [ :LINEBREAK, '\s*\n', /\s*\n/, :bol, method('linebreak') ],
37
- [ nil, '\s+', /\s+/, :bol, method('inlineMode') ],
37
+ [ :LINEBREAK, /\s*\n/, :bol, method('linebreak') ],
38
+ [ nil, /\s+/, :bol, method('inlineMode') ],
38
39
 
39
40
  # :bop mode rules
40
- [ :PRE, ' [^\n]+\n?', / [^\n]+\n?/, :bop, method('pre') ],
41
- [ nil, '\s*\n', /\s*\n/, :bop, method('linebreak') ],
41
+ [ :PRE, / [^\n]+\n?/, :bop, method('pre') ],
42
+ [ nil, /\s*\n/, :bop, method('linebreak') ],
42
43
 
43
44
  # :inline mode rules
44
- [ :SPACE, '[ \t\n]+', /[ \t\n]+/, :inline, method('space') ],
45
+ [ :SPACE, /[ \t\n]+/, :inline, method('space') ],
45
46
 
46
47
  # :bop and :bol mode rules
47
- [ :INLINEFUNCSTART, '<-', /<-/, [ :bop, :bol, :inline ],
48
+ [ :INLINEFUNCSTART, /<-/, [ :bop, :bol, :inline ],
48
49
  method('functionStart') ],
49
- [ :BLOCKFUNCSTART, '<\[', /<\[/, [ :bop, :bol ], method('functionStart') ],
50
- [ ':TITLE*', '={2,5}', /={2,5}/, [ :bop, :bol ], method('titleStart') ],
51
- [ 'TITLE*END', '={2,5}', /={2,5}/, :inline, method('titleEnd') ],
52
- [ 'BULLET*', '\*{1,4}[ \t]+', /\*{1,4}[ \t]+/, [ :bop, :bol ], method('bullet') ],
53
- [ 'NUMBER*', '\#{1,4}[ \t]+', /\#{1,4}[ \t]+/, [ :bop, :bol ], method('number') ],
54
- [ :HLINE, '----', /----/, [ :bop, :bol ], method('inlineMode') ],
50
+ [ :BLOCKFUNCSTART, /<\[/, [ :bop, :bol ], method('functionStart') ],
51
+ [ ':TITLE*', /={2,5}/, [ :bop, :bol ], method('titleStart') ],
52
+ [ 'TITLE*END', /={2,5}/, :inline, method('titleEnd') ],
53
+ [ 'BULLET*', /\*{1,4}[ \t]+/, [ :bop, :bol ], method('bullet') ],
54
+ [ 'NUMBER*', /\#{1,4}[ \t]+/, [ :bop, :bol ], method('number') ],
55
+ [ :HLINE, /----/, [ :bop, :bol ], method('inlineMode') ],
55
56
 
56
57
  # :bop, :bol and :inline mode rules
57
58
  # The <nowiki> token puts the scanner into :nowiki mode.
58
- [ nil, '<nowiki>', /<nowiki>/, [ :bop, :bol, :inline ], method('nowikiStart') ],
59
- [ :FCOLSTART, '<fcol:([a-z]+|#[0-9A-Fa-f]{3,6})>', /<fcol:([a-z]+|#[0-9A-Fa-f]{3,6})>/, [ :bop, :bol,
59
+ [ nil, /<nowiki>/, [ :bop, :bol, :inline ], method('nowikiStart') ],
60
+ [ nil, /<html>/, [ :bop, :bol, :inline ], method('htmlStart') ],
61
+ [ :FCOLSTART, /<fcol:([a-z]+|#[0-9A-Fa-f]{3,6})>/, [ :bop, :bol,
60
62
  :inline ],
61
63
  method('fontColorStart') ],
62
- [ :FCOLEND, '<\/fcol>', /<\/fcol>/, [ :bop, :bol, :inline ],
64
+ [ :FCOLEND, /<\/fcol>/, [ :bop, :bol, :inline ],
63
65
  method('fontColorEnd') ],
64
- [ :QUOTES, '\'{2,5}', /'{2,5}/, [ :bop, :bol, :inline ], method('quotes') ],
65
- [ :REF, '\[\[', /\[\[/, [ :bop, :bol, :inline ], method('refStart') ],
66
- [ :HREF, '\[', /\[/, [ :bop, :bol, :inline], method('hrefStart') ],
67
- [ :WORD, '.[^ \n\t\[<\']*', /.[^ \n\t\[<']*/, [ :bop, :bol, :inline ],
66
+ [ :QUOTES, /'{2,5}/, [ :bop, :bol, :inline ], method('quotes') ],
67
+ [ :REF, /\[\[/, [ :bop, :bol, :inline ], method('refStart') ],
68
+ [ :HREF, /\[/, [ :bop, :bol, :inline], method('hrefStart') ],
69
+ [ :WORD, /.[^ \n\t\[<']*/, [ :bop, :bol, :inline ],
68
70
  method('inlineMode') ],
69
71
 
70
72
  # :nowiki mode rules
71
- [ nil, '<\/nowiki>', /<\/nowiki>/, :nowiki, method('nowikiEnd') ],
72
- [ :WORD, '(<(?!\/nowiki>)|[^ \t\n<])+', /(<(?!\/nowiki>)|[^ \t\n<])+/, :nowiki ],
73
- [ :SPACE, '[ \t]+', /[ \t]+/, :nowiki ],
74
- [ :LINEBREAK, '\s*\n', /\s*\n/, :nowiki ],
73
+ [ nil, /<\/nowiki>/, :nowiki, method('nowikiEnd') ],
74
+ [ :WORD, /(<(?!\/nowiki>)|[^ \t\n<])+/, :nowiki ],
75
+ [ :SPACE, /[ \t]+/, :nowiki ],
76
+ [ :LINEBREAK, /\s*\n/, :nowiki ],
77
+
78
+ # :html mode rules
79
+ [ :HTMLBLOB, /(.|\n)*<\/html>/ , :html, method('htmlEnd') ],
80
+ [ :HTMLBLOB, /.*\n/ , :html ],
75
81
 
76
82
  # :ref mode rules
77
- [ :REFEND, '\]\]', /\]\]/, :ref, method('refEnd') ],
78
- [ :WORD, '(<(?!-)|(\](?!\])|[^|<\]]))+', /(<(?!-)|(\](?!\])|[^|<\]]))+/, :ref ],
79
- [ :QUERY, '<-\w+->', /<-\w+->/, :ref, method('query') ],
80
- [ :LITERAL, '.', /./, :ref ],
83
+ [ :REFEND, /\]\]/, :ref, method('refEnd') ],
84
+ [ :WORD, /(<(?!-)|(\](?!\])|[^|<\]]))+/, :ref ],
85
+ [ :QUERY, /<-\w+->/, :ref, method('query') ],
86
+ [ :LITERAL, /./, :ref ],
81
87
 
82
88
  # :href mode rules
83
- [ :HREFEND, '\]', /\]/, :href, method('hrefEnd') ],
84
- [ :WORD, '(<(?!-)|[^ \t\n\]<])+', /(<(?!-)|[^ \t\n\]<])+/, :href ],
85
- [ :QUERY, '<-\w+->', /<-\w+->/, :href, method('query') ],
86
- [ :SPACE, '[ \t\n]+', /[ \t\n]+/, :href ],
89
+ [ :HREFEND, /\]/, :href, method('hrefEnd') ],
90
+ [ :WORD, /(<(?!-)|[^ \t\n\]<])+/, :href ],
91
+ [ :QUERY, /<-\w+->/, :href, method('query') ],
92
+ [ :SPACE, /[ \t\n]+/, :href ],
87
93
 
88
94
  # :func mode rules
89
- [ :INLINEFUNCEND, '->' , /->/ , :func, method('functionEnd') ],
90
- [ :BLOCKFUNCEND, '\]>', /\]>/, :func, method('functionEnd') ],
91
- [ :ID, '[a-zA-Z_]\w*', /[a-zA-Z_]\w*/, :func ],
92
- [ :STRING, '"(\\\\"|[^"])*"', /"(\\"|[^"])*"/, :func, method('dqString') ],
93
- [ :STRING, '\'(\\\\\'|[^\'])*\'', /'(\\'|[^'])*'/, :func, method('sqString') ],
94
- [ nil, '[ \t\n]+', /[ \t\n]+/, :func ],
95
- [ :LITERAL, '.', /./, :func ]
95
+ [ :INLINEFUNCEND, /->/ , :func, method('functionEnd') ],
96
+ [ :BLOCKFUNCEND, /\]>/, :func, method('functionEnd') ],
97
+ [ :ID, /[a-zA-Z_]\w*/, :func ],
98
+ [ :STRING, /"(\\"|[^"])*"/, :func, method('dqString') ],
99
+ [ :STRING, /'(\\'|[^'])*'/, :func, method('sqString') ],
100
+ [ nil, /[ \t\n]+/, :func ],
101
+ [ :LITERAL, /./, :func ]
96
102
  ]
97
103
  super(masterFile, log, tokenPatterns, :bop)
98
104
  end
@@ -166,6 +172,16 @@ class TaskJuggler
166
172
  [ types[match.length], match ]
167
173
  end
168
174
 
175
+ def htmlStart(type, match)
176
+ self.mode = :html
177
+ [ type, match ]
178
+ end
179
+
180
+ def htmlEnd(type, match)
181
+ self.mode = :inline
182
+ [ type, match[0..-8] ]
183
+ end
184
+
169
185
  def nowikiStart(type, match)
170
186
  self.mode = :nowiki
171
187
  [ type, match ]
@@ -371,6 +371,11 @@ class TaskJuggler
371
371
  def rule_plainText
372
372
  repeatable
373
373
  optional
374
+ pattern(%w( !htmlBlob !space ), lambda {
375
+ el = RichTextElement.new(@richTextI, :htmlblob, @val[0].join)
376
+ el.appendSpace = !@val[1].nil?
377
+ el
378
+ })
374
379
  pattern(%w( $WORD !space ), lambda {
375
380
  el = RichTextElement.new(@richTextI, :text, @val[0])
376
381
  el.appendSpace = !@val[1].nil?
@@ -387,6 +392,13 @@ class TaskJuggler
387
392
  })
388
393
  end
389
394
 
395
+ def rule_htmlBlob
396
+ repeatable
397
+ pattern(%w( $HTMLBLOB ), lambda {
398
+ @val[0]
399
+ })
400
+ end
401
+
390
402
  def rule_space
391
403
  optional
392
404
  repeatable
@@ -149,7 +149,7 @@ EOT
149
149
  begin
150
150
  @sheet = sheet.forceUTF8Encoding
151
151
  rescue
152
- error($!)
152
+ error($!.message)
153
153
  end
154
154
 
155
155
  # If the sheet contains special cut markers, we extract only the content
@@ -60,7 +60,7 @@ class TaskJuggler
60
60
 
61
61
  attr_reader :id, :cellText, :tooltip, :hAlign, :cellColor, :fontColor
62
62
  attr_accessor :title, :start, :end, :scale, :listItem, :listType,
63
- :width, :content, :column
63
+ :width, :content, :column, :timeformat1, :timeformat2
64
64
 
65
65
  def initialize(id, title)
66
66
  # The column ID. It must be unique within the report.
@@ -99,6 +99,10 @@ class TaskJuggler
99
99
  @scale = 'week'
100
100
  # The width of columns.
101
101
  @width = nil
102
+ # Format of the upper calendar header line
103
+ @timeformat1 = nil
104
+ # Format of the lower calendar header line
105
+ @timeformat2 = nil
102
106
 
103
107
  # Reference to the ReportTableColumn object that was created based on this
104
108
  # definition.
@@ -218,13 +218,13 @@ class TaskJuggler
218
218
  # Check the master file is really a file and not stdin.
219
219
  unless (masterFile = @project.inputFiles.masterFile)
220
220
  error('cannot_freeze_stdin',
221
- "The project freeze feature only when the " +
221
+ "The project freeze feature can only be used when the " +
222
222
  "master file is a real file, not standard input.")
223
223
  end
224
224
 
225
225
  # Derive the file names for the header and bookings file from the base
226
226
  # name of the master file.
227
- masterFileBase = File.basename(masterFile, '.tjp')
227
+ masterFileBase = Dir.pwd + '/' + File.basename(masterFile, '.tjp')
228
228
  headerFile = masterFileBase + '-header.tji'
229
229
  bookingsFileBase = masterFileBase + '-bookings'
230
230
  bookingsFile = bookingsFileBase + '.tji'
@@ -27,7 +27,8 @@ class TaskJuggler
27
27
  # time. So make sure some needed attributes really exist so we don't
28
28
  # have to check for existance each time we access them.
29
29
  %w( allocate assignedresources booking charge chargeset complete
30
- criticalness depends duration effort end forward gauge length
30
+ competitors criticalness depends duration
31
+ effort end forward gauge length
31
32
  maxend maxstart minend minstart milestone pathcriticalness
32
33
  precedes priority scheduled shifts start status ).each do |attr|
33
34
  @property[attr, @scenarioIdx]
@@ -38,6 +39,20 @@ class TaskJuggler
38
39
  @dCache = DataCache.instance
39
40
  end
40
41
 
42
+ def markAsScheduled
43
+ return if @scheduled
44
+ @scheduled = true
45
+ if @milestone
46
+ typename = 'Milestone'
47
+ elsif @property.leaf?
48
+ typename = 'Task'
49
+ else
50
+ typename = 'Container'
51
+ end
52
+
53
+ Log.msg { "#{typename} #{@property.fullId} has been scheduled." }
54
+ end
55
+
41
56
  # Call this function to reset all scheduling related data prior to
42
57
  # scheduling.
43
58
  def prepareScheduling
@@ -78,18 +93,17 @@ class TaskJuggler
78
93
  @hasDurationSpec = true
79
94
  :durationTask
80
95
  else
81
- # If the task is set as milestone is has a duration spec.
96
+ # If the task is set as milestone it has a duration spec.
82
97
  @hasDurationSpec = @milestone
83
98
  :startEndTask
84
99
  end
85
100
 
86
- markMilestone
101
+ markAsMilestone
87
102
 
88
103
  # For start-end-tasks without allocation, we don't have to do
89
104
  # anything but to set the 'scheduled' flag.
90
105
  if @durationType == :startEndTask && @start && @end && @allocate.empty?
91
- @scheduled = true
92
- Log.msg { "Task #{@property.fullId}: #{period_to_s}" }
106
+ markAsScheduled
93
107
  end
94
108
 
95
109
  # Collect the limits of this task and all parent tasks into a single
@@ -575,6 +589,21 @@ class TaskJuggler
575
589
  "to ensure allocations or use a higher 'priority'.")
576
590
  end
577
591
 
592
+ thieves = []
593
+ @competitors.each do |t|
594
+ thieves << t if t['priority', @scenarioIdx] < @priority
595
+ end
596
+ unless thieves.empty?
597
+ warning('priority_inversion',
598
+ "Due to a mix of ALAP and ASAP scheduled tasks or a " +
599
+ "dependency on a lower priority tasks the following " +
600
+ "task#{thieves.length > 1 ? 's' : ''} stole resources from " +
601
+ "#{@property.fullId} despite having a lower priority:")
602
+ thieves.each do |t|
603
+ info('priority_inversion_info', "Task #{t.fullId}", t.sourceFileInfo)
604
+ end
605
+ end
606
+
578
607
  @errors == 0
579
608
  end
580
609
 
@@ -966,25 +995,27 @@ class TaskJuggler
966
995
  # are only set in scheduleContainer().
967
996
  if @property.leaf?
968
997
  instance_variable_set(('@' + thisEnd).intern, date)
998
+ typename = 'Task'
969
999
  if @durationType == :startEndTask
970
1000
  instance_variable_set(('@' + thisEnd + 'Idx').intern,
971
1001
  @project.dateToIdx(date))
1002
+ if @milestone
1003
+ typename = 'Milestone'
1004
+ end
972
1005
  end
973
- Log.msg { "Task #{@property.fullId}: #{period_to_s}" }
1006
+ Log.msg { "Update #{typename} #{@property.fullId}: #{period_to_s}" }
974
1007
  end
975
1008
 
976
1009
  if @milestone
977
1010
  # Start and end date of a milestone are identical.
978
- @scheduled = true
1011
+ markAsScheduled
979
1012
  if a(otherEnd).nil?
980
1013
  propagateDate(a(thisEnd), !atEnd)
981
1014
  end
982
- Log.msg { "Milestone #{@property.fullId}: #{period_to_s}" }
983
1015
  elsif !@scheduled && @start && @end &&
984
1016
  !(@length == 0 && @duration == 0 && @effort == 0 &&
985
1017
  !@allocate.empty?)
986
- @scheduled = true
987
- Log.msg { "Task #{@property.fullId} has been scheduled" }
1018
+ markAsScheduled
988
1019
  end
989
1020
 
990
1021
  # Propagate date to all dependent tasks. Don't do this for start
@@ -1115,8 +1146,8 @@ class TaskJuggler
1115
1146
  unless @start && @end
1116
1147
  raise "Start (#{@start}) and end (#{@end}) must be set"
1117
1148
  end
1118
- @scheduled = true
1119
1149
  Log.msg { "Container task #{@property.fullId} completed: #{period_to_s}" }
1150
+ markAsScheduled
1120
1151
 
1121
1152
  # If we have modified the start or end date, we need to communicate this
1122
1153
  # new date to surrounding tasks.
@@ -1260,6 +1291,11 @@ class TaskJuggler
1260
1291
  query.string = "#{count.to_i}"
1261
1292
  end
1262
1293
 
1294
+ def query_competitorcount(query)
1295
+ query.sortable = query.numerical = @competitors.length
1296
+ query.string = "#{@competitors.length}"
1297
+ end
1298
+
1263
1299
  def query_complete(query)
1264
1300
  # If we haven't calculated the value yet, calculate it first.
1265
1301
  unless @complete
@@ -1481,6 +1517,10 @@ class TaskJuggler
1481
1517
  end
1482
1518
  end
1483
1519
 
1520
+ def query_scheduling(query)
1521
+ query.string = @forward ? 'ASAP' : 'ASAP' if @property.leaf?
1522
+ end
1523
+
1484
1524
  def query_status(query)
1485
1525
  # If we haven't calculated the completion yet, calculate it first.
1486
1526
  calcStatus if @status.empty?
@@ -1751,7 +1791,7 @@ class TaskJuggler
1751
1791
  # scheduled once we have reached the other end.
1752
1792
  if (@forward && @currentSlotIdx >= @endIdx) |
1753
1793
  (!@forward && @currentSlotIdx <= @startIdx)
1754
- @scheduled = true
1794
+ markAsScheduled
1755
1795
  @property.parents.each do |parent|
1756
1796
  parent.scheduleContainer(@scenarioIdx)
1757
1797
  end
@@ -1821,16 +1861,35 @@ class TaskJuggler
1821
1861
 
1822
1862
  # In case we have a persistent allocation we need to check if there
1823
1863
  # is already a locked resource and use it.
1824
- if allocation.lockedResource
1825
- bookResource(allocation.lockedResource)
1826
- else
1827
- # If not, we create a list of candidates in the proper order and
1828
- # assign the first one available.
1829
- allocation.candidates(@scenarioIdx).each do |candidate|
1830
- if bookResource(candidate)
1831
- allocation.lockedResource = candidate if allocation.persistent
1832
- break
1833
- end
1864
+ locked_candidate = allocation.lockedResource
1865
+ if locked_candidate
1866
+ next if bookResource(locked_candidate)
1867
+
1868
+ if allocation.atomic &&
1869
+ locked_candidate.bookedTask(@scenarioIdx, @currentSlotIdx)
1870
+ rollbackBookings
1871
+ return
1872
+ end
1873
+
1874
+ if @forward
1875
+ next if @currentSlotIdx < locked_candidate.getMaxSlot(@scenarioIdx)
1876
+ else
1877
+ next if @currentSlotIdx > locked_candidate.getMinSlot(@scenarioIdx)
1878
+ end
1879
+ # Persistent candidate is gone for the rest of the project!
1880
+ # Warn and assign somebody else, if available!
1881
+ warning('broken_persistence',
1882
+ "Persistence broken for Task #{@property.fullId} " +
1883
+ "- resource #{locked_candidate.name} is gone")
1884
+ allocation.lockedResource = nil
1885
+ end
1886
+
1887
+ # Create a list of candidates in the proper order and
1888
+ # assign the first one available.
1889
+ allocation.candidates(@scenarioIdx).each do |candidate|
1890
+ if bookResource(candidate)
1891
+ allocation.lockedResource = candidate if allocation.persistent
1892
+ break
1834
1893
  end
1835
1894
  end
1836
1895
  end
@@ -1846,6 +1905,10 @@ class TaskJuggler
1846
1905
  @doneEffort >= @effort) || !limitsOk?(@currentSlotIdx, r)
1847
1906
 
1848
1907
  if r.book(@scenarioIdx, @currentSlotIdx, @property)
1908
+ # This method is _very_ performance sensitive. Uncomment this log
1909
+ # message only if you really need it.
1910
+ #Log.msg { "Book #{resource.name} on task #{@property.fullId}" }
1911
+
1849
1912
  # For effort based task we adjust the the start end (as defined by
1850
1913
  # the scheduling direction) to align with the first booked time
1851
1914
  # slot.
@@ -1878,6 +1941,11 @@ class TaskJuggler
1878
1941
  @assignedresources << r
1879
1942
  end
1880
1943
  booked = true
1944
+ elsif (competitor = r.bookedTask(@scenarioIdx, @currentSlotIdx))
1945
+ # Keep a list of all the Tasks that have successfully competed for
1946
+ # the same resources and are potentially delaying the progress of
1947
+ # this Task.
1948
+ @competitors << competitor unless @competitors.include?(competitor)
1881
1949
  end
1882
1950
  end
1883
1951
 
@@ -1966,7 +2034,7 @@ class TaskJuggler
1966
2034
  if @effort > 0
1967
2035
  if @doneEffort >= @effort
1968
2036
  @end = tentativeEnd
1969
- @scheduled = true
2037
+ markAsScheduled
1970
2038
  end
1971
2039
  elsif @length > 0
1972
2040
  @doneLength = 0
@@ -1980,7 +2048,7 @@ class TaskJuggler
1980
2048
  if @doneLength >= @length && date >= tentativeEnd
1981
2049
  endDate = @project.idxToDate(idx + 1)
1982
2050
  @end = [ endDate, tentativeEnd ].max
1983
- @scheduled = true
2051
+ markAsScheduled
1984
2052
  break
1985
2053
  end
1986
2054
  end
@@ -1988,13 +2056,13 @@ class TaskJuggler
1988
2056
  @doneDuration = ((tentativeEnd - @start) / slotDuration).to_i
1989
2057
  if @doneDuration >= @duration
1990
2058
  @end = tentativeEnd
1991
- @scheduled = true
2059
+ markAsScheduled
1992
2060
  elsif @duration * slotDuration < (@project['now'] - @start)
1993
2061
  # This handles the case where the bookings don't provide enough
1994
2062
  # @doneDuration to reach @duration, but the now date would be
1995
2063
  # after the @start + @duration date.
1996
2064
  @end = @start + @duration * slotDuration
1997
- @scheduled = true
2065
+ markAsScheduled
1998
2066
  end
1999
2067
  end
2000
2068
  end
@@ -2041,6 +2109,19 @@ class TaskJuggler
2041
2109
  end
2042
2110
  end
2043
2111
 
2112
+ def rollbackBookings
2113
+ @doneEffort = 0.0
2114
+
2115
+ @allocate.each do |allocation|
2116
+ allocation.lockedResource = nil
2117
+ allocation.candidates(@scenarioIdx).each do |resource|
2118
+ resource.allLeaves.each do |r|
2119
+ r.rollbackBookings(@scenarioIdx, @property)
2120
+ end
2121
+ end
2122
+ end
2123
+ end
2124
+
2044
2125
  # This function checks if the task has a dependency on another task or
2045
2126
  # fixed date for a certain end. If +atEnd+ is true, the task end will be
2046
2127
  # checked. Otherwise the start.
@@ -2096,7 +2177,7 @@ class TaskJuggler
2096
2177
 
2097
2178
  # This function determines if a task is a milestones and marks it
2098
2179
  # accordingly.
2099
- def markMilestone
2180
+ def markAsMilestone
2100
2181
  return if @property.container? || @hasDurationSpec ||
2101
2182
  !@booking.empty? || !@allocate.empty?
2102
2183
 
@@ -2123,6 +2204,7 @@ class TaskJuggler
2123
2204
  @hasDurationSpec = true
2124
2205
  @end = @start if @start && !@end
2125
2206
  @start = @end if !@start && @end
2207
+ Log.msg { "Mark as milestone #{@property.fullId}" }
2126
2208
  end
2127
2209
  end
2128
2210
 
@@ -2390,10 +2472,11 @@ class TaskJuggler
2390
2472
 
2391
2473
  # Recursively compile a list of Task properties which depend on the
2392
2474
  # current task.
2393
- def inputs(foundInputs, includeChildren, checkedTasks = [])
2475
+ def inputs(foundInputs, includeChildren, checkedTasks = {})
2394
2476
  # Ignore tasks that we have already included in the checked tasks list.
2395
- return if checkedTasks.include?([ @property, includeChildren ])
2396
- checkedTasks << [ @property, includeChildren ]
2477
+ taskSignature = [ @property, includeChildren ]
2478
+ return if checkedTasks.include?(taskSignature)
2479
+ checkedTasks[taskSignature] = true
2397
2480
 
2398
2481
  # An "input" must be a leaf task that has no direct or indirect (through
2399
2482
  # parent) following tasks. Only milestones are recognized as inputs.
@@ -2424,10 +2507,11 @@ class TaskJuggler
2424
2507
 
2425
2508
  # Recursively compile a list of Task properties which depend on the
2426
2509
  # current task.
2427
- def targets(foundTargets, includeChildren, checkedTasks = [])
2510
+ def targets(foundTargets, includeChildren, checkedTasks = {})
2428
2511
  # Ignore tasks that we have already included in the checked tasks list.
2429
- return if checkedTasks.include?([ @property, includeChildren ])
2430
- checkedTasks << [ @property, includeChildren ]
2512
+ taskSignature = [ @property, includeChildren ]
2513
+ return if checkedTasks.include?(taskSignature)
2514
+ checkedTasks[taskSignature] = true
2431
2515
 
2432
2516
  # A target must be a leaf function that has no direct or indirect
2433
2517
  # (through parent) following tasks. Only milestones are recognized as