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
  # = 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)