taskjuggler 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
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