taskjuggler 3.0.0 → 3.1.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 (553) hide show
  1. data/CHANGELOG +61 -0
  2. data/README.rdoc +43 -27
  3. data/data/css/tjreport.css +30 -0
  4. data/data/tjp.vim +100 -89
  5. data/examples/ProjectTemplate/template.tjp +338 -0
  6. data/examples/ToDo-List/todolist.tjp +84 -0
  7. data/examples/{tutorial.tjp → Tutorial/tutorial.tjp} +9 -7
  8. data/lib/header.tmpl +1 -1
  9. data/lib/taskjuggler/Account.rb +2 -2
  10. data/lib/taskjuggler/AccountCredit.rb +29 -0
  11. data/lib/taskjuggler/AccountScenario.rb +73 -7
  12. data/lib/taskjuggler/AlertLevelDefinitions.rb +104 -0
  13. data/lib/taskjuggler/AlgorithmDiff.rb +2 -2
  14. data/lib/taskjuggler/Allocation.rb +1 -1
  15. data/lib/taskjuggler/AppConfig.rb +1 -1
  16. data/lib/taskjuggler/AttributeBase.rb +1 -1
  17. data/lib/taskjuggler/AttributeDefinition.rb +1 -1
  18. data/lib/taskjuggler/Attributes.rb +40 -3
  19. data/lib/taskjuggler/BatchProcessor.rb +15 -14
  20. data/lib/taskjuggler/Booking.rb +1 -1
  21. data/lib/taskjuggler/Charge.rb +2 -2
  22. data/lib/taskjuggler/ChargeSet.rb +1 -1
  23. data/lib/taskjuggler/DataCache.rb +24 -12
  24. data/lib/taskjuggler/FileList.rb +1 -1
  25. data/lib/taskjuggler/HTMLDocument.rb +1 -1
  26. data/lib/taskjuggler/HTMLElements.rb +1 -1
  27. data/lib/taskjuggler/ICalendar.rb +1 -1
  28. data/lib/taskjuggler/Interval.rb +1 -1
  29. data/lib/taskjuggler/IntervalList.rb +1 -1
  30. data/lib/taskjuggler/Journal.rb +61 -41
  31. data/lib/taskjuggler/KeywordArray.rb +1 -1
  32. data/lib/taskjuggler/KeywordDocumentation.rb +121 -33
  33. data/lib/taskjuggler/LeaveList.rb +103 -0
  34. data/lib/taskjuggler/Limits.rb +1 -1
  35. data/lib/taskjuggler/Log.rb +6 -3
  36. data/lib/taskjuggler/LogFile.rb +1 -1
  37. data/lib/taskjuggler/LogicalExpression.rb +1 -1
  38. data/lib/taskjuggler/LogicalFunction.rb +16 -2
  39. data/lib/taskjuggler/LogicalOperation.rb +3 -1
  40. data/lib/taskjuggler/MessageHandler.rb +13 -4
  41. data/lib/taskjuggler/PTNProxy.rb +118 -0
  42. data/lib/taskjuggler/Project.rb +58 -67
  43. data/lib/taskjuggler/ProjectFileParser.rb +39 -5
  44. data/lib/taskjuggler/ProjectFileScanner.rb +1 -1
  45. data/lib/taskjuggler/PropertyList.rb +26 -2
  46. data/lib/taskjuggler/PropertySet.rb +8 -1
  47. data/lib/taskjuggler/PropertyTreeNode.rb +36 -32
  48. data/lib/taskjuggler/Query.rb +1 -1
  49. data/lib/taskjuggler/RealFormat.rb +4 -2
  50. data/lib/taskjuggler/Resource.rb +3 -3
  51. data/lib/taskjuggler/ResourceScenario.rb +219 -140
  52. data/lib/taskjuggler/RichText.rb +1 -1
  53. data/lib/taskjuggler/RichText/Document.rb +2 -2
  54. data/lib/taskjuggler/RichText/Element.rb +2 -2
  55. data/lib/taskjuggler/RichText/FunctionExample.rb +2 -2
  56. data/lib/taskjuggler/RichText/FunctionHandler.rb +2 -2
  57. data/lib/taskjuggler/RichText/Parser.rb +2 -2
  58. data/lib/taskjuggler/RichText/RTFHandlers.rb +1 -1
  59. data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
  60. data/lib/taskjuggler/RichText/RTFQuery.rb +1 -1
  61. data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
  62. data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -1
  63. data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
  64. data/lib/taskjuggler/RichText/Scanner.rb +18 -4
  65. data/lib/taskjuggler/RichText/Snip.rb +2 -2
  66. data/lib/taskjuggler/RichText/SyntaxRules.rb +6 -14
  67. data/lib/taskjuggler/RichText/TOCEntry.rb +16 -7
  68. data/lib/taskjuggler/RichText/TableOfContents.rb +3 -2
  69. data/lib/taskjuggler/RuntimeConfig.rb +1 -1
  70. data/lib/taskjuggler/Scenario.rb +1 -1
  71. data/lib/taskjuggler/ScenarioData.rb +1 -1
  72. data/lib/taskjuggler/Scoreboard.rb +1 -1
  73. data/lib/taskjuggler/SheetHandlerBase.rb +1 -1
  74. data/lib/taskjuggler/SheetReceiver.rb +1 -1
  75. data/lib/taskjuggler/SheetSender.rb +3 -3
  76. data/lib/taskjuggler/Shift.rb +2 -2
  77. data/lib/taskjuggler/ShiftAssignments.rb +24 -19
  78. data/lib/taskjuggler/ShiftScenario.rb +4 -4
  79. data/lib/taskjuggler/SimpleQueryExpander.rb +1 -1
  80. data/lib/taskjuggler/StatusSheetReceiver.rb +1 -1
  81. data/lib/taskjuggler/StatusSheetSender.rb +1 -1
  82. data/lib/taskjuggler/StdIoWrapper.rb +1 -1
  83. data/lib/taskjuggler/SyntaxReference.rb +5 -2
  84. data/lib/taskjuggler/TableColumnDefinition.rb +1 -1
  85. data/lib/taskjuggler/Task.rb +4 -8
  86. data/lib/taskjuggler/TaskDependency.rb +1 -1
  87. data/lib/taskjuggler/TaskJuggler.rb +1 -1
  88. data/lib/taskjuggler/TaskScenario.rb +131 -51
  89. data/lib/taskjuggler/TernarySearchTree.rb +6 -4
  90. data/lib/taskjuggler/TextFormatter.rb +9 -2
  91. data/lib/taskjuggler/TextParser.rb +13 -3
  92. data/lib/taskjuggler/TextParser/MacroTable.rb +1 -1
  93. data/lib/taskjuggler/TextParser/Pattern.rb +52 -8
  94. data/lib/taskjuggler/TextParser/Rule.rb +11 -5
  95. data/lib/taskjuggler/TextParser/Scanner.rb +1 -1
  96. data/lib/taskjuggler/TextParser/SourceFileInfo.rb +1 -1
  97. data/lib/taskjuggler/TextParser/StackElement.rb +1 -1
  98. data/lib/taskjuggler/TextParser/State.rb +2 -2
  99. data/lib/taskjuggler/TextParser/TokenDoc.rb +1 -1
  100. data/lib/taskjuggler/TimeSheetReceiver.rb +1 -1
  101. data/lib/taskjuggler/TimeSheetSender.rb +1 -1
  102. data/lib/taskjuggler/TimeSheetSummary.rb +1 -1
  103. data/lib/taskjuggler/TimeSheets.rb +4 -6
  104. data/lib/taskjuggler/Tj3AppBase.rb +18 -1
  105. data/lib/taskjuggler/Tj3Config.rb +4 -4
  106. data/lib/taskjuggler/Tj3SheetAppBase.rb +1 -1
  107. data/lib/taskjuggler/TjException.rb +1 -1
  108. data/lib/taskjuggler/TjTime.rb +1 -1
  109. data/lib/taskjuggler/TjpExample.rb +1 -1
  110. data/lib/taskjuggler/TjpSyntaxRules.rb +920 -392
  111. data/lib/taskjuggler/URLParameter.rb +1 -1
  112. data/lib/taskjuggler/UTF8String.rb +1 -1
  113. data/lib/taskjuggler/UserManual.rb +1 -1
  114. data/lib/taskjuggler/VimSyntax.rb +9 -6
  115. data/lib/taskjuggler/WorkingHours.rb +12 -1
  116. data/lib/taskjuggler/XMLDocument.rb +1 -1
  117. data/lib/taskjuggler/XMLElement.rb +1 -1
  118. data/lib/taskjuggler/apps/Tj3.rb +8 -3
  119. data/lib/taskjuggler/apps/Tj3Client.rb +1 -1
  120. data/lib/taskjuggler/apps/Tj3Daemon.rb +1 -1
  121. data/lib/taskjuggler/apps/Tj3Man.rb +1 -1
  122. data/lib/taskjuggler/apps/Tj3SsReceiver.rb +2 -2
  123. data/lib/taskjuggler/apps/Tj3SsSender.rb +1 -1
  124. data/lib/taskjuggler/apps/Tj3TsReceiver.rb +1 -1
  125. data/lib/taskjuggler/apps/Tj3TsSender.rb +1 -1
  126. data/lib/taskjuggler/apps/Tj3TsSummary.rb +1 -1
  127. data/lib/taskjuggler/daemon/Daemon.rb +1 -1
  128. data/lib/taskjuggler/daemon/ProcessIntercom.rb +1 -1
  129. data/lib/taskjuggler/daemon/ProjectBroker.rb +1 -1
  130. data/lib/taskjuggler/daemon/ProjectServer.rb +1 -1
  131. data/lib/taskjuggler/daemon/ReportServer.rb +2 -2
  132. data/lib/taskjuggler/daemon/ReportServlet.rb +1 -1
  133. data/lib/taskjuggler/daemon/WebServer.rb +1 -1
  134. data/lib/taskjuggler/daemon/WelcomePage.rb +1 -1
  135. data/lib/taskjuggler/deep_copy.rb +1 -1
  136. data/lib/taskjuggler/reports/AccountListRE.rb +115 -0
  137. data/lib/taskjuggler/reports/CSVFile.rb +1 -1
  138. data/lib/taskjuggler/reports/CollisionDetector.rb +1 -1
  139. data/lib/taskjuggler/reports/ColumnTable.rb +1 -1
  140. data/lib/taskjuggler/reports/GanttChart.rb +1 -1
  141. data/lib/taskjuggler/reports/GanttContainer.rb +1 -3
  142. data/lib/taskjuggler/reports/GanttHeader.rb +1 -1
  143. data/lib/taskjuggler/reports/GanttHeaderScaleItem.rb +1 -1
  144. data/lib/taskjuggler/reports/GanttLine.rb +23 -12
  145. data/lib/taskjuggler/reports/GanttLoadStack.rb +1 -1
  146. data/lib/taskjuggler/reports/GanttMilestone.rb +1 -1
  147. data/lib/taskjuggler/reports/GanttRouter.rb +1 -1
  148. data/lib/taskjuggler/reports/GanttTaskBar.rb +1 -1
  149. data/lib/taskjuggler/reports/HTMLGraphics.rb +1 -1
  150. data/lib/taskjuggler/reports/ICalReport.rb +5 -2
  151. data/lib/taskjuggler/reports/Navigator.rb +1 -1
  152. data/lib/taskjuggler/reports/NikuReport.rb +1 -1
  153. data/lib/taskjuggler/reports/Report.rb +29 -4
  154. data/lib/taskjuggler/reports/ReportBase.rb +15 -1
  155. data/lib/taskjuggler/reports/ReportContext.rb +1 -1
  156. data/lib/taskjuggler/reports/ReportTable.rb +1 -1
  157. data/lib/taskjuggler/reports/ReportTableCell.rb +1 -1
  158. data/lib/taskjuggler/reports/ReportTableColumn.rb +1 -1
  159. data/lib/taskjuggler/reports/ReportTableLegend.rb +1 -1
  160. data/lib/taskjuggler/reports/ReportTableLine.rb +1 -1
  161. data/lib/taskjuggler/reports/ResourceListRE.rb +3 -5
  162. data/lib/taskjuggler/reports/StatusSheetReport.rb +2 -2
  163. data/lib/taskjuggler/reports/TableReport.rb +336 -204
  164. data/lib/taskjuggler/reports/TableReportColumn.rb +30 -0
  165. data/lib/taskjuggler/reports/TagFile.rb +2 -2
  166. data/lib/taskjuggler/reports/TaskListRE.rb +3 -6
  167. data/lib/taskjuggler/reports/TextReport.rb +1 -1
  168. data/lib/taskjuggler/reports/TimeSheetReport.rb +3 -3
  169. data/lib/taskjuggler/reports/TjpExportRE.rb +4 -1
  170. data/lib/tj3.rb +1 -1
  171. data/lib/tj3client.rb +1 -1
  172. data/lib/tj3d.rb +1 -1
  173. data/lib/tj3man.rb +1 -1
  174. data/lib/tj3ss_receiver.rb +1 -1
  175. data/lib/tj3ss_sender.rb +1 -1
  176. data/lib/tj3ts_receiver.rb +1 -1
  177. data/lib/tj3ts_sender.rb +1 -1
  178. data/lib/tj3ts_summary.rb +1 -1
  179. data/lib/updateheader.sh +4 -1
  180. data/manual/Getting_Started +7 -4
  181. data/manual/How_To_Contribute +26 -5
  182. data/manual/Installation +26 -18
  183. data/manual/Intro +55 -33
  184. data/manual/Reporting_Bugs +18 -8
  185. data/manual/Rich_Text_Attributes +16 -3
  186. data/manual/Software +2 -2
  187. data/manual/TaskJuggler_2x_Migration +2 -2
  188. data/manual/The_TaskJuggler_Syntax +10 -0
  189. data/manual/Tutorial +2 -2
  190. data/manual/html/Day_To_Day_Juggling.html +16 -12
  191. data/manual/html/Getting_Started.html +9 -7
  192. data/manual/html/How_To_Contribute.html +18 -10
  193. data/manual/html/Installation.html +18 -15
  194. data/manual/html/Intro.html +44 -28
  195. data/manual/html/Reporting_Bugs.html +9 -7
  196. data/manual/html/Rich_Text_Attributes.html +11 -8
  197. data/manual/html/Software.html +5 -5
  198. data/manual/html/TaskJuggler_2x_Migration.html +4 -4
  199. data/manual/html/TaskJuggler_Internals.html +3 -3
  200. data/manual/html/The_TaskJuggler_Syntax.html +6 -3
  201. data/manual/html/Tutorial.html +12 -12
  202. data/manual/html/account.html +19 -10
  203. data/manual/html/account.task.html +5 -28
  204. data/manual/html/accountprefix.html +5 -5
  205. data/manual/html/{report.html → accountreport.html} +140 -23
  206. data/manual/html/accountroot.html +142 -0
  207. data/manual/html/active.html +5 -5
  208. data/manual/html/adopt.task.html +7 -8
  209. data/manual/html/aggregate.html +145 -0
  210. data/manual/html/alert.html +12 -11
  211. data/manual/html/alertlevels.html +102 -0
  212. data/manual/html/allocate.html +6 -6
  213. data/manual/html/alphabet.html +1 -1
  214. data/manual/html/alternative.html +3 -3
  215. data/manual/html/author.html +3 -3
  216. data/manual/html/balance.html +84 -11
  217. data/manual/html/booking.resource.html +3 -3
  218. data/manual/html/booking.task.html +3 -3
  219. data/manual/html/caption.html +6 -4
  220. data/manual/html/cellcolor.column.html +3 -3
  221. data/manual/html/celltext.column.html +3 -3
  222. data/manual/html/center.html +28 -4
  223. data/manual/html/charge.html +3 -3
  224. data/manual/html/chargeset.html +5 -5
  225. data/manual/html/columnid.html +40 -9
  226. data/manual/html/columns.html +6 -4
  227. data/manual/html/complete.html +15 -9
  228. data/manual/html/copyright.html +5 -5
  229. data/manual/html/{credit.html → credits.html} +15 -12
  230. data/manual/html/css/tjreport.css +30 -0
  231. data/manual/html/currency.html +28 -15
  232. data/manual/html/currencyformat.html +4 -4
  233. data/manual/html/dailymax.html +3 -3
  234. data/manual/html/dailymin.html +3 -3
  235. data/manual/html/dailyworkinghours.html +3 -3
  236. data/manual/html/date.extend.html +3 -3
  237. data/manual/html/date.html +3 -3
  238. data/manual/html/definitions.html +3 -3
  239. data/manual/html/depends.html +3 -3
  240. data/manual/html/details.html +3 -3
  241. data/manual/html/disabled.html +9 -3
  242. data/manual/html/duration.html +3 -3
  243. data/manual/html/efficiency.html +3 -3
  244. data/manual/html/effort.html +3 -3
  245. data/manual/html/email.html +3 -3
  246. data/manual/html/enabled.html +9 -3
  247. data/manual/html/end.column.html +3 -3
  248. data/manual/html/end.html +3 -3
  249. data/manual/html/end.limit.html +3 -3
  250. data/manual/html/end.report.html +4 -4
  251. data/manual/html/end.timesheet.html +3 -3
  252. data/manual/html/endcredit.html +18 -9
  253. data/manual/html/epilog.html +6 -4
  254. data/manual/html/export.html +10 -6
  255. data/manual/html/extend.html +3 -3
  256. data/manual/html/fail.html +3 -3
  257. data/manual/html/fdl.html +3 -3
  258. data/manual/html/flags.account.html +3 -3
  259. data/manual/html/flags.html +3 -3
  260. data/manual/html/flags.journalentry.html +3 -3
  261. data/manual/html/flags.report.html +6 -4
  262. data/manual/html/flags.resource.html +3 -3
  263. data/manual/html/flags.statussheet.html +3 -3
  264. data/manual/html/flags.task.html +3 -3
  265. data/manual/html/flags.timesheet.html +3 -3
  266. data/manual/html/fontcolor.column.html +3 -3
  267. data/manual/html/footer.html +28 -4
  268. data/manual/html/formats.html +4 -4
  269. data/manual/html/functions.html +4 -4
  270. data/manual/html/gapduration.html +3 -3
  271. data/manual/html/gaplength.html +4 -4
  272. data/manual/html/halign.center.html +3 -3
  273. data/manual/html/halign.column.html +3 -3
  274. data/manual/html/halign.left.html +3 -3
  275. data/manual/html/halign.right.html +3 -3
  276. data/manual/html/hasalert.html +3 -3
  277. data/manual/html/header.html +28 -4
  278. data/manual/html/headline.html +6 -6
  279. data/manual/html/hideaccount.html +73 -0
  280. data/manual/html/hidejournalentry.html +6 -6
  281. data/manual/html/hidereport.html +3 -3
  282. data/manual/html/hideresource.html +4 -4
  283. data/manual/html/hidetask.html +4 -4
  284. data/manual/html/icalreport.html +3 -3
  285. data/manual/html/include.macro.html +4 -4
  286. data/manual/html/include.project.html +5 -6
  287. data/manual/html/include.properties.html +5 -97
  288. data/manual/html/index.html +2 -2
  289. data/manual/html/inherit.extend.html +3 -3
  290. data/manual/html/interval1.html +3 -3
  291. data/manual/html/interval2.html +3 -3
  292. data/manual/html/interval3.html +3 -3
  293. data/manual/html/interval4.html +3 -3
  294. data/manual/html/isactive.html +3 -3
  295. data/manual/html/ischildof.html +3 -3
  296. data/manual/html/isdependencyof.html +3 -3
  297. data/manual/html/isdutyof.html +3 -3
  298. data/manual/html/isfeatureof.html +3 -3
  299. data/manual/html/isleaf.html +3 -3
  300. data/manual/html/ismilestone.html +3 -3
  301. data/manual/html/isongoing.html +3 -3
  302. data/manual/html/isresource.html +5 -5
  303. data/manual/html/{alert level.html → isresponsibilityof.html} +19 -14
  304. data/manual/html/istask.html +5 -5
  305. data/manual/html/journalattributes.html +6 -4
  306. data/manual/html/journalentry.html +3 -3
  307. data/manual/html/journalmode.html +8 -6
  308. data/manual/html/leaveallowance.html +139 -0
  309. data/manual/html/leaves.html +140 -0
  310. data/manual/html/left.html +30 -6
  311. data/manual/html/length.html +4 -4
  312. data/manual/html/limits.allocate.html +5 -32
  313. data/manual/html/limits.html +3 -3
  314. data/manual/html/limits.resource.html +3 -3
  315. data/manual/html/limits.task.html +3 -3
  316. data/manual/html/listitem.column.html +3 -3
  317. data/manual/html/listtype.column.html +3 -3
  318. data/manual/html/loadunit.html +6 -4
  319. data/manual/html/logicalexpression.html +3 -3
  320. data/manual/html/logicalflagexpression.html +3 -3
  321. data/manual/html/macro.html +3 -3
  322. data/manual/html/managers.html +3 -3
  323. data/manual/html/mandatory.html +3 -3
  324. data/manual/html/maxend.html +3 -3
  325. data/manual/html/maximum.html +3 -3
  326. data/manual/html/maxstart.html +3 -3
  327. data/manual/html/milestone.html +3 -3
  328. data/manual/html/minend.html +3 -3
  329. data/manual/html/minimum.html +3 -3
  330. data/manual/html/minstart.html +3 -3
  331. data/manual/html/monthlymax.html +3 -3
  332. data/manual/html/monthlymin.html +3 -3
  333. data/manual/html/navbar.html +23 -5
  334. data/manual/html/navigator.html +34 -3
  335. data/manual/html/newtask.html +3 -3
  336. data/manual/html/nikureport.html +3 -3
  337. data/manual/html/note.task.html +3 -3
  338. data/manual/html/now.html +3 -3
  339. data/manual/html/numberformat.html +4 -4
  340. data/manual/html/onend.html +3 -3
  341. data/manual/html/onstart.html +3 -3
  342. data/manual/html/opennodes.html +6 -4
  343. data/manual/html/overtime.booking.html +4 -4
  344. data/manual/html/period.column.html +3 -3
  345. data/manual/html/period.limit.html +3 -3
  346. data/manual/html/period.report.html +4 -4
  347. data/manual/html/period.task.html +3 -3
  348. data/manual/html/persistent.html +3 -3
  349. data/manual/html/precedes.html +3 -3
  350. data/manual/html/priority.html +3 -3
  351. data/manual/html/priority.timesheet.html +3 -3
  352. data/manual/html/project.html +4 -4
  353. data/manual/html/projectid.html +3 -3
  354. data/manual/html/projectid.task.html +3 -3
  355. data/manual/html/projectids.html +3 -3
  356. data/manual/html/projection.html +9 -3
  357. data/manual/html/prolog.html +6 -4
  358. data/manual/html/properties.html +193 -9
  359. data/manual/html/purge.html +5 -5
  360. data/manual/html/rate.html +3 -3
  361. data/manual/html/rate.resource.html +3 -3
  362. data/manual/html/reference.extend.html +3 -3
  363. data/manual/html/remaining.html +3 -3
  364. data/manual/html/replace.html +9 -6
  365. data/manual/html/reportprefix.html +5 -5
  366. data/manual/html/resource.html +22 -4
  367. data/manual/html/resourceattributes.html +6 -6
  368. data/manual/html/resourceprefix.html +3 -3
  369. data/manual/html/resourcereport.html +311 -8
  370. data/manual/html/resourceroot.html +6 -4
  371. data/manual/html/resources.limit.html +4 -4
  372. data/manual/html/responsible.html +3 -3
  373. data/manual/html/richtext.extend.html +3 -3
  374. data/manual/html/right.html +30 -6
  375. data/manual/html/rollupaccount.html +69 -0
  376. data/manual/html/rollupresource.html +6 -6
  377. data/manual/html/rolluptask.html +4 -4
  378. data/manual/html/scale.column.html +3 -3
  379. data/manual/html/scenario.html +3 -3
  380. data/manual/html/scenario.ical.html +3 -3
  381. data/manual/html/scenarios.export.html +3 -3
  382. data/manual/html/scenarios.html +6 -4
  383. data/manual/html/scenariospecific.extend.html +3 -3
  384. data/manual/html/scheduled.html +3 -3
  385. data/manual/html/scheduling.html +3 -3
  386. data/manual/html/select.html +3 -3
  387. data/manual/html/selfcontained.html +6 -4
  388. data/manual/html/shift.allocate.html +77 -0
  389. data/manual/html/shift.html +13 -7
  390. data/manual/html/shift.resource.html +11 -5
  391. data/manual/html/shift.task.html +9 -3
  392. data/manual/html/shift.timesheet.html +4 -4
  393. data/manual/html/shifts.allocate.html +6 -6
  394. data/manual/html/shifts.resource.html +3 -3
  395. data/manual/html/shifts.task.html +3 -3
  396. data/manual/html/shorttimeformat.html +3 -3
  397. data/manual/html/sloppy.booking.html +4 -4
  398. data/manual/html/sloppy.projection.html +12 -6
  399. data/manual/html/sortaccounts.html +73 -0
  400. data/manual/html/sortjournalentries.html +8 -6
  401. data/manual/html/sortresources.html +4 -4
  402. data/manual/html/sorttasks.html +4 -4
  403. data/manual/html/start.column.html +3 -3
  404. data/manual/html/start.html +3 -3
  405. data/manual/html/start.limit.html +3 -3
  406. data/manual/html/start.report.html +4 -4
  407. data/manual/html/startcredit.html +10 -4
  408. data/manual/html/status.statussheet.html +5 -5
  409. data/manual/html/status.timesheet.html +5 -5
  410. data/manual/html/statussheet.html +3 -3
  411. data/manual/html/statussheetreport.html +10 -6
  412. data/manual/html/strict.projection.html +10 -4
  413. data/manual/html/summary.html +3 -3
  414. data/manual/html/supplement.html +5 -5
  415. data/manual/html/supplement.resource.html +22 -4
  416. data/manual/html/supplement.task.html +4 -4
  417. data/manual/html/tagfile.html +3 -3
  418. data/manual/html/task.html +3 -3
  419. data/manual/html/task.statussheet.html +3 -3
  420. data/manual/html/task.timesheet.html +3 -3
  421. data/manual/html/taskattributes.html +3 -3
  422. data/manual/html/taskprefix.html +3 -3
  423. data/manual/html/taskreport.html +347 -8
  424. data/manual/html/taskroot.html +6 -4
  425. data/manual/html/text.extend.html +3 -3
  426. data/manual/html/textreport.html +333 -8
  427. data/manual/html/timeformat.html +4 -4
  428. data/manual/html/timeoff.nikureport.html +3 -3
  429. data/manual/html/timesheet.html +3 -3
  430. data/manual/html/timesheetreport.html +10 -6
  431. data/manual/html/timezone.export.html +3 -3
  432. data/manual/html/timezone.html +3 -3
  433. data/manual/html/timezone.report.html +6 -4
  434. data/manual/html/timezone.shift.html +3 -3
  435. data/manual/html/timingresolution.html +3 -3
  436. data/manual/html/title.column.html +3 -3
  437. data/manual/html/title.html +4 -4
  438. data/manual/html/toc.html +1705 -658
  439. data/manual/html/tooltip.column.html +3 -3
  440. data/manual/html/trackingscenario.html +3 -3
  441. data/manual/html/treelevel.html +3 -3
  442. data/manual/html/vacation.html +3 -3
  443. data/manual/html/vacation.resource.html +4 -4
  444. data/manual/html/vacation.shift.html +4 -4
  445. data/manual/html/warn.html +3 -3
  446. data/manual/html/weeklymax.html +3 -3
  447. data/manual/html/weeklymin.html +3 -3
  448. data/manual/html/weekstartsmonday.html +3 -3
  449. data/manual/html/weekstartssunday.html +3 -3
  450. data/manual/html/width.column.html +3 -3
  451. data/manual/html/work.html +3 -3
  452. data/manual/html/workinghours.project.html +3 -3
  453. data/manual/html/workinghours.resource.html +3 -3
  454. data/manual/html/workinghours.shift.html +3 -3
  455. data/manual/html/yearlyworkingdays.html +4 -4
  456. data/spec/ICalendar_spec.rb +4 -2
  457. data/spec/IntervalList_spec.rb +1 -1
  458. data/spec/ProjectBroker_spec.rb +2 -6
  459. data/spec/StatusSheets_spec.rb +1 -1
  460. data/spec/TernarySearchTree_spec.rb +2 -2
  461. data/spec/TimeSheets_spec.rb +1 -1
  462. data/spec/Tj3Daemon_spec.rb +1 -1
  463. data/spec/Tj3_spec.rb +1 -1
  464. data/spec/support/DaemonControl.rb +1 -1
  465. data/spec/support/spec_helper.rb +19 -0
  466. data/taskjuggler.gemspec +1 -0
  467. data/test/MessageChecker.rb +1 -1
  468. data/test/ReferenceGenerator.rb +1 -1
  469. data/test/TestSuite/CSV-Reports/Leave.tjp +37 -0
  470. data/test/TestSuite/CSV-Reports/celltext.tjp +1 -1
  471. data/test/TestSuite/CSV-Reports/efficiency.tjp +20 -0
  472. data/test/TestSuite/CSV-Reports/headcount.tjp +31 -0
  473. data/test/TestSuite/CSV-Reports/refs/Leave.csv +5 -0
  474. data/test/TestSuite/CSV-Reports/refs/alert.csv +6 -0
  475. data/test/TestSuite/CSV-Reports/refs/celltext.csv +6 -0
  476. data/test/TestSuite/CSV-Reports/refs/efficiency.csv +5 -0
  477. data/test/TestSuite/CSV-Reports/refs/headcount.csv +4 -0
  478. data/test/TestSuite/CSV-Reports/refs/sortByTree.csv +6 -0
  479. data/test/TestSuite/CSV-Reports/refs/sortBy_duration.down.csv +6 -0
  480. data/test/TestSuite/CSV-Reports/refs/sortBy_effort.up.csv +6 -0
  481. data/test/TestSuite/CSV-Reports/refs/sortBy_plan.start.down.csv +6 -0
  482. data/test/TestSuite/CSV-Reports/refs/taskreport.csv +6 -0
  483. data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +14 -0
  484. data/test/TestSuite/CSV-Reports/resourcereport.tjp +1 -1
  485. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +1 -1
  486. data/test/TestSuite/CSV-Reports/sortByTree.tjp +1 -1
  487. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +1 -1
  488. data/test/TestSuite/CSV-Reports/taskreport.tjp +1 -1
  489. data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +1 -1
  490. data/test/TestSuite/Export-Reports/refs/AccountReport.tjp +1089 -0
  491. data/test/TestSuite/Export-Reports/refs/AlertLevels.tjp +24 -0
  492. data/test/TestSuite/Export-Reports/refs/Complete.tjp +5 -25
  493. data/test/TestSuite/Export-Reports/refs/navigator.tjp +58 -0
  494. data/test/TestSuite/Export-Reports/refs/template.tjp +142 -0
  495. data/test/TestSuite/Export-Reports/refs/textreport.tjp +19 -0
  496. data/test/TestSuite/ReportGenerator/Correct/Alerts.tjp +26 -7
  497. data/test/TestSuite/ReportGenerator/Correct/refs/Alerts-1.csv +177 -141
  498. data/test/TestSuite/ReportGenerator/Correct/refs/FTE-1.csv +1 -1
  499. data/test/TestSuite/Scheduler/Correct/Allocate.tjp +2 -2
  500. data/test/TestSuite/Scheduler/Correct/Shift2.tjp +4 -4
  501. data/test/TestSuite/Syntax/Correct/Account.tjp +23 -10
  502. data/test/TestSuite/Syntax/Correct/AccountReport.tjp +74 -0
  503. data/test/TestSuite/Syntax/Correct/AdoptedTasks.tjp +4 -0
  504. data/test/TestSuite/Syntax/Correct/AlertLevels.tjp +25 -0
  505. data/test/TestSuite/Syntax/Correct/Celltext.tjp +3 -3
  506. data/test/TestSuite/Syntax/Correct/Complete.tjp +8 -5
  507. data/test/TestSuite/Syntax/Correct/Leave.tjp +37 -0
  508. data/test/TestSuite/Syntax/Correct/Reports.tjp +4 -4
  509. data/test/TestSuite/Syntax/Correct/Shift.tjp +4 -4
  510. data/test/TestSuite/Syntax/Correct/manual2example.rb +4 -3
  511. data/test/TestSuite/Syntax/Correct/navigator.tjp +31 -0
  512. data/test/TestSuite/Syntax/Correct/template.tjp +338 -0
  513. data/test/TestSuite/Syntax/Correct/textreport.tjp +21 -0
  514. data/test/TestSuite/Syntax/Correct/tutorial.tjp +12 -10
  515. data/test/TestSuite/Syntax/Errors/{adopt_duplicate_child.tjp → adopt_duplicate_child-1.tjp} +0 -0
  516. data/test/TestSuite/Syntax/Errors/{adopt_common_root.tjp → adopt_duplicate_child-2.tjp} +1 -1
  517. data/test/TestSuite/Syntax/Errors/{adopt_duplicate_parent.tjp → adopt_duplicate_child-3.tjp} +1 -1
  518. data/test/TestSuite/Syntax/Errors/adopt_self.tjp +7 -0
  519. data/test/TestSuite/Syntax/Errors/alert_level_redef.tjp +8 -0
  520. data/test/TestSuite/Syntax/Errors/alert_name_redef.tjp +8 -0
  521. data/test/TestSuite/Syntax/Errors/too_few_alert_levels.tjp +5 -0
  522. data/test/TjpGen.rb +1 -1
  523. data/test/all.rb +1 -1
  524. data/test/test_AlgorithmDiff.rb +1 -1
  525. data/test/test_BatchProcessor.rb +23 -10
  526. data/test/test_CSV-Reports.rb +1 -1
  527. data/test/test_CSVFile.rb +1 -1
  528. data/test/test_CollisionDetector.rb +1 -1
  529. data/test/test_Export-Reports.rb +1 -1
  530. data/test/test_Journal.rb +42 -15
  531. data/test/test_Limits.rb +1 -1
  532. data/test/test_LogicalExpression.rb +1 -1
  533. data/test/test_MacroTable.rb +8 -3
  534. data/test/test_Project.rb +1 -1
  535. data/test/test_ProjectFileScanner.rb +1 -1
  536. data/test/test_PropertySet.rb +1 -1
  537. data/test/test_Query.rb +1 -1
  538. data/test/test_RealFormat.rb +1 -1
  539. data/test/test_ReportGenerator.rb +1 -1
  540. data/test/test_RichText.rb +1 -1
  541. data/test/test_Scheduler.rb +1 -1
  542. data/test/test_ShiftAssignments.rb +1 -1
  543. data/test/test_SimpleQueryExpander.rb +1 -1
  544. data/test/test_Syntax.rb +1 -1
  545. data/test/test_TextFormatter.rb +1 -1
  546. data/test/test_TjTime.rb +1 -1
  547. data/test/test_TjpExample.rb +1 -1
  548. data/test/test_URLParameter.rb +1 -1
  549. data/test/test_UTF8String.rb +1 -1
  550. data/test/test_WorkingHours.rb +1 -1
  551. data/test/test_deep_copy.rb +1 -1
  552. metadata +318 -248
  553. data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +0 -8
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = ProjectFileParser.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -237,20 +237,37 @@ class TaskJuggler
237
237
  # type. +sourceFileInfo+ is a SourceFileInfo of the report definition. The
238
238
  # method returns the newly created Report.
239
239
  def newReport(id, name, type, sourceFileInfo)
240
+ # If there is no parent property and the report prefix is not empty, the
241
+ # reportprefix defines the parent property.
242
+ if @property.nil? && !@reportprefix.empty?
243
+ @property = @project.report(@reportprefix)
244
+ end
245
+
246
+ # Report IDs must be unique. If an ID was provided, check if it exists
247
+ # already.
248
+ if id
249
+ # If we have a scope property, we need to prepend the ID of the scope
250
+ # property to the provided ID.
251
+ id = (@property ? @property.fullId + '.' : '') + @val[1]
252
+
253
+ if @project.report(id)
254
+ error('report_exists', "report #{id} has already been defined.",
255
+ sourceFileInfo, @property)
256
+ end
257
+ end
258
+
240
259
  @reportCounter += 1
241
- if name != '.'
260
+ if name != '.' && name != ''
242
261
  if @project.reportByName(name)
243
262
  error('report_redefinition',
244
263
  "A report with the name #{name} has already been defined.")
245
264
  end
246
265
  end
247
266
  @property = Report.new(@project, id || "report#{@reportCounter}",
248
- name, nil)
267
+ name, @property)
249
268
  @property.typeSpec = type
250
269
  @property.sourceFileInfo = sourceFileInfo
251
- @property.set('formats', [ :tjp ])
252
270
  @property.inheritAttributes
253
- @property
254
271
  end
255
272
 
256
273
  # If the @limitResources list is not empty, we have to create a Limits
@@ -394,6 +411,11 @@ class TaskJuggler
394
411
  @cr.setLastSyntaxToken(idx)
395
412
  end
396
413
 
414
+ # Specify the support level for the current pattern.
415
+ def level(level)
416
+ @cr.setSupportLevel(level)
417
+ end
418
+
397
419
  # Add a reference to another pattern. This information is only used to
398
420
  # generate the documentation for the patterns of this rule.
399
421
  def also(seeAlso)
@@ -454,6 +476,18 @@ class TaskJuggler
454
476
  @property = nil
455
477
  end
456
478
 
479
+ # This method most be used instead of the += operator for all list
480
+ # attributes. += will always return an Array object. This will cause
481
+ # trouble with the list attributes that are not plain Arrays.
482
+ def appendScListAttribute(attrId, list)
483
+ list.each do |v|
484
+ @property[attrId, @scenarioIdx] << v
485
+ end
486
+ # The << operator does not set the 'provided' flag. Just do a self
487
+ # assignment to trigget the flag to get set.
488
+ @property[attrId, @scenarioIdx] = @property[attrId, @scenarioIdx]
489
+ end
490
+
457
491
  end
458
492
 
459
493
  end
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = ProjectFileScanner.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = PropertyList.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -11,6 +11,8 @@
11
11
  # published by the Free Software Foundation.
12
12
  #
13
13
 
14
+ require 'taskjuggler/PTNProxy'
15
+
14
16
  class TaskJuggler
15
17
 
16
18
  # The PropertyList is a utility class that can be used to hold a list of
@@ -60,6 +62,16 @@ class TaskJuggler
60
62
  @items.method(func).call(*args, &block)
61
63
  end
62
64
 
65
+ def includeAdopted
66
+ adopted = []
67
+ @items.each do |p|
68
+ p.adoptees.each do |ap|
69
+ adopted += includeAdoptedR(ap, p)
70
+ end
71
+ end
72
+ append(adopted)
73
+ end
74
+
63
75
  def to_ary
64
76
  @items.dup
65
77
  end
@@ -165,6 +177,18 @@ class TaskJuggler
165
177
 
166
178
  private
167
179
 
180
+ def includeAdoptedR(property, parent)
181
+ # Create a proxy for the current PropertyTreeNode and add it to a list.
182
+ adopted = [ parentProxy = PTNProxy.new(property, parent) ]
183
+
184
+ # Add proxies for all children (adopted or not) and their children.
185
+ property.kids.each do |p|
186
+ adopted += includeAdoptedR(p, parentProxy)
187
+ end
188
+
189
+ adopted
190
+ end
191
+
168
192
  # Append a new sorting level to the existing levels.
169
193
  def addSortingCriteria(criteria, up, scIdx)
170
194
  unless @propertySet.knownAttribute?(criteria) ||
@@ -214,7 +238,7 @@ class TaskJuggler
214
238
  @items.sort! do |a, b|
215
239
  res = 0
216
240
  @sortingLevels.times do |i|
217
- if @query
241
+ if @query && @sortingCriteria[i] != 'tree'
218
242
  # In case we have a Query reference, we get the two values with this
219
243
  # query.
220
244
  @query.scenarioIdx = @scenarioIdx[i] < 0 ? nil : @scenarioIdx[i]
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = PropertySet.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -193,6 +193,12 @@ class TaskJuggler
193
193
  property = prop
194
194
  end
195
195
 
196
+ # Iterate over all properties and eliminate references to this the
197
+ # PropertyTreeNode to be removed.
198
+ @properties.each do |p|
199
+ p.removeReferences(p)
200
+ end
201
+
196
202
  # Recursively remove all sub-nodes. The children list is modified during
197
203
  # the call, so we can't use an iterator here.
198
204
  until property.children.empty? do
@@ -205,6 +211,7 @@ class TaskJuggler
205
211
  # Remove this node from the child list of the parent node.
206
212
  property.parent.children.delete(property) if property.parent
207
213
 
214
+
208
215
  property
209
216
  end
210
217
 
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = PropertyTreeNode.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -135,34 +135,30 @@ class TaskJuggler
135
135
  self
136
136
  end
137
137
 
138
+ # We often use PTNProxy objects to represent PropertyTreeNode objects. The
139
+ # proxy usually does a good job acting like a PropertyTreeNode. But in
140
+ # some situations, we want to make sure to operate on the PropertyTreeNode
141
+ # and not the PTNProxy. Both classes provide a ptn() method that always
142
+ # return the PropertyTreeNode.
143
+ def ptn
144
+ self
145
+ end
146
+
138
147
  # Adopt _property_ as a step child. Also register the new relationship
139
148
  # with the child.
140
149
  def adopt(property)
141
- return if @adoptees.include?(property)
142
-
143
- # The adopted node and the adopting node must not have any common
144
- # ancestors.
145
- if root == property.root
146
- error('adopt_common_root',
147
- "The adoptee #{property.fullId} and the parent #{fullId} " +
148
- "may not share common ancestors.")
150
+ # A property cannot adopt itself.
151
+ if self == property
152
+ error('adopt_self', 'A property cannot adopt itself')
149
153
  end
150
154
 
151
- # The adopted trees for this node must not overlap.
152
- @adoptees.each do |adoptee|
153
- # Check if the to be adopted node is an ancestor of an already adopted
154
- # node.
155
- if adoptee.ancestors.include?(property)
155
+ # A top level task must never contain the same leaf task more then once!
156
+ allOfRoot = root.all
157
+ property.allLeaves.each do |adoptee|
158
+ if allOfRoot.include?(adoptee)
156
159
  error('adopt_duplicate_child',
157
- "The child #{adoptee.fullId} of #{property.fullId} " +
158
- "has already been adopted by #{fullId}.")
159
- end
160
- # Check if the already adopted nodes are an ancestor of the to be
161
- # adopted node.
162
- if property.ancestors.include?(adoptee)
163
- error('adopt_duplicate_parent',
164
- "The parent #{adoptee.fullId} of #{property.fullId} " +
165
- "has already been adopted by #{fullId}.")
160
+ "The task '#{adoptee.fullId}' has already been adopted by " +
161
+ "property '#{root.fullId}' or any of its sub-properties.")
166
162
  end
167
163
  end
168
164
 
@@ -177,7 +173,6 @@ class TaskJuggler
177
173
  return if @stepParents.include?(property)
178
174
 
179
175
  @stepParents << property
180
- property.adopt(self)
181
176
  end
182
177
 
183
178
  # Return a list of all children including adopted kids.
@@ -202,6 +197,13 @@ class TaskJuggler
202
197
  @attributes, @scenarioAttributes = backup
203
198
  end
204
199
 
200
+ # Remove any references in the stored data that references the _property_.
201
+ def removeReferences(property)
202
+ @children.delete(property)
203
+ @adoptees.delete(property)
204
+ @stepParents.delete(property)
205
+ end
206
+
205
207
  # Return the index of the child _node_.
206
208
  def levelSeqNo(node)
207
209
  @children.index(node) + 1
@@ -258,7 +260,7 @@ class TaskJuggler
258
260
  # Returns a list of this node and all transient sub nodes.
259
261
  def all
260
262
  res = [ self ]
261
- @children.each do |c|
263
+ kids.each do |c|
262
264
  res = res.concat(c.all)
263
265
  end
264
266
  res
@@ -266,11 +268,11 @@ class TaskJuggler
266
268
 
267
269
  # Return a list of all leaf nodes of this node.
268
270
  def allLeaves(withoutSelf = false)
271
+ res = []
269
272
  if leaf?
270
- res = withoutSelf ? [] : [ self ]
273
+ res << self unless withoutSelf
271
274
  else
272
- res = []
273
- @children.each do |c|
275
+ kids.each do |c|
274
276
  res += c.allLeaves
275
277
  end
276
278
  end
@@ -553,8 +555,10 @@ class TaskJuggler
553
555
  journal = @project['journal']
554
556
  query.sortable = query.numerical = alert =
555
557
  journal.alertLevel(query.end, self, query.hideJournalEntry)
556
- query.string = colorName = @project.alertLevelName(alert)
557
- rText = "<fcol:#{colorName.downcase}>#{colorName}</fcol>"
558
+ alertLevel = @project['alertLevels'][alert]
559
+ query.string = alertLevel.name
560
+ rText = "<fcol:#{alertLevel.color}><nowiki>#{alertLevel.name}" +
561
+ "</nowiki></fcol>"
558
562
  unless (rti = RichText.new(rText, RTFHandlers.create(@project),
559
563
  @project.messageHandler).
560
564
  generateIntermediateFormat)
@@ -645,8 +649,8 @@ class TaskJuggler
645
649
  # provided by the class *Scenario classes. In case we can't find a function
646
650
  # called for the base class we try to find it in corresponding *Scenario
647
651
  # class.
648
- def method_missing(func, scenarioIdx, *args)
649
- @data[scenarioIdx].method(func).call(*args)
652
+ def method_missing(func, scenarioIdx, *args, &block)
653
+ @data[scenarioIdx].send(func, *args, &block)
650
654
  end
651
655
 
652
656
  def error(id, text)
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = Query.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = RealFormat.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -63,8 +63,10 @@ class TaskJuggler
63
63
  intNumber = '0' * (@fractionDigits - intNumber.length + 1) + intNumber
64
64
  end
65
65
  intPart = intNumber[0..-(@fractionDigits + 1)]
66
+ # Determinate the fractional part
66
67
  fracPart =
67
- @fractionDigits > 0 ? '.' + intNumber[-(@fractionDigits)..-1] : ''
68
+ @fractionDigits > 0 ? @fractionSeparator +
69
+ intNumber[-(@fractionDigits)..-1] : ''
68
70
 
69
71
  if @thousandsSeparator.empty?
70
72
  out = intPart
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = Resource.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -37,8 +37,8 @@ class TaskJuggler
37
37
  # provided by the class ResourceScenario. In case we can't find a
38
38
  # function called for the Resource class we try to find it in
39
39
  # ResourceScenario.
40
- def method_missing(func, scenarioIdx, *args)
41
- @data[scenarioIdx].method(func).call(*args)
40
+ def method_missing(func, scenarioIdx, *args, &block)
41
+ @data[scenarioIdx].method(func).call(*args, &block)
42
42
  end
43
43
 
44
44
  def query_dashboard(query)
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = ResourceScenario.rb -- The TaskJuggler III Project Management Software
5
5
  #
6
- # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
7
  # by Chris Schlaeger <chris@linux.com>
8
8
  #
9
9
  # This program is free software; you can redistribute it and/or modify
@@ -24,13 +24,18 @@ class TaskJuggler
24
24
  # nil: Value has not been determined yet.
25
25
  # Task: A reference to a Task object
26
26
  # Bit 0: Reserved
27
- # Bit 1: 0: Work time
28
- # 1: Off time
29
- # Bit 2 - 5: 0: No vacation or leave time
30
- # 1: Regular vacation
31
- # 2 - 15: Reserved
32
- # Bit 6: Reserved
33
- # Bit 7: 0: No global override
27
+ # Bit 1: 0: Work time (as defined by working hours)
28
+ # 1: No work time (as defined by working hours)
29
+ # Bit 2 - 5: 0: No holiday or leave time
30
+ # 1: Public holiday (holiday)
31
+ # 2: Annual leave
32
+ # 3: Special leave
33
+ # 4: Sick leave
34
+ # 5: unpaid leave
35
+ # 6: blocked for other projects
36
+ # 7 - 15: Reserved
37
+ # Bit 6 - 7: Reserved
38
+ # Bit 8: 0: No global override
34
39
  # 1: Override global setting
35
40
  # The scoreboard is only created when needed to save memory for projects
36
41
  # which read-in the coporate employee database but only need a small
@@ -49,9 +54,9 @@ class TaskJuggler
49
54
  # Attributed are only really created when they are accessed the first
50
55
  # time. So make sure some needed attributes really exist so we don't
51
56
  # have to check for existance each time we access them.
52
- %w( alloctdeffort criticalness directreports duties efficiency
57
+ %w( alloctdeffort chargeset criticalness directreports duties efficiency
53
58
  effort limits managers rate reports shifts
54
- vacations workinghours ).each do |attr|
59
+ leaves leaveallowances workinghours ).each do |attr|
55
60
  @property[attr, @scenarioIdx]
56
61
  end
57
62
 
@@ -241,6 +246,26 @@ class TaskJuggler
241
246
  book(sbIdx, booking.task, true)
242
247
  end
243
248
 
249
+ # Compute the annual leave days within the period specified by the
250
+ # _query_. The result is in days.
251
+ def query_annualleave(query)
252
+ query.sortable = query.numerical = val =
253
+ getLeave(query.startIdx, query.endIdx, :annual)
254
+ query.string = query.scaleLoad(val)
255
+ end
256
+
257
+ def query_annualleavebalance(query)
258
+ if @property.leaf?
259
+ leave = getLeave(query.startIdx, query.endIdx, :annual)
260
+ allowanceSlots = @leaveallowances.balance(:annual, query.start,
261
+ query.end)
262
+ allowance = @project.slotsToDays(allowanceSlots)
263
+ query.sortable = query.numerical = val = allowance - leave
264
+ query.string = query.scaleLoad(val)
265
+ end
266
+ end
267
+
268
+
244
269
  # Compute the cost generated by this Resource for a given Account during a
245
270
  # given interval. If a Task is provided as scopeProperty only the turnover
246
271
  # directly assiciated with the Task is taken into account.
@@ -248,7 +273,7 @@ class TaskJuggler
248
273
  if query.costAccount
249
274
  query.sortable = query.numerical = cost =
250
275
  turnover(query.startIdx, query.endIdx, query.costAccount,
251
- query.scopeProperty)
276
+ query.scopeProperty, true)
252
277
  query.string = query.currencyFormat.format(cost)
253
278
  else
254
279
  query.string = 'No \'balance\' defined!'
@@ -292,13 +317,31 @@ class TaskJuggler
292
317
  # probably don't need to compute this for every resource.
293
318
  globalWorkSlots = @project.getWorkSlots(query.startIdx, query.endIdx)
294
319
  workSlots = getWorkSlots(query.startIdx, query.endIdx)
295
- fte = workSlots.to_f / globalWorkSlots if globalWorkSlots > 0
320
+ if globalWorkSlots > 0
321
+ fte = (workSlots.to_f / globalWorkSlots) * @efficiency
322
+ end
296
323
  end
297
324
 
298
325
  query.sortable = query.numerical = fte
299
326
  query.string = query.numberFormat.format(fte)
300
327
  end
301
328
 
329
+ # The headcount of the resource or group.
330
+ def query_headcount(query)
331
+ headcount = 0
332
+ if @property.container?
333
+ @property.kids.each do |resource|
334
+ resource.query_headcount(@scenarioIdx, query)
335
+ headcount += query.to_num
336
+ end
337
+ else
338
+ headcount += @efficiency.round
339
+ end
340
+
341
+ query.sortable = query.numerical = headcount
342
+ query.string = query.numberFormat.format(headcount)
343
+ end
344
+
302
345
  # Get the rate of the resource.
303
346
  def query_rate(query)
304
347
  query.sortable = query.numerical = r = rate
@@ -319,14 +362,77 @@ class TaskJuggler
319
362
  end
320
363
  end
321
364
 
322
- # The work time of the Resource that was blocked by a vacation during the
365
+ # Compute the sick leave days within the period specified by the
366
+ # _query_. The result is in days.
367
+ def query_sickleave(query)
368
+ query.sortable = query.numerical = val =
369
+ getLeave(query.startIdx, query.endIdx, :sick)
370
+ query.string = query.scaleLoad(val)
371
+ end
372
+
373
+ # Compute the special leave days within the period specified by the
374
+ # _query_. The result is in days.
375
+ def query_specialleave(query)
376
+ query.sortable = query.numerical = val =
377
+ getLeave(query.startIdx, query.endIdx, :special)
378
+ query.string = query.scaleLoad(val)
379
+ end
380
+
381
+ # The work time of the Resource that was blocked by leaves during the
323
382
  # specified TimeInterval. The result is in working days (effort).
324
- def query_vacationdays(query)
383
+ def query_timeoffdays(query)
325
384
  query.sortable = query.numerical = time =
326
- getVacationDays(query.startIdx, query.endIdx)
385
+ getTimeOffDays(query.startIdx, query.endIdx)
327
386
  query.string = query.scaleLoad(time)
328
387
  end
329
388
 
389
+ # Compute the unpaid leave days within the period specified by the
390
+ # _query_. The result is in days.
391
+ def query_unpaidleave(query)
392
+ query.sortable = query.numerical = val =
393
+ getLeave(query.startIdx, query.endIdx, :unpaid)
394
+ query.string = query.scaleLoad(val)
395
+ end
396
+
397
+ # A generic tree iterator that recursively accumulates the result of the
398
+ # block for each leaf object.
399
+ def treeSum(startIdx, endIdx, *args, &block)
400
+ cacheTag = "#{self.class}.#{caller[0][/`.*'/][1..-2]}"
401
+ treeSumR(cacheTag, startIdx, endIdx, *args, &block)
402
+ end
403
+
404
+ # Recursing method for treeSum.
405
+ def treeSumR(cacheTag, startIdx, endIdx, *args, &block)
406
+ # Check if the value to be computed is already in the data cache. If so,
407
+ # return it. Otherwise we have to compute it first and then store it in
408
+ # the cache. We use the signature of the method that called treeSum()
409
+ # and its arguments together with 'self' as index to the cache.
410
+ @dCache.cached(self, cacheTag, startIdx, endIdx, *args) do
411
+ if @property.container?
412
+ sum = 0.0
413
+ # Iterate over all the kids and accumulate the result of the
414
+ # recursively called method.
415
+ @property.kids.each do |resource|
416
+ sum += resource.treeSumR(@scenarioIdx, cacheTag, startIdx, endIdx,
417
+ *args, &block)
418
+ end
419
+ sum
420
+ else
421
+ instance_eval(&block)
422
+ end
423
+ end
424
+ end
425
+
426
+ # Returns the number of leave days for the period described by _startIdx_
427
+ # and _endIdx_ for the given _type_ of leave.
428
+ def getLeave(startIdx, endIdx, type)
429
+ treeSum(startIdx, endIdx, type) do
430
+ @project.convertToDailyLoad(@project['scheduleGranularity'] *
431
+ getLeaveSlots(startIdx, endIdx, type))
432
+ end
433
+ end
434
+
435
+
330
436
  # Returns the work of the resource (and its children) weighted by their
331
437
  # efficiency.
332
438
  def getEffectiveWork(startIdx, endIdx, task = nil)
@@ -337,10 +443,6 @@ class TaskJuggler
337
443
  # The unique key we use to address the result in the cache.
338
444
  @dCache.cached(self, :ResourceScenarioEffectiveWork, startIdx, endIdx,
339
445
  task) do
340
- # Convert the interval dates to indexes if needed.
341
- startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
342
- endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
343
-
344
446
  work = 0.0
345
447
  if @property.container?
346
448
  @property.kids.each do |resource|
@@ -360,96 +462,66 @@ class TaskJuggler
360
462
 
361
463
  # Returns the allocated accumulated time of this resource and its children.
362
464
  def getAllocatedTime(startIdx, endIdx, task = nil)
363
- # Convert the interval dates to indexes if needed.
364
- startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
365
- endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
366
-
367
- time = 0
368
- if @property.container?
369
- @property.kids.each do |resource|
370
- time += resource.getAllocatedTime(@scenarioIdx, startIdx, endIdx, task)
371
- end
372
- else
465
+ treeSum(startIdx, endIdx, task) do
373
466
  return 0 if @scoreboard.nil?
374
467
 
375
- time = @project.convertToDailyLoad(@project['scheduleGranularity'] *
468
+ @project.convertToDailyLoad(@project['scheduleGranularity'] *
376
469
  getAllocatedSlots(startIdx, endIdx, task))
377
470
  end
378
- time
379
471
  end
380
472
 
381
473
  # Return the unallocated work time (in seconds) of the resource and its
382
474
  # children.
383
475
  def getEffectiveFreeTime(startIdx, endIdx)
384
- # Convert the interval dates to indexes if needed.
385
- startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
386
- endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
387
-
388
- freeTime = 0
389
- if @property.container?
390
- @property.kids.each do |resource|
391
- freeTime += resource.getEffectiveFreeTime(@scenarioIdx, startIdx,
392
- endIdx)
393
- end
394
- else
395
- freeTime = getFreeSlots(startIdx, endIdx) *
396
- @project['scheduleGranularity']
476
+ treeSum(startIdx, endIdx) do
477
+ getFreeSlots(startIdx, endIdx) * @project['scheduleGranularity']
397
478
  end
398
- freeTime
399
479
  end
400
480
 
401
481
  # Return the unallocated work of the resource and its children weighted by
402
482
  # their efficiency.
403
483
  def getEffectiveFreeWork(startIdx, endIdx)
404
- # Convert the interval dates to indexes if needed.
405
- startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
406
- endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
407
-
408
- work = 0.0
409
- if @property.container?
410
- @property.kids.each do |resource|
411
- work += resource.getEffectiveFreeWork(@scenarioIdx, startIdx, endIdx)
412
- end
413
- else
414
- work = @project.convertToDailyLoad(
415
- getFreeSlots(startIdx, endIdx) *
416
- @project['scheduleGranularity']) * @efficiency
484
+ treeSum(startIdx, endIdx) do
485
+ @project.convertToDailyLoad(getFreeSlots(startIdx, endIdx) *
486
+ @project['scheduleGranularity']) *
487
+ @efficiency
417
488
  end
418
- work
419
489
  end
420
490
 
421
- # Return the number of working days that are blocked by vacations.
422
- def getVacationDays(startIdx, endIdx)
423
- # Convert the interval dates to indexes if needed.
424
- startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
425
- endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
426
-
427
- vacationDays = 0.0
428
- if @property.container?
429
- @property.kids.each do |resource|
430
- vacationDays += resource.getVacationDays(@scenarioIdx,
431
- startIdx, endIdx)
432
- end
433
- else
434
- initScoreboard if @scoreboard.nil?
435
-
436
- vacationDays = @project.convertToDailyLoad(
437
- getVacationSlots(startIdx, endIdx) *
438
- @project['scheduleGranularity']) * @efficiency
491
+ # Return the number of working days that are blocked by leaves.
492
+ def getTimeOffDays(startIdx, endIdx)
493
+ treeSum(startIdx, endIdx) do
494
+ @project.convertToDailyLoad(getTimeOffSlots(startIdx, endIdx) *
495
+ @project['scheduleGranularity']) *
496
+ @efficiency
439
497
  end
440
- vacationDays
441
498
  end
442
499
 
443
- def turnover(startIdx, endIdx, account, task = nil)
500
+ def turnover(startIdx, endIdx, account, task = nil, includeKids = false)
444
501
  amount = 0.0
445
- if @property.container?
502
+ if @property.container? && includeKids
446
503
  @property.kids.each do |child|
447
- amount += child.turnover(@scenarioIdx, startIdx, endIdx, account, task)
504
+ amount += child.turnover(@scenarioIdx, startIdx, endIdx, account,
505
+ task)
448
506
  end
449
507
  else
450
- @duties.each do |duty|
451
- amount += duty.turnover(@scenarioIdx, startIdx, endIdx, account,
508
+ if task
509
+ # If we have a know task, we only include the amount that is
510
+ # specific to this resource, this task and the chargeset of the
511
+ # task.
512
+ amount += task.turnover(@scenarioIdx, startIdx, endIdx, account,
452
513
  @property)
514
+ elsif !@chargeset.empty?
515
+ # If no tasks was provided, we include the amount of this resource,
516
+ # weighted by the charset of this resource.
517
+ totalResourceCost = cost(startIdx, endIdx)
518
+ @chargeset.each do |set|
519
+ set.each do |accnt, share|
520
+ if share > 0.0 && (accnt == account || accnt.isChildOf?(account))
521
+ amount += totalResourceCost * share
522
+ end
523
+ end
524
+ end
453
525
  end
454
526
  end
455
527
 
@@ -545,7 +617,7 @@ class TaskJuggler
545
617
  end
546
618
 
547
619
  # Return a list of scoreboard intervals that are at least _minDuration_ long
548
- # and contain only off-duty and vacation slots. The result is an Array of
620
+ # and contain only off-duty and leave slots. The result is an Array of
549
621
  # [ start, end ] TjTime values.
550
622
  def collectTimeOffIntervals(iv, minDuration)
551
623
  # Time-off intervals are only useful for leaf resources. Group resources
@@ -581,107 +653,114 @@ class TaskJuggler
581
653
  # Count the number of slots betweend the _startIdx_ and _endIdx_ that can
582
654
  # be used for work
583
655
  def getWorkSlots(startIdx, endIdx)
584
- return 0 if startIdx >= endIdx
585
-
586
- initScoreboard unless @scoreboard
587
-
588
- workSlots = 0
589
- startIdx.upto(endIdx - 1) do |idx|
590
- slot = @scoreboard[idx]
656
+ countSlots(startIdx, endIdx) do |val|
591
657
  # We count free slots and assigned slots.
592
- workSlots += 1 if slot.nil? || slot.is_a?(Task)
658
+ val.nil? || val.is_a?(Task)
593
659
  end
660
+ end
594
661
 
595
- workSlots
662
+ # Count the number of slots that are work time slots but marked as annual
663
+ # leave.
664
+ def getLeaveSlots(startIdx, endIdx, type)
665
+ countSlots(startIdx, endIdx) do |val|
666
+ val.is_a?(Fixnum) && (val & 0x3E) == (Leave::Types[type] << 2)
667
+ end
596
668
  end
597
669
 
598
670
  # Count the free slots between the start and end index.
599
671
  def getFreeSlots(startIdx, endIdx)
600
- return 0 if startIdx >= endIdx
601
-
602
- initScoreboard unless @scoreboard
603
-
604
- freeSlots = 0
605
- startIdx.upto(endIdx - 1) do |idx|
606
- freeSlots += 1 if @scoreboard[idx].nil?
672
+ countSlots(startIdx, endIdx) do |val|
673
+ val.nil?
607
674
  end
608
-
609
- freeSlots
610
675
  end
611
676
 
612
677
  # Count the regular work time slots between the start and end index that
613
- # have been blocked by a vacation.
614
- def getVacationSlots(startIdx, endIdx)
615
- return 0 if startIdx >= endIdx
616
-
617
- initScoreboard unless @scoreboard
618
-
619
- vacationSlots = 0
620
- startIdx.upto(endIdx - 1) do |idx|
621
- val = @scoreboard[idx]
622
- # Bit 1 needs to be unset and the vacation bits must not be 0.
623
- vacationSlots += 1 if val.is_a?(Fixnum) && (val & 0x2) == 0 &&
624
- (val & 0x3C) != 0
678
+ # have been blocked by leaves.
679
+ def getTimeOffSlots(startIdx, endIdx)
680
+ countSlots(startIdx, endIdx) do |val|
681
+ # Bit 1 needs to be unset and the leave bits must not be 0.
682
+ val.is_a?(Fixnum) && (val & 0x2) == 0 && (val & 0x3C) != 0
625
683
  end
626
- vacationSlots
627
684
  end
628
685
 
629
686
  private
630
687
 
631
688
  def initScoreboard
632
- # Create scoreboard and mark all slots as unavailable
689
+ # Create scoreboard and mark all slots as non-working-time.
633
690
  @scoreboard = Scoreboard.new(@project['start'], @project['end'],
634
691
  @project['scheduleGranularity'], 2)
635
692
 
636
- # We'll need this frequently and can savely cache it here.
637
- @shifts = @shifts
638
- @workinghours = @workinghours
639
-
640
693
  # Change all work time slots to nil (available) again.
641
694
  @project.scoreboardSize.times do |i|
642
695
  @scoreboard[i] = nil if onShift?(i)
643
696
  end
644
697
 
645
- # Mark all resource specific vacation slots as such
646
- @vacations.each do |vacation|
647
- startIdx = @scoreboard.dateToIdx(vacation.start)
648
- endIdx = @scoreboard.dateToIdx(vacation.end)
698
+ # Mark all global leave slots as such
699
+ @project['leaves'].each do |leave|
700
+ startIdx = @scoreboard.dateToIdx(leave.interval.start)
701
+ endIdx = @scoreboard.dateToIdx(leave.interval.end)
649
702
  startIdx.upto(endIdx - 1) do |i|
650
- # If the slot is nil, we don't set the time-off bit.
651
- @scoreboard[i] = (@scoreboard[i].nil? ? 0 : 2) | (1 << 2)
703
+ sb = @scoreboard[i]
704
+ # We preseve the work-time bit (#1).
705
+ @scoreboard[i] = (sb.nil? ? 0 : 2) | (leave.typeIdx << 2)
652
706
  end
653
707
  end
654
708
 
655
- # Mark all global vacation slots as such
656
- @project['vacations'].each do |vacation|
657
- startIdx = @scoreboard.dateToIdx(vacation.start)
658
- endIdx = @scoreboard.dateToIdx(vacation.end)
709
+ # Mark all resource specific leave slots as such
710
+ @leaves.each do |leave|
711
+ startIdx = @scoreboard.dateToIdx(leave.interval.start)
712
+ endIdx = @scoreboard.dateToIdx(leave.interval.end)
659
713
  startIdx.upto(endIdx - 1) do |i|
660
- # If the slot is nil or set to 4 then don't set the time-off bit.
661
- sb = @scoreboard[i]
662
- @scoreboard[i] = ((sb.nil? || sb == 4) ? 0 : 2) | (1 << 2)
714
+ if (sb = @scoreboard[i])
715
+ # The slot is already marked as non-working slot. We override the
716
+ # leave type if the new type is larger than the old one.
717
+ leaveIdx = (sb & 0x3C) >> 2
718
+ if leave.typeIdx > leaveIdx
719
+ # The work-time bit (#1) is preserved.
720
+ @scoreboard[i] = (sb & 0x2) | (leave.typeIdx << 2)
721
+ end
722
+ else
723
+ # This marks a working time slot as a leave slot. Since bit 1 is
724
+ # not set, we still know that this could be a working slot.
725
+ @scoreboard[i] = leave.typeIdx << 2
726
+ end
663
727
  end
664
728
  end
665
729
 
666
730
  unless @shifts.nil?
667
- # Mark the vacations from all the shifts the resource is assigned to.
731
+ # Mark the leaves from all the shifts the resource is assigned to.
668
732
  @project.scoreboardSize.times do |i|
669
733
  v = @shifts.getSbSlot(i)
670
- # Check if the vacation replacement bit is set. In that case we copy
671
- # the whole interval over to the resource scoreboard overriding any
672
- # global vacations.
734
+ # Make sure a shift is actually assigned.
735
+ next unless v
736
+
673
737
  if (v & (1 << 8)) != 0
738
+ # Check if the leave replacement bit (#8) is set. In that case we
739
+ # copy the whole interval over to the resource scoreboard
740
+ # overriding any global leaves.
674
741
  @scoreboard[i] = (v & 0x3E == 0) ? nil : (v & 0x3D)
675
- elsif ((sbV = @scoreboard[i]).nil? || (sbV & 0x3C) == 0) &&
742
+ elsif ((sb = @scoreboard[i]).nil? || ((sb & 0x3C) < (v & 0x3C))) &&
676
743
  (v & 0x3C) != 0
677
- # We only add the shift vacations but don't turn global vacation
678
- # slots into working slots again.
744
+ # In merge mode, we only add the shift leaves with higher type
745
+ # index or unassigned slots.
679
746
  @scoreboard[i] = v & 0x3E
680
747
  end
681
748
  end
682
749
  end
683
750
  end
684
751
 
752
+ def countSlots(startIdx, endIdx)
753
+ return 0 if startIdx >= endIdx
754
+
755
+ initScoreboard unless @scoreboard
756
+
757
+ slots = 0
758
+ startIdx.upto(endIdx - 1) do |idx|
759
+ slots += 1 if yield(@scoreboard[idx])
760
+ end
761
+ slots
762
+ end
763
+
685
764
  # Limit the _startIdx_ and _endIdx_ to the actually assigned interval.
686
765
  # If _task_ is provided, fit it for the bookings of this particular task.
687
766
  def fitIndicies(startIdx, endIdx, task = nil)