taskjuggler 3.0.0 → 3.1.0

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