taskjuggler 3.1.0 → 3.2.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 (410) hide show
  1. data/CHANGELOG +44 -0
  2. data/bin/tj3webd +4 -0
  3. data/data/css/tjreport.css +14 -5
  4. data/data/tjp.vim +22 -7
  5. data/examples/Fedora-20/reports.tji +2 -4
  6. data/examples/Scrum/Product Burndown.csv +26 -0
  7. data/examples/Scrum/Sprint 1 Burndown.csv +26 -0
  8. data/examples/Scrum/Sprint 2 Burndown.csv +26 -0
  9. data/examples/Scrum/Sprint 3 Burndown.csv +26 -0
  10. data/examples/Scrum/scrum.tjp +141 -0
  11. data/examples/Tutorial/tutorial.tjp +13 -7
  12. data/lib/taskjuggler/Attributes.rb +2 -3
  13. data/lib/taskjuggler/HTMLDocument.rb +25 -18
  14. data/lib/taskjuggler/Journal.rb +85 -65
  15. data/lib/taskjuggler/KeywordDocumentation.rb +25 -13
  16. data/lib/taskjuggler/LeaveList.rb +1 -1
  17. data/lib/taskjuggler/Limits.rb +3 -5
  18. data/lib/taskjuggler/MessageHandler.rb +173 -19
  19. data/lib/taskjuggler/Painter.rb +75 -0
  20. data/lib/taskjuggler/Painter/BasicShapes.rb +76 -0
  21. data/lib/taskjuggler/Painter/Color.rb +273 -0
  22. data/lib/taskjuggler/Painter/Element.rb +56 -0
  23. data/lib/taskjuggler/Painter/FontData.rb +221 -0
  24. data/lib/taskjuggler/Painter/FontMetrics.rb +125 -0
  25. data/lib/taskjuggler/Painter/FontMetricsData.rb +151 -0
  26. data/lib/taskjuggler/Painter/Group.rb +77 -0
  27. data/lib/taskjuggler/Painter/Points.rb +47 -0
  28. data/lib/taskjuggler/Painter/Primitives.rb +100 -0
  29. data/lib/taskjuggler/Painter/SVGSupport.rb +36 -0
  30. data/lib/taskjuggler/Painter/Text.rb +36 -0
  31. data/lib/taskjuggler/Project.rb +46 -29
  32. data/lib/taskjuggler/ProjectFileParser.rb +24 -22
  33. data/lib/taskjuggler/ProjectFileScanner.rb +2 -2
  34. data/lib/taskjuggler/PropertyTreeNode.rb +26 -34
  35. data/lib/taskjuggler/Query.rb +8 -5
  36. data/lib/taskjuggler/RealFormat.rb +3 -0
  37. data/lib/taskjuggler/Resource.rb +3 -5
  38. data/lib/taskjuggler/ResourceScenario.rb +19 -7
  39. data/lib/taskjuggler/RichText.rb +4 -6
  40. data/lib/taskjuggler/RichText/FunctionExample.rb +1 -1
  41. data/lib/taskjuggler/RichText/FunctionHandler.rb +5 -6
  42. data/lib/taskjuggler/RichText/Parser.rb +4 -6
  43. data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
  44. data/lib/taskjuggler/RichText/RTFQuery.rb +2 -3
  45. data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
  46. data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -2
  47. data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
  48. data/lib/taskjuggler/RichText/Scanner.rb +6 -6
  49. data/lib/taskjuggler/RichText/Snip.rb +1 -2
  50. data/lib/taskjuggler/RuntimeConfig.rb +9 -6
  51. data/lib/taskjuggler/ScenarioData.rb +4 -3
  52. data/lib/taskjuggler/Scoreboard.rb +6 -0
  53. data/lib/taskjuggler/SheetHandlerBase.rb +25 -8
  54. data/lib/taskjuggler/SimpleQueryExpander.rb +14 -5
  55. data/lib/taskjuggler/SyntaxReference.rb +1 -2
  56. data/lib/taskjuggler/TableColumnSorter.rb +84 -0
  57. data/lib/taskjuggler/Task.rb +3 -5
  58. data/lib/taskjuggler/TaskJuggler.rb +36 -29
  59. data/lib/taskjuggler/TaskScenario.rb +154 -66
  60. data/lib/taskjuggler/TextParser.rb +24 -17
  61. data/lib/taskjuggler/TextParser/Scanner.rb +16 -11
  62. data/lib/taskjuggler/TextParser/SourceFileInfo.rb +20 -15
  63. data/lib/taskjuggler/TimeSheets.rb +6 -12
  64. data/lib/taskjuggler/Tj3AppBase.rb +35 -16
  65. data/lib/taskjuggler/Tj3Config.rb +1 -1
  66. data/lib/taskjuggler/TjpSyntaxRules.rb +239 -49
  67. data/lib/taskjuggler/XMLElement.rb +9 -2
  68. data/lib/taskjuggler/apps/Tj3.rb +43 -37
  69. data/lib/taskjuggler/apps/Tj3Client.rb +62 -112
  70. data/lib/taskjuggler/apps/Tj3Daemon.rb +66 -29
  71. data/lib/taskjuggler/apps/Tj3Man.rb +5 -5
  72. data/lib/taskjuggler/apps/Tj3SsReceiver.rb +10 -13
  73. data/lib/taskjuggler/apps/Tj3SsSender.rb +13 -16
  74. data/lib/taskjuggler/apps/Tj3TsReceiver.rb +10 -13
  75. data/lib/taskjuggler/apps/Tj3TsSender.rb +12 -15
  76. data/lib/taskjuggler/apps/Tj3TsSummary.rb +12 -15
  77. data/lib/taskjuggler/apps/Tj3WebD.rb +99 -0
  78. data/lib/taskjuggler/daemon/Daemon.rb +50 -10
  79. data/lib/taskjuggler/daemon/DaemonConnector.rb +127 -0
  80. data/lib/taskjuggler/daemon/ProcessIntercom.rb +36 -21
  81. data/lib/taskjuggler/daemon/ProjectBroker.rb +122 -112
  82. data/lib/taskjuggler/daemon/ProjectServer.rb +78 -46
  83. data/lib/taskjuggler/daemon/ReportServer.rb +52 -28
  84. data/lib/taskjuggler/daemon/ReportServlet.rb +92 -21
  85. data/lib/taskjuggler/daemon/WebServer.rb +75 -22
  86. data/lib/taskjuggler/daemon/WelcomePage.rb +1 -0
  87. data/lib/taskjuggler/reports/AccountListRE.rb +3 -3
  88. data/lib/taskjuggler/reports/CSVFile.rb +9 -2
  89. data/lib/taskjuggler/reports/ChartPlotter.rb +453 -0
  90. data/lib/taskjuggler/reports/Navigator.rb +1 -0
  91. data/lib/taskjuggler/reports/NikuReport.rb +4 -4
  92. data/lib/taskjuggler/reports/Report.rb +6 -18
  93. data/lib/taskjuggler/reports/ReportBase.rb +9 -9
  94. data/lib/taskjuggler/reports/ReportContext.rb +2 -2
  95. data/lib/taskjuggler/reports/StatusSheetReport.rb +6 -6
  96. data/lib/taskjuggler/reports/TableReport.rb +24 -15
  97. data/lib/taskjuggler/reports/TimeSheetReport.rb +5 -5
  98. data/lib/taskjuggler/reports/TraceReport.rb +251 -0
  99. data/lib/tj3webd.rb +17 -0
  100. data/manual/Day_To_Day_Juggling +10 -3
  101. data/manual/Installation +38 -19
  102. data/manual/Software +25 -19
  103. data/manual/Tutorial +119 -110
  104. data/manual/html/Day_To_Day_Juggling.html +7 -5
  105. data/manual/html/Getting_Started.html +4 -4
  106. data/manual/html/How_To_Contribute.html +4 -4
  107. data/manual/html/Installation.html +19 -11
  108. data/manual/html/Intro.html +4 -4
  109. data/manual/html/Reporting_Bugs.html +4 -4
  110. data/manual/html/Rich_Text_Attributes.html +4 -4
  111. data/manual/html/Software.html +15 -11
  112. data/manual/html/TaskJuggler_2x_Migration.html +4 -4
  113. data/manual/html/TaskJuggler_Internals.html +4 -4
  114. data/manual/html/The_TaskJuggler_Syntax.html +4 -4
  115. data/manual/html/Tutorial.html +41 -32
  116. data/manual/html/account.html +4 -4
  117. data/manual/html/account.task.html +4 -4
  118. data/manual/html/accountprefix.html +4 -4
  119. data/manual/html/accountreport.html +27 -9
  120. data/manual/html/accountroot.html +5 -5
  121. data/manual/html/active.html +4 -4
  122. data/manual/html/adopt.task.html +4 -4
  123. data/manual/html/aggregate.html +4 -4
  124. data/manual/html/alert.html +4 -4
  125. data/manual/html/alertlevels.html +4 -4
  126. data/manual/html/allocate.html +5 -5
  127. data/manual/html/alphabet.html +4 -4
  128. data/manual/html/alternative.html +4 -4
  129. data/manual/html/author.html +4 -4
  130. data/manual/html/balance.html +5 -5
  131. data/manual/html/booking.resource.html +4 -4
  132. data/manual/html/booking.task.html +4 -4
  133. data/manual/html/caption.html +5 -5
  134. data/manual/html/cellcolor.column.html +43 -8
  135. data/manual/html/celltext.column.html +4 -4
  136. data/manual/html/center.html +5 -5
  137. data/manual/html/charge.html +4 -4
  138. data/manual/html/chargeset.html +4 -4
  139. data/manual/html/columnid.html +27 -15
  140. data/manual/html/columns.html +5 -5
  141. data/manual/html/complete.html +4 -4
  142. data/manual/html/copyright.html +4 -4
  143. data/manual/html/credits.html +4 -4
  144. data/manual/html/css/tjreport.css +14 -5
  145. data/manual/html/currency.html +4 -4
  146. data/manual/html/currencyformat.html +5 -5
  147. data/manual/html/dailymax.html +5 -5
  148. data/manual/html/dailymin.html +5 -5
  149. data/manual/html/dailyworkinghours.html +4 -4
  150. data/manual/html/date.extend.html +4 -4
  151. data/manual/html/date.html +5 -5
  152. data/manual/html/definitions.html +4 -4
  153. data/manual/html/depends.html +4 -4
  154. data/manual/html/details.html +4 -4
  155. data/manual/html/disabled.html +4 -4
  156. data/manual/html/duration.html +4 -4
  157. data/manual/html/efficiency.html +4 -4
  158. data/manual/html/effort.html +4 -4
  159. data/manual/html/email.html +4 -4
  160. data/manual/html/enabled.html +4 -4
  161. data/manual/html/end.column.html +4 -4
  162. data/manual/html/end.html +4 -4
  163. data/manual/html/end.limit.html +4 -4
  164. data/manual/html/end.report.html +5 -5
  165. data/manual/html/end.timesheet.html +4 -4
  166. data/manual/html/endcredit.html +4 -4
  167. data/manual/html/epilog.html +5 -5
  168. data/manual/html/export.html +4 -4
  169. data/manual/html/extend.html +4 -4
  170. data/manual/html/fail.html +43 -8
  171. data/manual/html/fdl.html +4 -4
  172. data/manual/html/flags.account.html +4 -4
  173. data/manual/html/flags.html +4 -4
  174. data/manual/html/flags.journalentry.html +4 -4
  175. data/manual/html/flags.report.html +5 -5
  176. data/manual/html/flags.resource.html +4 -4
  177. data/manual/html/flags.statussheet.html +4 -4
  178. data/manual/html/flags.task.html +4 -4
  179. data/manual/html/flags.timesheet.html +4 -4
  180. data/manual/html/fontcolor.column.html +43 -8
  181. data/manual/html/footer.html +5 -5
  182. data/manual/html/formats.html +5 -5
  183. data/manual/html/functions.html +4 -4
  184. data/manual/html/gapduration.html +4 -4
  185. data/manual/html/gaplength.html +4 -4
  186. data/manual/html/halign.center.html +4 -4
  187. data/manual/html/halign.column.html +43 -8
  188. data/manual/html/halign.left.html +4 -4
  189. data/manual/html/halign.right.html +4 -4
  190. data/manual/html/hasalert.html +4 -4
  191. data/manual/html/header.html +5 -5
  192. data/manual/html/headline.html +7 -7
  193. data/manual/html/height.html +72 -0
  194. data/manual/html/hideaccount.html +46 -11
  195. data/manual/html/hidejournalentry.html +5 -5
  196. data/manual/html/hidereport.html +43 -8
  197. data/manual/html/hideresource.html +44 -9
  198. data/manual/html/hidetask.html +44 -9
  199. data/manual/html/icalreport.html +4 -4
  200. data/manual/html/include.macro.html +4 -4
  201. data/manual/html/include.project.html +4 -4
  202. data/manual/html/include.properties.html +4 -4
  203. data/manual/html/index.html +2 -1
  204. data/manual/html/inherit.extend.html +4 -4
  205. data/manual/html/interval1.html +4 -4
  206. data/manual/html/interval2.html +4 -4
  207. data/manual/html/interval3.html +4 -4
  208. data/manual/html/interval4.html +4 -4
  209. data/manual/html/isactive.html +4 -4
  210. data/manual/html/ischildof.html +4 -4
  211. data/manual/html/isdependencyof.html +4 -4
  212. data/manual/html/isdutyof.html +4 -4
  213. data/manual/html/isfeatureof.html +4 -4
  214. data/manual/html/isleaf.html +4 -4
  215. data/manual/html/ismilestone.html +4 -4
  216. data/manual/html/isongoing.html +4 -4
  217. data/manual/html/isresource.html +4 -4
  218. data/manual/html/isresponsibilityof.html +4 -4
  219. data/manual/html/istask.html +4 -4
  220. data/manual/html/journalattributes.html +11 -7
  221. data/manual/html/journalentry.html +4 -4
  222. data/manual/html/journalmode.html +5 -5
  223. data/manual/html/leaveallowance.html +5 -5
  224. data/manual/html/leaves.html +5 -6
  225. data/manual/html/left.html +5 -5
  226. data/manual/html/length.html +4 -4
  227. data/manual/html/limits.allocate.html +4 -4
  228. data/manual/html/limits.html +4 -4
  229. data/manual/html/limits.resource.html +4 -4
  230. data/manual/html/limits.task.html +4 -4
  231. data/manual/html/listitem.column.html +4 -4
  232. data/manual/html/listtype.column.html +4 -4
  233. data/manual/html/loadunit.html +5 -5
  234. data/manual/html/logicalexpression.html +8 -44
  235. data/manual/html/logicalflagexpression.html +4 -4
  236. data/manual/html/macro.html +4 -4
  237. data/manual/html/managers.html +4 -4
  238. data/manual/html/mandatory.html +4 -4
  239. data/manual/html/maxend.html +4 -4
  240. data/manual/html/maximum.html +5 -5
  241. data/manual/html/maxstart.html +4 -4
  242. data/manual/html/milestone.html +4 -4
  243. data/manual/html/minend.html +4 -4
  244. data/manual/html/minimum.html +5 -5
  245. data/manual/html/minstart.html +4 -4
  246. data/manual/html/monthlymax.html +5 -5
  247. data/manual/html/monthlymin.html +5 -5
  248. data/manual/html/navbar.html +10 -4
  249. data/manual/html/navigator.html +4 -4
  250. data/manual/html/newtask.html +4 -4
  251. data/manual/html/nikureport.html +4 -4
  252. data/manual/html/note.task.html +4 -4
  253. data/manual/html/now.html +4 -4
  254. data/manual/html/numberformat.html +5 -5
  255. data/manual/html/onend.html +4 -4
  256. data/manual/html/onstart.html +4 -4
  257. data/manual/html/opennodes.html +5 -5
  258. data/manual/html/overtime.booking.html +4 -4
  259. data/manual/html/period.column.html +4 -4
  260. data/manual/html/period.limit.html +4 -4
  261. data/manual/html/period.report.html +5 -5
  262. data/manual/html/period.task.html +4 -4
  263. data/manual/html/persistent.html +4 -4
  264. data/manual/html/precedes.html +4 -4
  265. data/manual/html/priority.html +4 -4
  266. data/manual/html/priority.timesheet.html +4 -4
  267. data/manual/html/project.html +4 -4
  268. data/manual/html/projectid.html +4 -4
  269. data/manual/html/projectid.task.html +4 -4
  270. data/manual/html/projectids.html +4 -4
  271. data/manual/html/projection.html +5 -7
  272. data/manual/html/prolog.html +5 -5
  273. data/manual/html/properties.html +11 -5
  274. data/manual/html/purge.html +5 -5
  275. data/manual/html/rate.html +4 -4
  276. data/manual/html/rate.resource.html +4 -4
  277. data/manual/html/reference.extend.html +4 -4
  278. data/manual/html/remaining.html +4 -4
  279. data/manual/html/replace.html +4 -4
  280. data/manual/html/reportprefix.html +4 -4
  281. data/manual/html/resource.html +4 -10
  282. data/manual/html/resourceattributes.html +4 -4
  283. data/manual/html/resourceprefix.html +4 -4
  284. data/manual/html/resourcereport.html +28 -10
  285. data/manual/html/resourceroot.html +5 -5
  286. data/manual/html/resources.limit.html +4 -4
  287. data/manual/html/responsible.html +4 -4
  288. data/manual/html/richtext.extend.html +4 -4
  289. data/manual/html/right.html +5 -5
  290. data/manual/html/rollupaccount.html +44 -9
  291. data/manual/html/rollupresource.html +44 -9
  292. data/manual/html/rolluptask.html +44 -9
  293. data/manual/html/scale.column.html +4 -4
  294. data/manual/html/scenario.html +4 -22
  295. data/manual/html/scenario.ical.html +4 -4
  296. data/manual/html/scenarios.export.html +4 -4
  297. data/manual/html/scenarios.html +5 -5
  298. data/manual/html/scenariospecific.extend.html +4 -4
  299. data/manual/html/scheduled.html +4 -4
  300. data/manual/html/scheduling.html +4 -4
  301. data/manual/html/select.html +4 -4
  302. data/manual/html/selfcontained.html +5 -5
  303. data/manual/html/shift.allocate.html +4 -4
  304. data/manual/html/shift.html +4 -4
  305. data/manual/html/shift.resource.html +5 -5
  306. data/manual/html/shift.task.html +4 -4
  307. data/manual/html/shift.timesheet.html +4 -4
  308. data/manual/html/shifts.allocate.html +4 -4
  309. data/manual/html/shifts.resource.html +4 -4
  310. data/manual/html/shifts.task.html +4 -4
  311. data/manual/html/shorttimeformat.html +4 -4
  312. data/manual/html/sloppy.booking.html +4 -4
  313. data/manual/html/sloppy.projection.html +5 -5
  314. data/manual/html/sortaccounts.html +5 -5
  315. data/manual/html/sortjournalentries.html +5 -5
  316. data/manual/html/sortresources.html +5 -5
  317. data/manual/html/sorttasks.html +5 -5
  318. data/manual/html/start.column.html +4 -4
  319. data/manual/html/start.html +4 -4
  320. data/manual/html/start.limit.html +4 -4
  321. data/manual/html/start.report.html +5 -5
  322. data/manual/html/startcredit.html +4 -4
  323. data/manual/html/status.statussheet.html +4 -4
  324. data/manual/html/status.timesheet.html +4 -4
  325. data/manual/html/statussheet.html +4 -4
  326. data/manual/html/statussheetreport.html +4 -4
  327. data/manual/html/strict.projection.html +5 -5
  328. data/manual/html/summary.html +4 -4
  329. data/manual/html/supplement.html +4 -4
  330. data/manual/html/supplement.resource.html +4 -10
  331. data/manual/html/supplement.task.html +4 -28
  332. data/manual/html/tagfile.html +4 -4
  333. data/manual/html/task.html +4 -28
  334. data/manual/html/task.statussheet.html +4 -4
  335. data/manual/html/task.timesheet.html +4 -4
  336. data/manual/html/taskattributes.html +4 -4
  337. data/manual/html/taskprefix.html +4 -4
  338. data/manual/html/taskreport.html +28 -10
  339. data/manual/html/taskroot.html +5 -5
  340. data/manual/html/text.extend.html +4 -4
  341. data/manual/html/textreport.html +27 -9
  342. data/manual/html/timeformat.html +5 -5
  343. data/manual/html/timeoff.nikureport.html +4 -4
  344. data/manual/html/timesheet.html +4 -4
  345. data/manual/html/timesheetreport.html +23 -5
  346. data/manual/html/timezone.export.html +4 -4
  347. data/manual/html/timezone.html +4 -4
  348. data/manual/html/timezone.report.html +5 -5
  349. data/manual/html/timezone.shift.html +4 -4
  350. data/manual/html/timingresolution.html +4 -4
  351. data/manual/html/title.column.html +4 -4
  352. data/manual/html/title.html +5 -5
  353. data/manual/html/toc.html +207 -179
  354. data/manual/html/tooltip.column.html +45 -10
  355. data/manual/html/tracereport.html +405 -0
  356. data/manual/html/trackingscenario.html +6 -6
  357. data/manual/html/treelevel.html +4 -4
  358. data/manual/html/vacation.html +4 -4
  359. data/manual/html/vacation.resource.html +4 -4
  360. data/manual/html/vacation.shift.html +4 -4
  361. data/manual/html/warn.html +43 -8
  362. data/manual/html/weeklymax.html +5 -5
  363. data/manual/html/weeklymin.html +5 -5
  364. data/manual/html/weekstartsmonday.html +4 -4
  365. data/manual/html/weekstartssunday.html +6 -6
  366. data/manual/html/width.column.html +6 -6
  367. data/manual/html/width.html +72 -0
  368. data/manual/html/work.html +4 -4
  369. data/manual/html/workinghours.project.html +4 -4
  370. data/manual/html/workinghours.resource.html +4 -4
  371. data/manual/html/workinghours.shift.html +4 -4
  372. data/manual/html/yearlyworkingdays.html +4 -4
  373. data/spec/Color_spec.rb +60 -0
  374. data/spec/ProjectBroker_spec.rb +3 -2
  375. data/spec/StatusSheets_spec.rb +5 -4
  376. data/spec/TableColumnSorter_spec.rb +78 -0
  377. data/spec/TimeSheets_spec.rb +6 -2
  378. data/spec/Tj3Daemon_spec.rb +2 -2
  379. data/spec/TraceReport_spec.rb +117 -0
  380. data/taskjuggler.gemspec +1 -1
  381. data/test/MessageChecker.rb +3 -1
  382. data/test/ReferenceGenerator.rb +1 -1
  383. data/test/TestSuite/CSV-Reports/Leave.tjp +1 -1
  384. data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +3 -0
  385. data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +9 -0
  386. data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +19 -16
  387. data/test/TestSuite/CSV-Reports/refs/weekly.csv +1 -0
  388. data/test/TestSuite/Export-Reports/refs/LogicalExpression.tjp +14 -2
  389. data/test/TestSuite/Export-Reports/refs/tutorial.tjp +98 -86
  390. data/test/TestSuite/Scheduler/Correct/Leaves.tjp +25 -0
  391. data/test/TestSuite/Syntax/Correct/Leave.tjp +1 -1
  392. data/test/TestSuite/Syntax/Correct/LogicalExpression.tjp +9 -1
  393. data/test/TestSuite/Syntax/Correct/TraceReport.tjp +10 -0
  394. data/test/TestSuite/Syntax/Correct/tutorial.tjp +10 -4
  395. data/test/test_CSV-Reports.rb +3 -3
  396. data/test/test_Export-Reports.rb +91 -86
  397. data/test/test_Journal.rb +15 -12
  398. data/test/test_Limits.rb +3 -3
  399. data/test/test_Project.rb +1 -2
  400. data/test/test_ProjectFileScanner.rb +1 -1
  401. data/test/test_PropertySet.rb +1 -1
  402. data/test/test_Query.rb +5 -6
  403. data/test/test_ReportGenerator.rb +15 -7
  404. data/test/test_RichText.rb +4 -3
  405. data/test/test_Scheduler.rb +19 -7
  406. data/test/test_ShiftAssignments.rb +2 -2
  407. data/test/test_SimpleQueryExpander.rb +29 -2
  408. data/test/test_Syntax.rb +14 -5
  409. metadata +49 -10
  410. data/lib/taskjuggler/LogFile.rb +0 -73
@@ -57,6 +57,7 @@ class TaskJuggler
57
57
  @doneEffort = 0.0
58
58
 
59
59
  @projectionMode = @project.scenario(@scenarioIdx).get('projection')
60
+ @nowIdx = @project.dateToIdx(@project['now'])
60
61
 
61
62
  @startIsDetermed = nil
62
63
  @endIsDetermed = nil
@@ -367,11 +368,11 @@ class TaskJuggler
367
368
  task.finishScheduling(@scenarioIdx)
368
369
  end
369
370
 
370
- if (parent = @property.parent)
371
- # Add the assigned resources to the parent task list.
371
+ @property.parents.each do |pTask|
372
+ # Add the assigned resources to the parent task's list.
372
373
  @assignedresources.each do |resource|
373
- unless parent['assignedresources', @scenarioIdx].include?(resource)
374
- parent['assignedresources', @scenarioIdx] << resource
374
+ unless pTask['assignedresources', @scenarioIdx].include?(resource)
375
+ pTask['assignedresources', @scenarioIdx] << resource
375
376
  end
376
377
  end
377
378
  end
@@ -558,7 +559,7 @@ class TaskJuggler
558
559
  "end date.")
559
560
  end
560
561
 
561
- if @effort == 0 && !@milestone && !@allocate.empty? &&
562
+ if @property.leaf? && @effort == 0 && !@milestone && !@allocate.empty? &&
562
563
  @assignedresources.empty?
563
564
  # The user used an 'allocate' for the task, but did not specify any
564
565
  # 'effort'. Actual allocations will only happen when resources are
@@ -1241,6 +1242,22 @@ class TaskJuggler
1241
1242
  @booking << booking
1242
1243
  end
1243
1244
 
1245
+ def query_activetasks(query)
1246
+ count = activeTasks(query)
1247
+
1248
+ query.sortable = query.numerical = count
1249
+ # For the string output, we only use integer numbers.
1250
+ query.string = "#{count.to_i}"
1251
+ end
1252
+
1253
+ def query_closedtasks(query)
1254
+ count = closedTasks(query)
1255
+
1256
+ query.sortable = query.numerical = count
1257
+ # For the string output, we only use integer numbers.
1258
+ query.string = "#{count.to_i}"
1259
+ end
1260
+
1244
1261
  def query_complete(query)
1245
1262
  # If we haven't calculated the value yet, calculate it first.
1246
1263
  unless @complete
@@ -1337,6 +1354,13 @@ class TaskJuggler
1337
1354
  query.assignList(list)
1338
1355
  end
1339
1356
 
1357
+ def query_gauge(query)
1358
+ # If we haven't calculated the schedule status yet, calculate it first.
1359
+ calcGauge unless @gauge
1360
+
1361
+ query.string = @gauge
1362
+ end
1363
+
1340
1364
  # The number of different resources assigned to the task during the query
1341
1365
  # interval. Each resource is counted based on their mathematically rounded
1342
1366
  # efficiency.
@@ -1350,22 +1374,41 @@ class TaskJuggler
1350
1374
  query.string = query.numberFormat.format(headcount)
1351
1375
  end
1352
1376
 
1353
- def query_maxend(query)
1354
- queryDateLimit(query, @maxend)
1377
+ def query_inputs(query)
1378
+ inputList = PropertyList.new(@project.tasks, false)
1379
+ inputs(inputList, true)
1380
+ inputList.delete(@property)
1381
+ inputList.setSorting([['start', true, @scenarioIdx],
1382
+ ['seqno', true, -1 ]])
1383
+ inputList.sort!
1384
+
1385
+ query.assignList(generateTaskList(inputList, query))
1355
1386
  end
1356
1387
 
1357
- def query_minend(query)
1358
- queryDateLimit(query, @minend)
1388
+ def query_maxend(query)
1389
+ queryDateLimit(query, @maxend)
1359
1390
  end
1360
1391
 
1361
1392
  def query_maxstart(query)
1362
1393
  queryDateLimit(query, @maxstart)
1363
1394
  end
1364
1395
 
1396
+ def query_minend(query)
1397
+ queryDateLimit(query, @minend)
1398
+ end
1399
+
1365
1400
  def query_minstart(query)
1366
1401
  queryDateLimit(query, @minstart)
1367
1402
  end
1368
1403
 
1404
+ def query_opentasks(query)
1405
+ count = openTasks(query)
1406
+
1407
+ query.sortable = query.numerical = count
1408
+ # For the string output, we only use integer numbers.
1409
+ query.string = "#{count.to_i}"
1410
+ end
1411
+
1369
1412
  def query_precursors(query)
1370
1413
  list = []
1371
1414
 
@@ -1403,9 +1446,8 @@ class TaskJuggler
1403
1446
  assignedResources(iv).each do |resource|
1404
1447
  if resource.allocated?(@scenarioIdx, iv, @property)
1405
1448
  if query.listItem
1406
- rti = RichText.new(query.listItem, RTFHandlers.create(@project),
1407
- @project.messageHandler).
1408
- generateIntermediateFormat
1449
+ rti = RichText.new(query.listItem, RTFHandlers.create(@project)).
1450
+ generateIntermediateFormat
1409
1451
  unless rti
1410
1452
  error('bad_resource_ts_query',
1411
1453
  "Syntax error in query statement for task attribute " +
@@ -1444,24 +1486,6 @@ class TaskJuggler
1444
1486
  query.string = @status
1445
1487
  end
1446
1488
 
1447
- def query_gauge(query)
1448
- # If we haven't calculated the schedule status yet, calculate it first.
1449
- calcGauge unless @gauge
1450
-
1451
- query.string = @gauge
1452
- end
1453
-
1454
- def query_inputs(query)
1455
- inputList = PropertyList.new(@project.tasks, false)
1456
- inputs(inputList, true)
1457
- inputList.delete(@property)
1458
- inputList.setSorting([['start', true, @scenarioIdx],
1459
- ['seqno', true, -1 ]])
1460
- inputList.sort!
1461
-
1462
- query.assignList(generateTaskList(inputList, query))
1463
- end
1464
-
1465
1489
  def query_targets(query)
1466
1490
  targetList = PropertyList.new(@project.tasks, false)
1467
1491
  targets(targetList, true)
@@ -1507,10 +1531,13 @@ class TaskJuggler
1507
1531
  # interval specified by _startIdx_ and _endIdx_. The effective work is the
1508
1532
  # actual work multiplied by the efficiency of the resource.
1509
1533
  def getEffectiveWork(startIdx, endIdx, resource = nil)
1534
+ # Make sure we have the real Resource and not a proxy.
1535
+ resource = resource.ptn if resource
1510
1536
  return 0.0 if @milestone || startIdx >= endIdx ||
1511
1537
  (resource && !@assignedresources.include?(resource))
1512
1538
 
1513
- @dCache.cached(self, :TaskScenarioEffectiveWork, startIdx, endIdx, resource) do
1539
+ @dCache.cached(self, :TaskScenarioEffectiveWork, startIdx, endIdx,
1540
+ resource) do
1514
1541
  workLoad = 0.0
1515
1542
  if @property.container?
1516
1543
  @property.kids.each do |task|
@@ -1519,8 +1546,8 @@ class TaskJuggler
1519
1546
  end
1520
1547
  else
1521
1548
  if resource
1522
- workLoad += resource.getEffectiveWork(@scenarioIdx, startIdx, endIdx,
1523
- @property)
1549
+ workLoad += resource.getEffectiveWork(@scenarioIdx, startIdx,
1550
+ endIdx, @property)
1524
1551
  else
1525
1552
  @assignedresources.each do |r|
1526
1553
  workLoad += r.getEffectiveWork(@scenarioIdx, startIdx, endIdx,
@@ -1538,7 +1565,8 @@ class TaskJuggler
1538
1565
  # This function is often called recursively for the same parameters. We
1539
1566
  # store the results in the cache to avoid repeated computations of the
1540
1567
  # same results.
1541
- @dCache.cached(self, :TaskScenarioCollectTimeOffIntervals, iv, minDuration) do
1568
+ @dCache.cached(self, :TaskScenarioCollectTimeOffIntervals, iv,
1569
+ minDuration) do
1542
1570
  il = IntervalList.new
1543
1571
  il << TimeInterval.new(@project['start'], @project['end'])
1544
1572
  if @property.leaf?
@@ -1567,31 +1595,41 @@ class TaskJuggler
1567
1595
  # Check if the Task _task_ depends on this task. _depth_ specifies how
1568
1596
  # many dependent task are traversed at max. A value of 0 means no limit.
1569
1597
  # TODO: Change this to a non-recursive implementation.
1570
- def isDependencyOf(task, depth)
1598
+ def isDependencyOf(task, depth, list = [])
1571
1599
  return true if task == @property
1572
1600
 
1601
+ # If this task is already in the list of traversed task, we can ignore
1602
+ # it.
1603
+ return false if list.include?(@property)
1604
+ list << @property
1605
+
1606
+ @startsuccs.each do |t, onEnd|
1607
+ unless onEnd
1608
+ # must be a start->start dependency
1609
+ return true if t.isDependencyOf(@scenarioIdx, task, depth, list)
1610
+ end
1611
+ end
1612
+
1613
+ # For task to depend on this task, the start of task must be after the
1614
+ # end of this task.
1615
+ if task['start', @scenarioIdx] && @end
1616
+ return false if task['start', @scenarioIdx] < @end
1617
+ end
1618
+
1573
1619
  # Check if any of the parent tasks is a dependency of _task_.
1574
1620
  t = @property.parent
1575
1621
  while t
1576
1622
  # If the parent is a dependency, than all childs are as well.
1577
- return true if t.isDependencyOf(@scenarioIdx, task, depth)
1623
+ return true if t.isDependencyOf(@scenarioIdx, task, depth, list)
1578
1624
  t = t.parent
1579
1625
  end
1580
1626
 
1581
-
1582
- @startsuccs.each do |dep|
1583
- unless dep[1]
1584
- # must be a start->start dependency
1585
- return true if dep[0].isDependencyOf(@scenarioIdx, task, depth)
1586
- end
1587
- end
1588
-
1589
1627
  return false if depth == 1
1590
1628
 
1591
- @endsuccs.each do |dep|
1592
- unless dep[1]
1629
+ @endsuccs.each do |ta, onEnd|
1630
+ unless onEnd
1593
1631
  # must be an end->start dependency
1594
- return true if dep[0].isDependencyOf(@scenarioIdx, task, depth - 1)
1632
+ return true if ta.isDependencyOf(@scenarioIdx, task, depth - 1, list)
1595
1633
  end
1596
1634
  end
1597
1635
 
@@ -1726,7 +1764,9 @@ class TaskJuggler
1726
1764
 
1727
1765
  def bookResources
1728
1766
  # First check if there is any resource at all for this slot.
1729
- return true unless @project.anyResourceAvailable?(@currentSlotIdx)
1767
+ return if !@project.anyResourceAvailable?(@currentSlotIdx) ||
1768
+ (@projectionMode && (@nowIdx > @currentSlotIdx))
1769
+
1730
1770
 
1731
1771
  # If the task has resource independent allocation limits we need to make
1732
1772
  # sure that none of them is already exceeded.
@@ -2290,27 +2330,74 @@ class TaskJuggler
2290
2330
  end
2291
2331
  end
2292
2332
 
2333
+ def activeTasks(query)
2334
+ return 0 unless TimeInterval.new(@start, @end).
2335
+ overlaps?(TimeInterval.new(query.start, query.end))
2336
+
2337
+ if @property.leaf?
2338
+ now = @project['now']
2339
+ return @start <= now && now < @end ? 1 : 0
2340
+ else
2341
+ cnt = 0
2342
+ @property.kids.each do |task|
2343
+ cnt += task.closedTasks(@scenarioIdx, query)
2344
+ end
2345
+ return cnt
2346
+ end
2347
+ end
2348
+
2349
+ def closedTasks(query)
2350
+ return 0 unless TimeInterval.new(@start, @end).
2351
+ overlaps?(TimeInterval.new(query.start, query.end))
2352
+
2353
+ if @property.leaf?
2354
+ return @end <= @project['now'] ? 1 : 0
2355
+ else
2356
+ cnt = 0
2357
+ @property.kids.each do |task|
2358
+ cnt += task.closedTasks(@scenarioIdx, query)
2359
+ end
2360
+ return cnt
2361
+ end
2362
+ end
2363
+
2364
+ def openTasks(query)
2365
+ return 0 unless TimeInterval.new(@start, @end).
2366
+ overlaps?(TimeInterval.new(query.start, query.end))
2367
+
2368
+ if @property.leaf?
2369
+ return @end > @project['now'] ? 1 : 0
2370
+ else
2371
+ cnt = 0
2372
+ @property.kids.each do |task|
2373
+ cnt += task.openTasks(@scenarioIdx, query)
2374
+ end
2375
+ return cnt
2376
+ end
2377
+ end
2378
+
2293
2379
  # Recursively compile a list of Task properties which depend on the
2294
2380
  # current task.
2295
- def inputs(list, includeChildren)
2296
- # Ignore tasks that we have already included in the list.
2297
- return if list.include?(@property)
2381
+ def inputs(foundInputs, includeChildren, checkedTasks = [])
2382
+ # Ignore tasks that we have already included in the checked tasks list.
2383
+ return if checkedTasks.include?(@property)
2384
+ checkedTasks << @property
2298
2385
 
2299
2386
  # A target must be a leaf function that has no direct or indirect
2300
2387
  # (through parent) following tasks. Only milestones are recognized as
2301
2388
  # targets.
2302
2389
  if @property.leaf? && !hasPredecessors && @milestone
2303
- list << @property
2390
+ foundInputs << @property
2304
2391
  return
2305
2392
  end
2306
2393
 
2307
2394
  @startpreds.each do |t, onEnd|
2308
- t.inputs(@scenarioIdx, list, false)
2395
+ t.inputs(@scenarioIdx, foundInputs, false, checkedTasks)
2309
2396
  end
2310
2397
 
2311
2398
  # Check for indirect predecessors.
2312
2399
  if @property.parent
2313
- @property.parent.inputs(@scenarioIdx, list, false)
2400
+ @property.parent.inputs(@scenarioIdx, foundInputs, false, checkedTasks)
2314
2401
  end
2315
2402
 
2316
2403
  # Also include targets of child tasks. The recursive iteration of child
@@ -2318,32 +2405,33 @@ class TaskJuggler
2318
2405
  # iterated.
2319
2406
  if includeChildren
2320
2407
  @property.kids.each do |child|
2321
- child.inputs(@scenarioIdx, list, true)
2408
+ child.inputs(@scenarioIdx, foundInputs, true, checkedTasks)
2322
2409
  end
2323
2410
  end
2324
2411
  end
2325
2412
 
2326
2413
  # Recursively compile a list of Task properties which depend on the
2327
2414
  # current task.
2328
- def targets(list, includeChildren)
2329
- # Ignore tasks that we have already included in the list.
2330
- return if list.include?(@property)
2415
+ def targets(foundTargets, includeChildren, checkedTasks = [])
2416
+ # Ignore tasks that we have already included in the checked tasks list.
2417
+ return if checkedTasks.include?(@property)
2418
+ checkedTasks << @property
2331
2419
 
2332
2420
  # A target must be a leaf function that has no direct or indirect
2333
2421
  # (through parent) following tasks. Only milestones are recognized as
2334
2422
  # targets.
2335
2423
  if @property.leaf? && !hasSuccessors && @milestone
2336
- list << @property
2424
+ foundTargets << @property
2337
2425
  return
2338
2426
  end
2339
2427
 
2340
2428
  @endsuccs.each do |t, onEnd|
2341
- t.targets(@scenarioIdx, list, false)
2429
+ t.targets(@scenarioIdx, foundTargets, false, checkedTasks)
2342
2430
  end
2343
2431
 
2344
2432
  # Check for indirect followers.
2345
2433
  if @property.parent
2346
- @property.parent.targets(@scenarioIdx, list, false)
2434
+ @property.parent.targets(@scenarioIdx, foundTargets, false, checkedTasks)
2347
2435
  end
2348
2436
 
2349
2437
  # Also include targets of child tasks. The recursive iteration of child
@@ -2351,7 +2439,7 @@ class TaskJuggler
2351
2439
  # iterated.
2352
2440
  if includeChildren
2353
2441
  @property.kids.each do |child|
2354
- child.targets(@scenarioIdx, list, true)
2442
+ child.targets(@scenarioIdx, foundTargets, true, checkedTasks)
2355
2443
  end
2356
2444
  end
2357
2445
  end
@@ -2416,8 +2504,8 @@ class TaskJuggler
2416
2504
 
2417
2505
  def generateDepencyListItem(query, task, dep, date)
2418
2506
  if query.listItem
2419
- rti = RichText.new(query.listItem, RTFHandlers.create(@project),
2420
- @project.messageHandler).generateIntermediateFormat
2507
+ rti = RichText.new(query.listItem, RTFHandlers.create(@project)).
2508
+ generateIntermediateFormat
2421
2509
  q = query.dup
2422
2510
  q.property = task
2423
2511
  q.setCustomData('dependency', { :string => dep })
@@ -2435,8 +2523,8 @@ class TaskJuggler
2435
2523
  date = task['start', @scenarioIdx].
2436
2524
  to_s(@property.project['timeFormat'])
2437
2525
  if query.listItem
2438
- rti = RichText.new(query.listItem, RTFHandlers.create(@project),
2439
- @project.messageHandler).generateIntermediateFormat
2526
+ rti = RichText.new(query.listItem, RTFHandlers.create(@project)).
2527
+ generateIntermediateFormat
2440
2528
  q = query.dup
2441
2529
  q.property = task
2442
2530
  q.setCustomData('date', { :string => date })
@@ -50,6 +50,8 @@ class TaskJuggler
50
50
  # with the name of the start rule.
51
51
  class TextParser
52
52
 
53
+ include MessageHandler
54
+
53
55
  # Utility class so that we can distinguish Array results from the Array
54
56
  # containing the results of a repeatable rule. We define some merging
55
57
  # method with a slightly different behaviour.
@@ -72,12 +74,10 @@ class TaskJuggler
72
74
  end
73
75
  end
74
76
 
75
- attr_reader :rules, :messageHandler
77
+ attr_reader :rules
76
78
 
77
79
  # Create a new TextParser object.
78
- def initialize(messageHandler)
79
- # The message handler will collect all error messages.
80
- @messageHandler = messageHandler
80
+ def initialize
81
81
  # This Hash will store the ruleset that the parser is operating on.
82
82
  @rules = { }
83
83
  # Array to hold the token types that the scanner can return.
@@ -201,7 +201,7 @@ class TaskJuggler
201
201
  result = parseFSM(@rules[ruleName])
202
202
  rescue TjException => msg
203
203
  if msg.message && !msg.message.empty?
204
- @messageHandler.critical('parse', msg.message)
204
+ critical('parse', msg.message)
205
205
  end
206
206
  return false
207
207
  end
@@ -224,7 +224,7 @@ class TaskJuggler
224
224
  # on to the TextScanner.
225
225
  @scanner.error(id, text, sfi, data)
226
226
  else
227
- @messageHandler.error(id, text, sfi, data)
227
+ error(id, text, sfi, data)
228
228
  end
229
229
  end
230
230
 
@@ -235,7 +235,7 @@ class TaskJuggler
235
235
  # warning on to the TextScanner.
236
236
  @scanner.warning(id, text, sfi, data)
237
237
  else
238
- @messageHandler.warning(id, text, sfi, data)
238
+ warning(id, text, sfi, data)
239
239
  end
240
240
  end
241
241
 
@@ -298,6 +298,7 @@ class TaskJuggler
298
298
  stackElement = @stack.last
299
299
  first = true
300
300
  transition.stateStack.each do |s|
301
+ checkForOldSyntax(s, token)
301
302
  if first && s.pattern == stackElement.state.pattern
302
303
  # The first state in the list may just be another state of the
303
304
  # current pattern. In this case, we already have the
@@ -318,16 +319,7 @@ class TaskJuggler
318
319
  # stores the result of the pattern and keeps the State that we
319
320
  # need to return to in case we jump to other patterns from this
320
321
  # pattern.
321
- if state.pattern.supportLevel == :deprecated
322
- warning('deprecated_keyword',
323
- "The keyword '#{token[1]}' has been deprecated! " +
324
- "See the reference manual for details.")
325
- end
326
- if state.pattern.supportLevel == :removed
327
- error('removed_keyword',
328
- "The keyword '#{token[1]}' is no longer supported! " +
329
- "See the reference manual for details.")
330
- end
322
+ checkForOldSyntax(state, token)
331
323
  @stack.push(TextParser::StackElement.new(state.pattern.function,
332
324
  state))
333
325
  end
@@ -441,6 +433,21 @@ class TaskJuggler
441
433
  end
442
434
  end
443
435
 
436
+ # Check if the current token matches a deprecated or removed syntax
437
+ # element.
438
+ def checkForOldSyntax(state, token)
439
+ if state.pattern.supportLevel == :deprecated
440
+ warning('deprecated_keyword',
441
+ "The keyword '#{token[1]}' has been deprecated! " +
442
+ "See the reference manual for details.")
443
+ end
444
+ if state.pattern.supportLevel == :removed
445
+ error('removed_keyword',
446
+ "The keyword '#{token[1]}' is no longer supported! " +
447
+ "See the reference manual for details.")
448
+ end
449
+ end
450
+
444
451
  # Convert the FSM stack state entries from State objects into [ rule,
445
452
  # pattern, index ] equivalents.
446
453
  def saveFsmStack