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
  # = StatusSheetReport.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
@@ -164,7 +164,7 @@ class TaskJuggler
164
164
  responsibility.journalEntries.each do |entry|
165
165
  task = entry.property
166
166
  @file << " task #{task.fullId} {\n"
167
- alertLevel = @project['alertLevels'][entry.alertLevel][0]
167
+ alertLevel = @project['alertLevels'][entry.alertLevel].id
168
168
  @file << " # status #{alertLevel} \"#{entry.headline}\" {\n"
169
169
  @file << " # # Date: #{entry.date}\n"
170
170
  if (tsRecord = entry.timeSheetRecord)
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # = TableReport.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
@@ -15,6 +15,7 @@ require 'taskjuggler/reports/ReportBase'
15
15
  require 'taskjuggler/reports/GanttChart'
16
16
  require 'taskjuggler/reports/ReportTableLegend'
17
17
  require 'taskjuggler/reports/ColumnTable'
18
+ require 'taskjuggler/reports/TableReportColumn'
18
19
  require 'taskjuggler/Query'
19
20
 
20
21
  class TaskJuggler
@@ -27,38 +28,46 @@ class TaskJuggler
27
28
  attr_reader :legend
28
29
 
29
30
  @@propertiesById = {
30
- # ID Header Indent Align Scen Spec.
31
- 'alert' => [ 'Alert', true, :left, false ],
32
- 'alertmessages' => [ 'Alert Messages', false, :left, false ],
33
- 'alertsummaries' => [ 'Alert Summaries', false, :left, false ],
34
- 'alerttrend' => [ 'Alert Trend', false, :left, false ],
35
- 'complete' => [ 'Completion', false, :right, true ],
36
- 'cost' => [ 'Cost', true, :right, true ],
37
- 'duration' => [ 'Duration', true, :right, true ],
38
- 'effort' => [ 'Effort', true, :right, true ],
39
- 'effortdone' => [ 'Effort Done', true, :right, true ],
40
- 'effortleft' => [ 'Effort Left', true, :right, true ],
41
- 'freetime' => [ 'Free Time', true, :right, true ],
42
- 'freework' => [ 'Free Work', true, :right, true ],
43
- 'followers' => [ 'Followers', false, :left, true ],
44
- 'id' => [ 'Id', false, :left, false ],
45
- 'inputs' => [ 'Inputs', false, :left, true ],
46
- 'journal' => [ 'Journal', false, :left, false ],
47
- 'journal_sub' => [ 'Journal', false, :left, false ],
48
- 'journalmessages' => [ 'Journal Messages', false, :left, false ],
49
- 'journalsummaries' => [ 'Journal Summaries', false, :left, false ],
50
- 'line' => [ 'Line No.', false, :right, false ],
51
- 'name' => [ 'Name', true, :left, false ],
52
- 'no' => [ 'No.', false, :right, false ],
53
- 'precursors' => [ 'Precursors', false, :left, true ],
54
- 'rate' => [ 'Rate', true, :right, true ],
55
- 'resources' => [ 'Resources', false, :left, true ],
56
- 'responsible' => [ 'Responsible', false, :left, true ],
57
- 'revenue' => [ 'Revenue', true, :right, true ],
58
- 'scenario' => [ 'Scenario', false, :left, true ],
59
- 'status' => [ 'Status', false, :left, true ],
60
- 'targets' => [ 'Targets', false, :left, true ],
61
- 'bsi' => [ 'BSI', false, :left, false ]
31
+ # ID Header Indent Align Scen Spec.
32
+ 'annualleave' => [ 'Annual Leave', true, :right, true ],
33
+ 'annualleavebalance'=> [ 'Annual Leave Balance', false, :right, true ],
34
+ 'alert' => [ 'Alert', true, :left, false ],
35
+ 'alertmessages' => [ 'Alert Messages', false, :left, false ],
36
+ 'alertsummaries' => [ 'Alert Summaries', false, :left, false ],
37
+ 'alerttrend' => [ 'Alert Trend', false, :left, false ],
38
+ 'balance' => [ 'Balance', true, :right, true ],
39
+ 'bsi' => [ 'BSI', false, :left, false ],
40
+ 'complete' => [ 'Completion', false, :right, true ],
41
+ 'cost' => [ 'Cost', true, :right, true ],
42
+ 'duration' => [ 'Duration', true, :right, true ],
43
+ 'effort' => [ 'Effort', true, :right, true ],
44
+ 'effortdone' => [ 'Effort Done', true, :right, true ],
45
+ 'effortleft' => [ 'Effort Left', true, :right, true ],
46
+ 'freetime' => [ 'Free Time', true, :right, true ],
47
+ 'freework' => [ 'Free Work', true, :right, true ],
48
+ 'followers' => [ 'Followers', false, :left, true ],
49
+ 'fte' => [ 'FTE', true, :right, true ],
50
+ 'headcount' => [ 'Headcount', true, :right, true ],
51
+ 'id' => [ 'Id', false, :left, false ],
52
+ 'inputs' => [ 'Inputs', false, :left, true ],
53
+ 'journal' => [ 'Journal', false, :left, false ],
54
+ 'journal_sub' => [ 'Journal', false, :left, false ],
55
+ 'journalmessages' => [ 'Journal Messages', false, :left, false ],
56
+ 'journalsummaries' => [ 'Journal Summaries', false, :left, false ],
57
+ 'line' => [ 'Line No.', false, :right, false ],
58
+ 'name' => [ 'Name', true, :left, false ],
59
+ 'no' => [ 'No.', false, :right, false ],
60
+ 'precursors' => [ 'Precursors', false, :left, true ],
61
+ 'rate' => [ 'Rate', true, :right, true ],
62
+ 'resources' => [ 'Resources', false, :left, true ],
63
+ 'responsible' => [ 'Responsible', false, :left, true ],
64
+ 'revenue' => [ 'Revenue', true, :right, true ],
65
+ 'scenario' => [ 'Scenario', false, :left, true ],
66
+ 'sickleave' => [ 'Sick Leave', true, :right, true ],
67
+ 'specialleave' => [ 'Special Leave', true, :right, true ],
68
+ 'status' => [ 'Status', false, :left, true ],
69
+ 'targets' => [ 'Targets', false, :left, true ],
70
+ 'unpaidleave' => [ 'Unpaid Leave', true, :right, true ]
62
71
  }
63
72
  @@propertiesByType = {
64
73
  # Type Indent Align
@@ -76,7 +85,10 @@ class TaskJuggler
76
85
 
77
86
  # Reference to the intermediate representation.
78
87
  @table = nil
79
- @start = @end = nil
88
+ # The table is generated row after row. We need to hold some computed
89
+ # values that are specific to certain columns. For that we use a Hash of
90
+ # ReportTableColumn objects.
91
+ @columns = { }
80
92
 
81
93
  @legend = ReportTableLegend.new
82
94
 
@@ -155,12 +167,12 @@ class TaskJuggler
155
167
  end
156
168
 
157
169
  # Return the alignment of the column based on the _colId_ or the
158
- # _propertyType_.
159
- def alignment(colId, propertyType)
170
+ # _attributeType_.
171
+ def alignment(colId, attributeType)
160
172
  if @@propertiesById.has_key?(colId)
161
173
  return @@propertiesById[colId][2]
162
- elsif @@propertiesByType.has_key?(propertyType)
163
- return @@propertiesByType[propertyType][1]
174
+ elsif @@propertiesByType.has_key?(attributeType)
175
+ return @@propertiesByType[attributeType][1]
164
176
  else
165
177
  :center
166
178
  end
@@ -187,87 +199,119 @@ class TaskJuggler
187
199
 
188
200
  protected
189
201
 
190
- # These can't be determined during initialization as they have have been
191
- # changed afterwards.
192
- def setReportPeriod
193
- @start = a('start')
194
- @end = a('end')
195
- end
196
-
197
202
  # In case the user has not specified the report period, we try to fit all
198
- # the _tasks_ in and add an extra 5% time at both ends. _scenarios_ is a
199
- # list of scenario indexes.
200
- def adjustReportPeriod(tasks, scenarios, columns)
201
- return if tasks.empty? ||
202
- a('start') != @project['start'] || a('end') != @project['end']
203
+ # the _tasks_ in and add an extra 5% time at both ends for some specific
204
+ # type of columns. _scenarios_ is a list of scenario indexes. _columnDef_
205
+ # is a reference to the TableColumnDefinition object describing the
206
+ # current column.
207
+ def adjustColumnPeriod(columnDef, tasks = [], scenarios = [])
208
+ # If we have user specified dates for the report period or the column
209
+ # period, we don't adjust the period. This flag is used to mark if we
210
+ # have user-provided values.
211
+ doNotAdjust = false
212
+
213
+ # Determine the start date for the column.
214
+ if columnDef.start
215
+ # We have a user-specified, column specific start date.
216
+ rStart = columnDef.start
217
+ doNotAdjust = true
218
+ else
219
+ # Use the report start date.
220
+ rStart = a('start')
221
+ doNotAdjust = true if rStart != @project['start']
222
+ end
203
223
 
204
- @start = @end = nil
224
+ if columnDef.end
225
+ rEnd = columnDef.end
226
+ doNotAdjust = true
227
+ else
228
+ rEnd = a('end')
229
+ doNotAdjust = true if rEnd != @project['end']
230
+ end
231
+
232
+ # Save the unadjusted dates to the columns Hash.
233
+ @columns[columnDef] = TableReportColumn.new(rStart, rEnd)
234
+
235
+ # If the task list is empty or the user has provided a custom start or
236
+ # end date, we don't touch the report period.
237
+ return if tasks.empty? || scenarios.empty? || doNotAdjust
238
+
239
+ # Find the start date of the earliest tasks included in the report and
240
+ # the end date of the last included tasks.
241
+ rStart = rEnd = nil
205
242
  scenarios.each do |scenarioIdx|
206
243
  tasks.each do |task|
207
244
  date = task['start', scenarioIdx] || @project['start']
208
- @start = date if @start.nil? || date < @start
245
+ rStart = date if rStart.nil? || date < rStart
209
246
  date = task['end', scenarioIdx] || @project['end']
210
- @end = date if @end.nil? || date > @end
247
+ rEnd = date if rEnd.nil? || date > rEnd
211
248
  end
212
249
  end
213
250
 
214
251
  # We want to add at least 5% on both ends.
215
252
  margin = 0
216
- minWidth = @end - @start + 1
217
- columns.each do |column|
218
- case column.id
219
- when 'chart'
220
- # In case we have a 'chart' column, we enforce certain minimum width
221
- # The following table contains an entry for each scale. The entry
222
- # consists of the triple 'seconds per unit', 'minimum width units'
223
- # and 'margin units'. The minimum with does not include the margins
224
- # since they are always added.
225
- mwMap = {
226
- 'hour' => [ 60 * 60, 18, 2 ],
227
- 'day' => [ 60 * 60 * 24, 18, 2 ],
228
- 'week' => [ 60 * 60 * 24 * 7, 6, 1 ],
229
- 'month' => [ 60 * 60 * 24 * 31, 10, 1 ],
230
- 'quarter' => [ 60 * 60 * 24 * 90, 6, 1 ],
231
- 'year' => [ 60 * 60 * 24 * 365, 4, 1 ]
232
- }
233
- entry = mwMap[column.scale]
234
- raise "Unknown scale #{column.scale}" unless entry
235
- margin = entry[0] * entry[2]
236
- # If the with determined by start and end dates of the task is below
237
- # the minimum width, we increase the width to the value provided by
238
- # the table.
239
- minWidth = entry[0] * entry[1] if minWidth < entry[0] * entry[1]
240
- break
241
- when 'hourly', 'daily', 'weekly', 'monthly', 'quarterly', 'yearly'
242
- # For the calendar columns we use a similar approach as we use for
243
- # the 'chart' column.
244
- mwMap = {
245
- 'hourly' => [ 60 * 60, 18, 2 ],
246
- 'daily' => [ 60 * 60 * 24, 18, 2 ],
247
- 'weekly' => [ 60 * 60 * 24 * 7, 6, 1 ],
248
- 'monthly' => [ 60 * 60 * 24 * 31, 10, 1 ],
249
- 'quarterly' => [ 60 * 60 * 24 * 90, 6, 1 ],
250
- 'yearly' => [ 60 * 60 * 24 * 365, 4, 1 ]
251
- }
252
- entry = mwMap[column.id]
253
- raise "Unknown scale #{column.id}" unless entry
254
- margin = entry[0] * entry[2]
255
- minWidth = entry[0] * entry[1] if minWidth < entry[0] * entry[1]
256
- break
257
- end
253
+ minWidth = rEnd - rStart + 1
254
+ case columnDef.id
255
+ when 'chart'
256
+ # In case we have a 'chart' column, we enforce certain minimum width
257
+ # The following table contains an entry for each scale. The entry
258
+ # consists of the triple 'seconds per unit', 'minimum width units'
259
+ # and 'margin units'. The minimum with does not include the margins
260
+ # since they are always added.
261
+ mwMap = {
262
+ 'hour' => [ 60 * 60, 18, 2 ],
263
+ 'day' => [ 60 * 60 * 24, 18, 2 ],
264
+ 'week' => [ 60 * 60 * 24 * 7, 6, 1 ],
265
+ 'month' => [ 60 * 60 * 24 * 31, 10, 1 ],
266
+ 'quarter' => [ 60 * 60 * 24 * 90, 6, 1 ],
267
+ 'year' => [ 60 * 60 * 24 * 365, 4, 1 ]
268
+ }
269
+ entry = mwMap[columnDef.scale]
270
+ raise "Unknown scale #{columnDef.scale}" unless entry
271
+ margin = entry[0] * entry[2]
272
+ # If the with determined by start and end dates of the task is below
273
+ # the minimum width, we increase the width to the value provided by
274
+ # the table.
275
+ minWidth = entry[0] * entry[1] if minWidth < entry[0] * entry[1]
276
+ when 'hourly', 'daily', 'weekly', 'monthly', 'quarterly', 'yearly'
277
+ # For the calendar columns we use a similar approach as we use for
278
+ # the 'chart' column.
279
+ mwMap = {
280
+ 'hourly' => [ 60 * 60, 18, 2 ],
281
+ 'daily' => [ 60 * 60 * 24, 18, 2 ],
282
+ 'weekly' => [ 60 * 60 * 24 * 7, 6, 1 ],
283
+ 'monthly' => [ 60 * 60 * 24 * 31, 10, 1 ],
284
+ 'quarterly' => [ 60 * 60 * 24 * 90, 6, 1 ],
285
+ 'yearly' => [ 60 * 60 * 24 * 365, 4, 1 ]
286
+ }
287
+ entry = mwMap[columnDef.id]
288
+ raise "Unknown scale #{columnDef.id}" unless entry
289
+ margin = entry[0] * entry[2]
290
+ minWidth = entry[0] * entry[1] if minWidth < entry[0] * entry[1]
291
+ else
292
+ doNotAdjust = true
258
293
  end
259
294
 
260
- if minWidth > (@end - @start + 1)
261
- margin += (minWidth - (@end - @start + 1)) / 2
295
+ unless doNotAdjust
296
+ if minWidth > (rEnd - rStart + 1)
297
+ margin += (minWidth - (rEnd - rStart + 1)) / 2
298
+ end
299
+
300
+ rStart -= margin
301
+ rEnd += margin
302
+
303
+ # Save the adjusted dates to the columns Hash.
304
+ @columns[columnDef] = TableReportColumn.new(rStart, rEnd)
262
305
  end
263
- @start -= margin
264
- @end += margin
265
306
  end
266
307
 
267
308
  # Generates cells for the table header. _columnDef_ is the
268
309
  # TableColumnDefinition object that describes the column. Based on the id of
269
310
  # the column different actions need to be taken to generate the header text.
270
311
  def generateHeaderCell(columnDef)
312
+ rStart = @columns[columnDef].start
313
+ rEnd = @columns[columnDef].end
314
+
271
315
  case columnDef.id
272
316
  when 'chart'
273
317
  # For the 'chart' column we generate a GanttChart object. The sizes are
@@ -275,7 +319,7 @@ class TaskJuggler
275
319
  # table.
276
320
  gantt = GanttChart.new(a('now'),
277
321
  a('weekStartsMonday'), self)
278
- gantt.generateByScale(@start, @end, columnDef.scale)
322
+ gantt.generateByScale(rStart, rEnd, columnDef.scale)
279
323
  # The header consists of 2 lines separated by a 1 pixel boundary.
280
324
  gantt.header.height = @table.headerLineHeight * 2 + 1
281
325
  # The maximum width of the chart. In case it needs more space, a
@@ -288,23 +332,23 @@ class TaskJuggler
288
332
  column.scrollbar = gantt.hasScrollbar?
289
333
  @table.equiLines = true
290
334
  when 'hourly'
291
- genCalChartHeader(columnDef, @start.midnight, :sameTimeNextHour,
335
+ genCalChartHeader(columnDef, rStart.midnight, rEnd, :sameTimeNextHour,
292
336
  :weekdayAndDate, :hour)
293
337
  when 'daily'
294
- genCalChartHeader(columnDef, @start.midnight, :sameTimeNextDay,
338
+ genCalChartHeader(columnDef, rStart.midnight, rEnd, :sameTimeNextDay,
295
339
  :monthAndYear, :day)
296
340
  when 'weekly'
297
341
  genCalChartHeader(columnDef,
298
- @start.beginOfWeek(a('weekStartsMonday')),
342
+ rStart.beginOfWeek(a('weekStartsMonday')), rEnd,
299
343
  :sameTimeNextWeek, :monthAndYear, :day)
300
344
  when 'monthly'
301
- genCalChartHeader(columnDef, @start.beginOfMonth, :sameTimeNextMonth,
302
- :year, :shortMonthName)
345
+ genCalChartHeader(columnDef, rStart.beginOfMonth, rEnd,
346
+ :sameTimeNextMonth, :year, :shortMonthName)
303
347
  when 'quarterly'
304
- genCalChartHeader(columnDef, @start.beginOfQuarter,
348
+ genCalChartHeader(columnDef, rStart.beginOfQuarter, rEnd,
305
349
  :sameTimeNextQuarter, :year, :quarterName)
306
350
  when 'yearly'
307
- genCalChartHeader(columnDef, @start.beginOfYear, :sameTimeNextYear,
351
+ genCalChartHeader(columnDef, rStart.beginOfYear, rEnd, :sameTimeNextYear,
308
352
  nil, :year)
309
353
  else
310
354
  # This is the most common case. It does not need any special treatment.
@@ -317,26 +361,57 @@ class TaskJuggler
317
361
  end
318
362
  end
319
363
 
364
+ # Generate a ReportTableLine for each of the accounts in _accountList_. If
365
+ # _scopeLine_ is defined, the generated account lines will be within the
366
+ # scope this resource line.
367
+ def generateAccountList(accountList, lineOffset, mode)
368
+ # Get the current Query from the report context and create a copy. We
369
+ # are going to modify it.
370
+ accountList.query = query = @project.reportContexts.last.query.dup
371
+ accountList.sort!
372
+
373
+ # The primary line counter. Is not used for enclosed lines.
374
+ no = lineOffset
375
+ # The scope line counter. It's reset for each new scope.
376
+ lineNo = lineOffset
377
+ # Init the variable to get a larger scope
378
+ line = nil
379
+ accountList.each do |account|
380
+ query.property = account
381
+
382
+ no += 1
383
+ Log.activity if lineNo % 10 == 0
384
+ lineNo += 1
385
+ a('scenarios').each do |scenarioIdx|
386
+ query.scenarioIdx = scenarioIdx
387
+ # Generate line for each account.
388
+ line = ReportTableLine.new(@table, account, nil)
389
+
390
+ line.no = no
391
+ line.lineNo = lineNo
392
+ line.subLineNo = @table.lines
393
+ setIndent(line, a('accountRoot'), accountList.treeMode?)
394
+
395
+ # Generate a cell for each column in this line.
396
+ a('columns').each do |columnDef|
397
+ query.attributeId = columnDef.id
398
+ next unless generateTableCell(line, columnDef, query)
399
+ end
400
+ end
401
+ end
402
+ lineNo
403
+ end
404
+
320
405
  # Generate a ReportTableLine for each of the tasks in _taskList_. In case
321
406
  # _resourceList_ is not nil, it also generates the nested resource lines for
322
407
  # each resource that is assigned to the particular task. If _scopeLine_
323
- # is defined, the generated task lines will be within the scope this resource
324
- # line.
408
+ # is defined, the generated task lines will be within the scope this
409
+ # resource line.
325
410
  def generateTaskList(taskList, resourceList, scopeLine)
326
- queryAttrs = { 'project' => @project,
327
- 'scopeProperty' => scopeLine ? scopeLine.property : nil,
328
- 'loadUnit' => a('loadUnit'),
329
- 'numberFormat' => a('numberFormat'),
330
- 'timeFormat' => a('timeFormat'),
331
- 'currencyFormat' => a('currencyFormat'),
332
- 'start' => @start, 'end' => @end,
333
- 'hideJournalEntry' => a('hideJournalEntry'),
334
- 'journalMode' => a('journalMode'),
335
- 'journalAttributes' => a('journalAttributes'),
336
- 'sortJournalEntries' => a('sortJournalEntries'),
337
- 'costAccount' => a('costAccount'),
338
- 'revenueAccount' => a('revenueAccount') }
339
- taskList.query = Query.new(queryAttrs)
411
+ # Get the current Query from the report context and create a copy. We
412
+ # are going to modify it.
413
+ taskList.query = query = @project.reportContexts.last.query.dup
414
+ query.scopeProperty = scopeLine ? scopeLine.property : nil
340
415
  taskList.sort!
341
416
 
342
417
  # The primary line counter. Is not used for enclosed lines.
@@ -348,7 +423,6 @@ class TaskJuggler
348
423
  taskList.each do |task|
349
424
  # Get the current Query from the report context and create a copy. We
350
425
  # are going to modify it.
351
- query = @project.reportContexts.last.query.dup
352
426
  query.property = task
353
427
  query.scopeProperty = scopeLine ? scopeLine.property : nil
354
428
 
@@ -368,7 +442,7 @@ class TaskJuggler
368
442
  # Generate a cell for each column in this line.
369
443
  a('columns').each do |columnDef|
370
444
  query.attributeId = columnDef.id
371
- next unless generateTableCell(line, task, columnDef, query)
445
+ next unless generateTableCell(line, columnDef, query)
372
446
  end
373
447
  end
374
448
 
@@ -391,20 +465,10 @@ class TaskJuggler
391
465
  # each task that the resource is assigned to. If _scopeLine_ is defined, the
392
466
  # generated resource lines will be within the scope this task line.
393
467
  def generateResourceList(resourceList, taskList, scopeLine)
394
- queryAttrs = { 'project' => @project,
395
- 'scopeProperty' => scopeLine ? scopeLine.property : nil,
396
- 'loadUnit' => a('loadUnit'),
397
- 'numberFormat' => a('numberFormat'),
398
- 'timeFormat' => a('timeFormat'),
399
- 'currencyFormat' => a('currencyFormat'),
400
- 'start' => @start, 'end' => @end,
401
- 'hideJournalEntry' => a('hideJournalEntry'),
402
- 'journalMode' => a('journalMode'),
403
- 'journalAttributes' => a('journalAttributes'),
404
- 'sortJournalEntries' => a('sortJournalEntries'),
405
- 'costAccount' => a('costAccount'),
406
- 'revenueAccount' => a('revenueAccount') }
407
- resourceList.query = Query.new(queryAttrs)
468
+ # Get the current Query from the report context and create a copy. We
469
+ # are going to modify it.
470
+ resourceList.query = query = @project.reportContexts.last.query.dup
471
+ query.scopeProperty = scopeLine ? scopeLine.property : nil
408
472
  resourceList.sort!
409
473
 
410
474
  # The primary line counter. Is not used for enclosed lines.
@@ -416,7 +480,6 @@ class TaskJuggler
416
480
  resourceList.each do |resource|
417
481
  # Get the current Query from the report context and create a copy. We
418
482
  # are going to modify it.
419
- query = @project.reportContexts.last.query.dup
420
483
  query.property = resource
421
484
  query.scopeProperty = scopeLine ? scopeLine.property : nil
422
485
 
@@ -436,7 +499,7 @@ class TaskJuggler
436
499
  # Generate a cell for each column in this line.
437
500
  a('columns').each do |column|
438
501
  query.attributeId = column.id
439
- next unless generateTableCell(line, resource, column, query)
502
+ next unless generateTableCell(line, column, query)
440
503
  end
441
504
  end
442
505
 
@@ -463,7 +526,8 @@ class TaskJuggler
463
526
  # that is called to advance _t_ to the next table column interval.
464
527
  # _name1Func_ and _name2Func_ are functions that return the upper and lower
465
528
  # title of the particular column.
466
- def genCalChartHeader(columnDef, t, sameTimeNextFunc, name1Func, name2Func)
529
+ def genCalChartHeader(columnDef, t, rEnd, sameTimeNextFunc,
530
+ name1Func, name2Func)
467
531
  tableColumn = ReportTableColumn.new(@table, columnDef, '')
468
532
 
469
533
  # Calendar chars only work when all lines have same height.
@@ -483,14 +547,14 @@ class TaskJuggler
483
547
  # iteration is done with 2 nested loops. The outer loops generates the
484
548
  # intervals for the upper (larger) scale. The inner loop generates the
485
549
  # lower (smaller) scale.
486
- while t < @end
550
+ while t < rEnd
487
551
  cellsInInterval = 0
488
552
  # Label for upper scale. The yearly calendar only has a lower scale.
489
553
  currentInterval = t.send(name1Func) if name1Func
490
554
  firstColumn = nil
491
555
  # The innter loops terminates when the label for the upper scale has
492
556
  # changed to the next scale cell.
493
- while t < @end && (name1Func.nil? ||
557
+ while t < rEnd && (name1Func.nil? ||
494
558
  t.send(name1Func) == currentInterval)
495
559
  # call TjTime::sameTimeNext... function to get the end of the column.
496
560
  nextT = t.send(sameTimeNextFunc)
@@ -508,8 +572,11 @@ class TaskJuggler
508
572
  column.cell1.hidden = true
509
573
  end
510
574
  column.cell2.text = t.send(name2Func).to_s
511
- # TODO: The width should be taken from some data structure.
512
- column.cell2.width = 28
575
+ # We assume an average of 7 pixel per character
576
+ width = 8 + 7 * column.cell2.text.length
577
+ # Ensure a minimum with of 28 to have good looking tables even with
578
+ # small column headers (like day of months numbers).
579
+ column.cell2.width = width <= 28 ? 28 : width
513
580
  # Off-duty cells will have a different color than working time cells.
514
581
  unless @project.hasWorkingTime(iv)
515
582
  column.cell2.category = 'tabhead_offduty'
@@ -537,14 +604,15 @@ class TaskJuggler
537
604
  # columns. In such a case many cells are generated with a single call of
538
605
  # this method. The last kind of cell is actually not a cell. It just
539
606
  # generates the chart objects that belong to the property in this line.
540
- def generateTableCell(line, property, columnDef, query)
541
- if columnDef.start || columnDef.end
542
- # If the user has specified a new start or end time for this column,
543
- # we have to duplicate the query before we modify it.
544
- query = query.dup
545
- query.start = columnDef.start if columnDef.start
546
- query.end = columnDef.end if columnDef.end
547
- end
607
+ def generateTableCell(line, columnDef, query)
608
+ # Adjust the Query to use column specific settings. We create a copy of
609
+ # the Query to avoid spoiling the original query with column specific
610
+ # settings.
611
+ query = query.dup
612
+ query.start = @columns[columnDef].start
613
+ query.end = @columns[columnDef].end
614
+ query.listType = columnDef.listType
615
+ query.listItem = columnDef.listItem
548
616
 
549
617
  case columnDef.id
550
618
  when 'chart'
@@ -562,26 +630,26 @@ class TaskJuggler
562
630
  # The calendar cells can be all generated by the same function. But we
563
631
  # need to use different parameters.
564
632
  when 'hourly'
565
- start = @start.midnight
633
+ start = query.start.midnight
566
634
  sameTimeNextFunc = :sameTimeNextHour
567
635
  when 'daily'
568
- start = @start.midnight
636
+ start = query.start.midnight
569
637
  sameTimeNextFunc = :sameTimeNextDay
570
638
  when 'weekly'
571
- start = @start.beginOfWeek(a('weekStartsMonday'))
639
+ start = query.start.beginOfWeek(a('weekStartsMonday'))
572
640
  sameTimeNextFunc = :sameTimeNextWeek
573
641
  when 'monthly'
574
- start = @start.beginOfMonth
642
+ start = query.start.beginOfMonth
575
643
  sameTimeNextFunc = :sameTimeNextMonth
576
644
  when 'quarterly'
577
- start = @start.beginOfQuarter
645
+ start = query.start.beginOfQuarter
578
646
  sameTimeNextFunc = :sameTimeNextQuarter
579
647
  when 'yearly'
580
- start = @start.beginOfYear
648
+ start = query.start.beginOfYear
581
649
  sameTimeNextFunc = :sameTimeNextYear
582
650
  else
583
651
  if calculated?(columnDef.id)
584
- return genCalculatedCell(query, line, columnDef, property)
652
+ return genCalculatedCell(query, line, columnDef)
585
653
  else
586
654
  return genStandardCell(query, line, columnDef)
587
655
  end
@@ -595,13 +663,15 @@ class TaskJuggler
595
663
 
596
664
  PlaceHolderCell.new(line, tcLine)
597
665
  # Depending on the property type we use different generator functions.
598
- if property.is_a?(Task)
666
+ if query.property.is_a?(Task)
599
667
  genCalChartTaskCell(query, tcLine, columnDef, start, sameTimeNextFunc)
600
- elsif property.is_a?(Resource)
668
+ elsif query.property.is_a?(Resource)
601
669
  genCalChartResourceCell(query, tcLine, columnDef, start,
602
670
  sameTimeNextFunc)
671
+ elsif query.property.is_a?(Account)
672
+ genCalChartAccountCell(query, tcLine, columnDef, start, sameTimeNextFunc)
603
673
  else
604
- raise "Unknown property type #{property.class}"
674
+ raise "Unknown property type #{query.property.class}"
605
675
  end
606
676
  true
607
677
  end
@@ -610,16 +680,14 @@ class TaskJuggler
610
680
  # property that line is for. It returns true if the cell exists, false for a
611
681
  # hidden cell.
612
682
  def genStandardCell(query, line, columnDef)
613
- query = query.dup
614
- query.listType = columnDef.listType
615
- query.listItem = columnDef.listItem
616
-
617
683
  # Find out, what type of PropertyTreeNode we are dealing with.
618
684
  property = line.property
619
685
  if property.is_a?(Task)
620
686
  propertyList = @project.tasks
621
687
  elsif property.is_a?(Resource)
622
688
  propertyList = @project.resources
689
+ elsif property.is_a?(Account)
690
+ propertyList = @project.accounts
623
691
  else
624
692
  raise "Unknown property type #{property.class}"
625
693
  end
@@ -632,7 +700,7 @@ class TaskJuggler
632
700
  return false
633
701
  end
634
702
 
635
- setStandardCellAttributes(cell, columnDef,
703
+ setStandardCellAttributes(query, cell, columnDef,
636
704
  propertyList.attributeType(columnDef.id), line)
637
705
 
638
706
  # If the user has requested a custom cell text, this will be used
@@ -653,13 +721,8 @@ class TaskJuggler
653
721
  # or other sources of information. It returns true if the cell exists, false
654
722
  # for a hidden cell. _query_ is the Query to get the cell value. _line_
655
723
  # is the ReportTableLine of the cell. _columnDef_ is the
656
- # TableColumnDefinition of the column. _property_ is the PropertyTreeNode
657
- # that is reported in this cell.
658
- def genCalculatedCell(query, line, columnDef, property)
659
- query = query.dup
660
- query.listType = columnDef.listType
661
- query.listItem = columnDef.listItem
662
-
724
+ # TableColumnDefinition of the column.
725
+ def genCalculatedCell(query, line, columnDef)
663
726
  # Create a new cell
664
727
  cell = newCell(query, line)
665
728
 
@@ -668,7 +731,7 @@ class TaskJuggler
668
731
  return false
669
732
  end
670
733
 
671
- setStandardCellAttributes(cell, columnDef, nil, line)
734
+ setStandardCellAttributes(query, cell, columnDef, nil, line)
672
735
 
673
736
  if query.process
674
737
  cell.text = (rti = query.to_rti) ? rti : query.to_s
@@ -677,15 +740,16 @@ class TaskJuggler
677
740
  # Some columns need some extra care.
678
741
  case columnDef.id
679
742
  when 'alert'
680
- id = @project.alertLevelId(query.to_num)
743
+ id = @project['alertLevels'][query.to_sort].id
681
744
  cell.icon = "flag-#{id}"
682
- cell.fontColor = @project.alertLevelColor(query.to_sort)
745
+ cell.fontColor = @project['alertLevels'][query.to_sort].color
683
746
  when 'alerttrend'
684
747
  icons = %w( up flat down )
685
748
  cell.icon = "trend-#{icons[query.to_sort]}"
686
749
  when 'line'
687
750
  cell.text = line.lineNo.to_s
688
751
  when 'name'
752
+ property = query.property
689
753
  cell.icon =
690
754
  if property.is_a?(Task)
691
755
  if property.container?
@@ -722,6 +786,49 @@ class TaskJuggler
722
786
  true
723
787
  end
724
788
 
789
+ # Generate the cells for the account lines of a calendar column. These
790
+ # lines do not directly belong to the @table object but to an embedded
791
+ # ColumnTable object. Therefor a single @table column usually has many
792
+ # cells on each single line. _scenarioIdx_ is the index of the scenario
793
+ # that is reported in this line. _line_ is the @table line. _t_ is the
794
+ # start date for the calendar. _sameTimeNextFunc_ is the function that
795
+ # will move the date to the next cell.
796
+ def genCalChartAccountCell(query, line, columnDef, t, sameTimeNextFunc)
797
+ # We modify the start and end dates to match the cell boundaries. So
798
+ # we need to make sure we don't modify the original Query but our own
799
+ # copies.
800
+ query = query.dup
801
+
802
+ firstCell = nil
803
+ endDate = query.end
804
+ while t < endDate
805
+ # call TjTime::sameTimeNext... function
806
+ nextT = t.send(sameTimeNextFunc)
807
+ query.attributeId = 'balance'
808
+ query.start = t
809
+ query.end = nextT
810
+ query.process
811
+
812
+ # Create a new cell
813
+ cell = newCell(query, line)
814
+
815
+ cell.text = query.to_s
816
+
817
+ cdText = columnDef.cellText.getPattern(query)
818
+ cell.text = cdText if cdText
819
+ cell.showTooltipHint = false
820
+
821
+ setAccountCellBgColor(query, line, cell)
822
+
823
+ setCustomCellAttributes(cell, columnDef, query)
824
+
825
+ tryCellMerging(cell, line, firstCell)
826
+
827
+ t = nextT
828
+ firstCell = cell unless firstCell
829
+ end
830
+ end
831
+
725
832
  # Generate the cells for the task lines of a calendar column. These lines do
726
833
  # not directly belong to the @table object but to an embedded ColumnTable
727
834
  # object. Therefor a single @table column usually has many cells on each
@@ -729,7 +836,7 @@ class TaskJuggler
729
836
  # in this line. _line_ is the @table line. _t_ is the start date for the
730
837
  # calendar. _sameTimeNextFunc_ is the function that will move the date to
731
838
  # the next cell.
732
- def genCalChartTaskCell(origQuery, line, columnDef, t, sameTimeNextFunc)
839
+ def genCalChartTaskCell(query, line, columnDef, t, sameTimeNextFunc)
733
840
  task = line.property
734
841
  # Find out if we have an enclosing resource scope.
735
842
  if line.scopeLine && line.scopeLine.property.is_a?(Resource)
@@ -740,17 +847,19 @@ class TaskJuggler
740
847
 
741
848
  # Get the interval of the task. In case a date is invalid due to a
742
849
  # scheduling problem, we use the full project interval.
743
- taskStart = task['start', origQuery.scenarioIdx]
744
- taskEnd = task['end', origQuery.scenarioIdx]
850
+ taskStart = task['start', query.scenarioIdx]
851
+ taskEnd = task['end', query.scenarioIdx]
745
852
  taskIv = TimeInterval.new(taskStart.nil? ? @project['start'] : taskStart,
746
853
  taskEnd.nil? ? @project['end'] : taskEnd)
747
854
 
855
+ # We modify the start and end dates to match the cell boundaries. So
856
+ # we need to make sure we don't modify the original Query but our own
857
+ # copies.
858
+ query = query.dup
859
+
748
860
  firstCell = nil
749
- while t < @end
750
- # We modify the start and end dates to match the cell boundaries. So
751
- # we need to make sure we don't modify the original Query but our own
752
- # copies.
753
- query = origQuery.dup
861
+ endDate = query.end
862
+ while t < endDate
754
863
  # call TjTime::sameTimeNext... function
755
864
  nextT = t.send(sameTimeNextFunc)
756
865
  cellIv = TimeInterval.new(t, nextT)
@@ -768,7 +877,7 @@ class TaskJuggler
768
877
  # Create a new cell
769
878
  cell = newCell(query, line)
770
879
 
771
- # To increase readability, we don't show 0.0 values.
880
+ # To increase readability show empty cells instead of 0.0 values.
772
881
  cell.text = query.to_s if query.to_num != 0.0
773
882
  else
774
883
  raise "Unknown column content #{column.content}"
@@ -782,7 +891,6 @@ class TaskJuggler
782
891
  if cellIv.overlaps?(taskIv)
783
892
  # The cell is either a container or leaf task
784
893
  cell.category = task.container? ? 'calconttask' : 'caltask'
785
- setCustomCellAttributes(cell, columnDef, query)
786
894
  elsif !@project.isWorkingTime(cellIv)
787
895
  # The cell is a vacation cell.
788
896
  cell.category = 'offduty'
@@ -792,6 +900,7 @@ class TaskJuggler
792
900
  end
793
901
  cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
794
902
 
903
+ setCustomCellAttributes(cell, columnDef, query)
795
904
  tryCellMerging(cell, line, firstCell)
796
905
 
797
906
  t = nextT
@@ -810,15 +919,15 @@ class TaskJuggler
810
919
  # reported in this line. _line_ is the @table line. _t_ is the start date
811
920
  # for the calendar. _sameTimeNextFunc_ is the function that will move the
812
921
  # date to the next cell.
813
- def genCalChartResourceCell(origQuery, line, columnDef, t,
922
+ def genCalChartResourceCell(query, line, columnDef, t,
814
923
  sameTimeNextFunc)
815
924
  # Find out if we have an enclosing task scope.
816
925
  if line.scopeLine && line.scopeLine.property.is_a?(Task)
817
926
  task = line.scopeLine.property
818
927
  # Get the interval of the task. In case a date is invalid due to a
819
928
  # scheduling problem, we use the full project interval.
820
- taskStart = task['start', origQuery.scenarioIdx]
821
- taskEnd = task['end', origQuery.scenarioIdx]
929
+ taskStart = task['start', query.scenarioIdx]
930
+ taskEnd = task['end', query.scenarioIdx]
822
931
  taskIv = TimeInterval.new(taskStart.nil? ? @project['start'] :
823
932
  taskStart,
824
933
  taskEnd.nil? ? @project['end'] : taskEnd)
@@ -826,13 +935,14 @@ class TaskJuggler
826
935
  task = nil
827
936
  end
828
937
 
829
- firstCell = nil
830
- while t < @end
831
- # We modify the start and end dates to match the cell boundaries. So
832
- # we need to make sure we don't modify the original Query but our own
833
- # copies.
834
- query = origQuery.dup
938
+ # We modify the start and end dates to match the cell boundaries. So
939
+ # we need to make sure we don't modify the original Query but our own
940
+ # copies.
941
+ query = query.dup
835
942
 
943
+ firstCell = nil
944
+ endDate = query.end
945
+ while t < endDate
836
946
  # Create a new cell
837
947
  cell = newCell(query, line)
838
948
 
@@ -847,6 +957,7 @@ class TaskJuggler
847
957
  query.process
848
958
  workLoad = query.to_num
849
959
  scaledWorkLoad = query.to_s
960
+
850
961
  if task
851
962
  # Get work load for the particular task.
852
963
  query.scopeProperty = task
@@ -917,6 +1028,8 @@ class TaskJuggler
917
1028
  end
918
1029
  cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
919
1030
 
1031
+ setCustomCellAttributes(cell, columnDef, query)
1032
+
920
1033
  tryCellMerging(cell, line, firstCell)
921
1034
 
922
1035
  t = nextT
@@ -931,7 +1044,7 @@ class TaskJuggler
931
1044
 
932
1045
  # This method takes care of often used cell attributes like indentation,
933
1046
  # alignment and background color.
934
- def setStandardCellAttributes(cell, columnDef, attributeType, line)
1047
+ def setStandardCellAttributes(query, cell, columnDef, attributeType, line)
935
1048
  # Determine whether it should be indented
936
1049
  if indent(columnDef.id, attributeType)
937
1050
  cell.indent = line.indentation
@@ -942,11 +1055,13 @@ class TaskJuggler
942
1055
 
943
1056
  # Set background color
944
1057
  if line.property.is_a?(Task)
945
- cell.category = line.property.get('index') % 2 == 1 ?
946
- 'taskcell1' : 'taskcell2'
947
- else
948
- cell.category = line.property.get('index') % 2 == 1 ?
949
- 'resourcecell1' : 'resourcecell2'
1058
+ cell.category = 'taskcell'
1059
+ cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
1060
+ elsif line.property.is_a?(Resource)
1061
+ cell.category = 'resourcecell'
1062
+ cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
1063
+ elsif line.property.is_a?(Account)
1064
+ setAccountCellBgColor(query, line, cell)
950
1065
  end
951
1066
 
952
1067
  # Set column width
@@ -1019,6 +1134,23 @@ class TaskJuggler
1019
1134
  end
1020
1135
  end
1021
1136
 
1137
+ def setAccountCellBgColor(query, line, cell)
1138
+ if query.costAccount &&
1139
+ (query.property.isChildOf?(query.costAccount) ||
1140
+ query.costAccount == query.property)
1141
+ prefix = 'cost'
1142
+ elsif query.revenueAccount &&
1143
+ (query.property.isChildOf?(query.revenueAccount) ||
1144
+ query.revenueAccount == query.property)
1145
+ prefix = 'revenue'
1146
+ else
1147
+ prefix = ''
1148
+ end
1149
+
1150
+ cell.category = prefix + 'accountcell' +
1151
+ (line.property.get('index') % 2 == 1 ? '1' : '2')
1152
+ end
1153
+
1022
1154
  # Make sure we have a valid cell text. If not, this is the result of an
1023
1155
  # error. This could happen after scheduling errors.
1024
1156
  def checkCellText(cell)