taskjuggler 0.0.2

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 (571) hide show
  1. data/COPYING +280 -0
  2. data/README +31 -0
  3. data/Rakefile +20 -0
  4. data/benchmarks/UTF-8-Strings.rb +58 -0
  5. data/benchmarks/allocate.tjp +30 -0
  6. data/benchmarks/booking.tjp +62 -0
  7. data/benchmarks/depends.tjp +112 -0
  8. data/benchmarks/htmltaskreport.tjp +45 -0
  9. data/benchmarks/runbench.rb +24 -0
  10. data/bin/tj3 +3 -0
  11. data/bin/tj3man +3 -0
  12. data/doc/classes/AppConfig.html +808 -0
  13. data/doc/classes/Arguments.html +226 -0
  14. data/doc/classes/String.html +395 -0
  15. data/doc/classes/TaskJuggler.html +1358 -0
  16. data/doc/classes/TaskJuggler/Account.html +257 -0
  17. data/doc/classes/TaskJuggler/AccountScenario.html +218 -0
  18. data/doc/classes/TaskJuggler/Allocation.html +419 -0
  19. data/doc/classes/TaskJuggler/AllocationAttribute.html +291 -0
  20. data/doc/classes/TaskJuggler/AttributeBase.html +608 -0
  21. data/doc/classes/TaskJuggler/AttributeDefinition.html +259 -0
  22. data/doc/classes/TaskJuggler/Booking.html +307 -0
  23. data/doc/classes/TaskJuggler/BookingListAttribute.html +263 -0
  24. data/doc/classes/TaskJuggler/BooleanAttribute.html +261 -0
  25. data/doc/classes/TaskJuggler/CSVFile.html +325 -0
  26. data/doc/classes/TaskJuggler/Charge.html +279 -0
  27. data/doc/classes/TaskJuggler/ChargeListAttribute.html +229 -0
  28. data/doc/classes/TaskJuggler/ChargeSet.html +440 -0
  29. data/doc/classes/TaskJuggler/ChargeSetListAttribute.html +276 -0
  30. data/doc/classes/TaskJuggler/ColumnTable.html +260 -0
  31. data/doc/classes/TaskJuggler/DateAttribute.html +194 -0
  32. data/doc/classes/TaskJuggler/DependencyListAttribute.html +267 -0
  33. data/doc/classes/TaskJuggler/DurationAttribute.html +229 -0
  34. data/doc/classes/TaskJuggler/FixnumAttribute.html +194 -0
  35. data/doc/classes/TaskJuggler/FlagListAttribute.html +263 -0
  36. data/doc/classes/TaskJuggler/FloatAttribute.html +229 -0
  37. data/doc/classes/TaskJuggler/GanttChart.html +667 -0
  38. data/doc/classes/TaskJuggler/GanttContainer.html +441 -0
  39. data/doc/classes/TaskJuggler/GanttHeader.html +280 -0
  40. data/doc/classes/TaskJuggler/GanttHeaderScaleItem.html +245 -0
  41. data/doc/classes/TaskJuggler/GanttLine.html +398 -0
  42. data/doc/classes/TaskJuggler/GanttLoadStack.html +327 -0
  43. data/doc/classes/TaskJuggler/GanttMilestone.html +415 -0
  44. data/doc/classes/TaskJuggler/GanttRouter.html +425 -0
  45. data/doc/classes/TaskJuggler/GanttTaskBar.html +429 -0
  46. data/doc/classes/TaskJuggler/HTMLDocument.html +240 -0
  47. data/doc/classes/TaskJuggler/HTMLGraphics.html +231 -0
  48. data/doc/classes/TaskJuggler/Interval.html +552 -0
  49. data/doc/classes/TaskJuggler/IntervalListAttribute.html +267 -0
  50. data/doc/classes/TaskJuggler/KeywordDocumentation.html +796 -0
  51. data/doc/classes/TaskJuggler/Limits.html +416 -0
  52. data/doc/classes/TaskJuggler/Limits/Limit.html +381 -0
  53. data/doc/classes/TaskJuggler/LimitsAttribute.html +261 -0
  54. data/doc/classes/TaskJuggler/Log.html +613 -0
  55. data/doc/classes/TaskJuggler/LogicalAttribute.html +226 -0
  56. data/doc/classes/TaskJuggler/LogicalExpression.html +251 -0
  57. data/doc/classes/TaskJuggler/LogicalFlag.html +229 -0
  58. data/doc/classes/TaskJuggler/LogicalFunction.html +324 -0
  59. data/doc/classes/TaskJuggler/LogicalOperation.html +299 -0
  60. data/doc/classes/TaskJuggler/Macro.html +194 -0
  61. data/doc/classes/TaskJuggler/MacroParser.html +360 -0
  62. data/doc/classes/TaskJuggler/MacroTable.html +366 -0
  63. data/doc/classes/TaskJuggler/Message.html +281 -0
  64. data/doc/classes/TaskJuggler/MessageHandler.html +215 -0
  65. data/doc/classes/TaskJuggler/Project.html +1606 -0
  66. data/doc/classes/TaskJuggler/ProjectFileParser.html +412 -0
  67. data/doc/classes/TaskJuggler/PropertyList.html +597 -0
  68. data/doc/classes/TaskJuggler/PropertySet.html +1200 -0
  69. data/doc/classes/TaskJuggler/PropertyTreeNode.html +1449 -0
  70. data/doc/classes/TaskJuggler/Query.html +600 -0
  71. data/doc/classes/TaskJuggler/RealFormat.html +252 -0
  72. data/doc/classes/TaskJuggler/ReferenceAttribute.html +194 -0
  73. data/doc/classes/TaskJuggler/Report.html +528 -0
  74. data/doc/classes/TaskJuggler/ReportElement.html +1070 -0
  75. data/doc/classes/TaskJuggler/ReportTable.html +497 -0
  76. data/doc/classes/TaskJuggler/ReportTableCell.html +518 -0
  77. data/doc/classes/TaskJuggler/ReportTableColumn.html +364 -0
  78. data/doc/classes/TaskJuggler/ReportTableElement.html +644 -0
  79. data/doc/classes/TaskJuggler/ReportTableLegend.html +343 -0
  80. data/doc/classes/TaskJuggler/ReportTableLine.html +431 -0
  81. data/doc/classes/TaskJuggler/Resource.html +211 -0
  82. data/doc/classes/TaskJuggler/ResourceListAttribute.html +267 -0
  83. data/doc/classes/TaskJuggler/ResourceListRE.html +249 -0
  84. data/doc/classes/TaskJuggler/ResourceScenario.html +1137 -0
  85. data/doc/classes/TaskJuggler/RichText.html +537 -0
  86. data/doc/classes/TaskJuggler/RichTextAttribute.html +229 -0
  87. data/doc/classes/TaskJuggler/RichTextDocument.html +418 -0
  88. data/doc/classes/TaskJuggler/RichTextElement.html +829 -0
  89. data/doc/classes/TaskJuggler/RichTextException.html +212 -0
  90. data/doc/classes/TaskJuggler/RichTextParser.html +317 -0
  91. data/doc/classes/TaskJuggler/RichTextProtocolExample.html +303 -0
  92. data/doc/classes/TaskJuggler/RichTextProtocolHandler.html +194 -0
  93. data/doc/classes/TaskJuggler/RichTextScanner.html +561 -0
  94. data/doc/classes/TaskJuggler/RichTextSnip.html +364 -0
  95. data/doc/classes/TaskJuggler/RichTextSyntaxRules.html +883 -0
  96. data/doc/classes/TaskJuggler/Scenario.html +163 -0
  97. data/doc/classes/TaskJuggler/ScenarioData.html +354 -0
  98. data/doc/classes/TaskJuggler/Scoreboard.html +638 -0
  99. data/doc/classes/TaskJuggler/Shift.html +255 -0
  100. data/doc/classes/TaskJuggler/ShiftAssignment.html +488 -0
  101. data/doc/classes/TaskJuggler/ShiftAssignments.html +715 -0
  102. data/doc/classes/TaskJuggler/ShiftAssignmentsAttribute.html +261 -0
  103. data/doc/classes/TaskJuggler/ShiftScenario.html +282 -0
  104. data/doc/classes/TaskJuggler/SourceFileInfo.html +247 -0
  105. data/doc/classes/TaskJuggler/StringAttribute.html +229 -0
  106. data/doc/classes/TaskJuggler/SymbolAttribute.html +194 -0
  107. data/doc/classes/TaskJuggler/SyntaxReference.html +516 -0
  108. data/doc/classes/TaskJuggler/TOCEntry.html +242 -0
  109. data/doc/classes/TaskJuggler/TableColumnDefinition.html +273 -0
  110. data/doc/classes/TaskJuggler/TableOfContents.html +256 -0
  111. data/doc/classes/TaskJuggler/Task.html +203 -0
  112. data/doc/classes/TaskJuggler/TaskDependency.html +251 -0
  113. data/doc/classes/TaskJuggler/TaskListAttribute.html +267 -0
  114. data/doc/classes/TaskJuggler/TaskListRE.html +250 -0
  115. data/doc/classes/TaskJuggler/TaskScenario.html +2206 -0
  116. data/doc/classes/TaskJuggler/TextParser.html +670 -0
  117. data/doc/classes/TaskJuggler/TextParser/Pattern.html +923 -0
  118. data/doc/classes/TaskJuggler/TextParser/Rule.html +779 -0
  119. data/doc/classes/TaskJuggler/TextParser/StackElement.html +267 -0
  120. data/doc/classes/TaskJuggler/TextParser/TextParserResultArray.html +212 -0
  121. data/doc/classes/TaskJuggler/TextParser/TokenDoc.html +221 -0
  122. data/doc/classes/TaskJuggler/TextScanner.html +708 -0
  123. data/doc/classes/TaskJuggler/TextScanner/BufferStreamHandle.html +355 -0
  124. data/doc/classes/TaskJuggler/TextScanner/FileStreamHandle.html +341 -0
  125. data/doc/classes/TaskJuggler/TextScanner/StreamHandle.html +260 -0
  126. data/doc/classes/TaskJuggler/TjException.html +185 -0
  127. data/doc/classes/TaskJuggler/TjTime.html +1845 -0
  128. data/doc/classes/TaskJuggler/TjpExample.html +310 -0
  129. data/doc/classes/TaskJuggler/TjpExportRE.html +329 -0
  130. data/doc/classes/TaskJuggler/TjpSyntaxRules.html +8928 -0
  131. data/doc/classes/TaskJuggler/UserManual.html +606 -0
  132. data/doc/classes/TaskJuggler/WorkingHours.html +582 -0
  133. data/doc/classes/TaskJuggler/WorkingHoursAttribute.html +284 -0
  134. data/doc/classes/TaskJuggler/XMLBlob.html +207 -0
  135. data/doc/classes/TaskJuggler/XMLComment.html +206 -0
  136. data/doc/classes/TaskJuggler/XMLDocument.html +293 -0
  137. data/doc/classes/TaskJuggler/XMLElement.html +341 -0
  138. data/doc/classes/TaskJuggler/XMLNamedText.html +174 -0
  139. data/doc/classes/TaskJuggler/XMLText.html +221 -0
  140. data/doc/files/COPYING.html +448 -0
  141. data/doc/files/README.html +134 -0
  142. data/doc/files/lib/AccountScenario_rb.html +116 -0
  143. data/doc/files/lib/Account_rb.html +118 -0
  144. data/doc/files/lib/Allocation_rb.html +118 -0
  145. data/doc/files/lib/AppConfig_rb.html +116 -0
  146. data/doc/files/lib/AttributeBase_rb.html +106 -0
  147. data/doc/files/lib/AttributeDefinition_rb.html +106 -0
  148. data/doc/files/lib/Attributes_rb.html +130 -0
  149. data/doc/files/lib/Booking_rb.html +106 -0
  150. data/doc/files/lib/ChargeSet_rb.html +116 -0
  151. data/doc/files/lib/Charge_rb.html +116 -0
  152. data/doc/files/lib/HTMLDocument_rb.html +116 -0
  153. data/doc/files/lib/Interval_rb.html +116 -0
  154. data/doc/files/lib/KeywordDocumentation_rb.html +122 -0
  155. data/doc/files/lib/Limits_rb.html +116 -0
  156. data/doc/files/lib/Log_rb.html +116 -0
  157. data/doc/files/lib/LogicalExpression_rb.html +122 -0
  158. data/doc/files/lib/LogicalFlag_rb.html +116 -0
  159. data/doc/files/lib/LogicalFunction_rb.html +116 -0
  160. data/doc/files/lib/LogicalOperation_rb.html +116 -0
  161. data/doc/files/lib/MacroParser_rb.html +118 -0
  162. data/doc/files/lib/MacroTable_rb.html +122 -0
  163. data/doc/files/lib/MessageHandler_rb.html +106 -0
  164. data/doc/files/lib/Message_rb.html +116 -0
  165. data/doc/files/lib/ProjectFileParser_rb.html +122 -0
  166. data/doc/files/lib/Project_rb.html +148 -0
  167. data/doc/files/lib/PropertyList_rb.html +106 -0
  168. data/doc/files/lib/PropertySet_rb.html +118 -0
  169. data/doc/files/lib/PropertyTreeNode_rb.html +106 -0
  170. data/doc/files/lib/Query_rb.html +116 -0
  171. data/doc/files/lib/RealFormat_rb.html +106 -0
  172. data/doc/files/lib/ResourceScenario_rb.html +116 -0
  173. data/doc/files/lib/Resource_rb.html +118 -0
  174. data/doc/files/lib/RichTextDocument_rb.html +120 -0
  175. data/doc/files/lib/RichTextElement_rb.html +120 -0
  176. data/doc/files/lib/RichTextParser_rb.html +120 -0
  177. data/doc/files/lib/RichTextProtocolExample_rb.html +120 -0
  178. data/doc/files/lib/RichTextProtocolHandler_rb.html +106 -0
  179. data/doc/files/lib/RichTextScanner_rb.html +116 -0
  180. data/doc/files/lib/RichTextSnip_rb.html +118 -0
  181. data/doc/files/lib/RichTextSyntaxRules_rb.html +106 -0
  182. data/doc/files/lib/RichText_rb.html +118 -0
  183. data/doc/files/lib/ScenarioData_rb.html +118 -0
  184. data/doc/files/lib/Scenario_rb.html +116 -0
  185. data/doc/files/lib/Scoreboard_rb.html +106 -0
  186. data/doc/files/lib/ShiftAssignments_rb.html +116 -0
  187. data/doc/files/lib/ShiftScenario_rb.html +116 -0
  188. data/doc/files/lib/Shift_rb.html +118 -0
  189. data/doc/files/lib/SourceFileInfo_rb.html +106 -0
  190. data/doc/files/lib/SyntaxReference_rb.html +122 -0
  191. data/doc/files/lib/TOCEntry_rb.html +118 -0
  192. data/doc/files/lib/TableColumnDefinition_rb.html +106 -0
  193. data/doc/files/lib/TableOfContents_rb.html +118 -0
  194. data/doc/files/lib/TaskDependency_rb.html +106 -0
  195. data/doc/files/lib/TaskJuggler_rb.html +120 -0
  196. data/doc/files/lib/TaskScenario_rb.html +116 -0
  197. data/doc/files/lib/Task_rb.html +118 -0
  198. data/doc/files/lib/TextParser/Pattern_rb.html +116 -0
  199. data/doc/files/lib/TextParser/Rule_rb.html +106 -0
  200. data/doc/files/lib/TextParser/StackElement_rb.html +106 -0
  201. data/doc/files/lib/TextParser/TokenDoc_rb.html +106 -0
  202. data/doc/files/lib/TextParser_rb.html +124 -0
  203. data/doc/files/lib/TextScanner_rb.html +128 -0
  204. data/doc/files/lib/Tj3Config_rb.html +118 -0
  205. data/doc/files/lib/TjException_rb.html +106 -0
  206. data/doc/files/lib/TjTime_rb.html +118 -0
  207. data/doc/files/lib/TjpExample_rb.html +116 -0
  208. data/doc/files/lib/TjpSyntaxRules_rb.html +106 -0
  209. data/doc/files/lib/UTF8String_rb.html +132 -0
  210. data/doc/files/lib/UserManual_rb.html +124 -0
  211. data/doc/files/lib/WorkingHours_rb.html +116 -0
  212. data/doc/files/lib/XMLDocument_rb.html +116 -0
  213. data/doc/files/lib/XMLElement_rb.html +116 -0
  214. data/doc/files/lib/reports/CSVFile_rb.html +116 -0
  215. data/doc/files/lib/reports/ColumnTable_rb.html +116 -0
  216. data/doc/files/lib/reports/GanttChart_rb.html +122 -0
  217. data/doc/files/lib/reports/GanttContainer_rb.html +116 -0
  218. data/doc/files/lib/reports/GanttHeaderScaleItem_rb.html +106 -0
  219. data/doc/files/lib/reports/GanttHeader_rb.html +116 -0
  220. data/doc/files/lib/reports/GanttLine_rb.html +126 -0
  221. data/doc/files/lib/reports/GanttLoadStack_rb.html +116 -0
  222. data/doc/files/lib/reports/GanttMilestone_rb.html +116 -0
  223. data/doc/files/lib/reports/GanttRouter_rb.html +106 -0
  224. data/doc/files/lib/reports/GanttTaskBar_rb.html +116 -0
  225. data/doc/files/lib/reports/HTMLGraphics_rb.html +106 -0
  226. data/doc/files/lib/reports/ReportElement_rb.html +118 -0
  227. data/doc/files/lib/reports/ReportTableCell_rb.html +106 -0
  228. data/doc/files/lib/reports/ReportTableColumn_rb.html +106 -0
  229. data/doc/files/lib/reports/ReportTableElement_rb.html +122 -0
  230. data/doc/files/lib/reports/ReportTableLegend_rb.html +106 -0
  231. data/doc/files/lib/reports/ReportTableLine_rb.html +116 -0
  232. data/doc/files/lib/reports/ReportTable_rb.html +118 -0
  233. data/doc/files/lib/reports/Report_rb.html +126 -0
  234. data/doc/files/lib/reports/ResourceListRE_rb.html +122 -0
  235. data/doc/files/lib/reports/TaskListRE_rb.html +122 -0
  236. data/doc/files/lib/reports/TjpExportRE_rb.html +116 -0
  237. data/doc/files/lib/taskjuggler3_rb.html +276 -0
  238. data/doc/files/lib/tj3man_rb.html +189 -0
  239. data/doc/fr_class_index.html +285 -0
  240. data/doc/fr_file_index.html +223 -0
  241. data/doc/fr_method_index.html +1953 -0
  242. data/doc/index.html +21 -0
  243. data/doc/rdoc-style.css +299 -0
  244. data/examples/tutorial.tjp +361 -0
  245. data/gem_spec.rb +30 -0
  246. data/lib/Account.rb +50 -0
  247. data/lib/AccountScenario.rb +39 -0
  248. data/lib/Allocation.rb +102 -0
  249. data/lib/AppConfig.rb +134 -0
  250. data/lib/AttributeBase.rb +131 -0
  251. data/lib/AttributeDefinition.rb +47 -0
  252. data/lib/Attributes.rb +478 -0
  253. data/lib/BatchProcessor.rb +209 -0
  254. data/lib/Booking.rb +59 -0
  255. data/lib/Charge.rb +71 -0
  256. data/lib/ChargeSet.rb +126 -0
  257. data/lib/HTMLDocument.rb +59 -0
  258. data/lib/Interval.rb +127 -0
  259. data/lib/KeywordDocumentation.rb +560 -0
  260. data/lib/Limits.rb +219 -0
  261. data/lib/Log.rb +160 -0
  262. data/lib/LogicalExpression.rb +71 -0
  263. data/lib/LogicalFlag.rb +34 -0
  264. data/lib/LogicalFunction.rb +102 -0
  265. data/lib/LogicalOperation.rb +118 -0
  266. data/lib/MacroParser.rb +77 -0
  267. data/lib/MacroTable.rb +84 -0
  268. data/lib/Message.rb +56 -0
  269. data/lib/MessageHandler.rb +34 -0
  270. data/lib/Project.rb +662 -0
  271. data/lib/ProjectFileParser.rb +333 -0
  272. data/lib/PropertyList.rb +181 -0
  273. data/lib/PropertySet.rb +304 -0
  274. data/lib/PropertyTreeNode.rb +461 -0
  275. data/lib/Query.rb +227 -0
  276. data/lib/RealFormat.rb +73 -0
  277. data/lib/Resource.rb +42 -0
  278. data/lib/ResourceScenario.rb +511 -0
  279. data/lib/RichText.rb +147 -0
  280. data/lib/RichTextDocument.rb +139 -0
  281. data/lib/RichTextElement.rb +391 -0
  282. data/lib/RichTextParser.rb +66 -0
  283. data/lib/RichTextProtocolExample.rb +65 -0
  284. data/lib/RichTextProtocolHandler.rb +35 -0
  285. data/lib/RichTextScanner.rb +390 -0
  286. data/lib/RichTextSnip.rb +104 -0
  287. data/lib/RichTextSyntaxRules.rb +265 -0
  288. data/lib/Scenario.rb +27 -0
  289. data/lib/ScenarioData.rb +65 -0
  290. data/lib/Scoreboard.rb +141 -0
  291. data/lib/Shift.rb +48 -0
  292. data/lib/ShiftAssignments.rb +291 -0
  293. data/lib/ShiftScenario.rb +46 -0
  294. data/lib/SourceFileInfo.rb +37 -0
  295. data/lib/SyntaxReference.rb +284 -0
  296. data/lib/TOCEntry.rb +76 -0
  297. data/lib/TableColumnDefinition.rb +54 -0
  298. data/lib/TableOfContents.rb +46 -0
  299. data/lib/Task.rb +37 -0
  300. data/lib/TaskDependency.rb +39 -0
  301. data/lib/TaskJuggler.rb +84 -0
  302. data/lib/TaskScenario.rb +1622 -0
  303. data/lib/TextParser.rb +416 -0
  304. data/lib/TextParser/Pattern.rb +263 -0
  305. data/lib/TextParser/Rule.rb +171 -0
  306. data/lib/TextParser/StackElement.rb +45 -0
  307. data/lib/TextParser/TokenDoc.rb +38 -0
  308. data/lib/TextScanner.rb +682 -0
  309. data/lib/Tj3Config.rb +27 -0
  310. data/lib/TjException.rb +27 -0
  311. data/lib/TjTime.rb +395 -0
  312. data/lib/TjpExample.rb +119 -0
  313. data/lib/TjpSyntaxRules.rb +4022 -0
  314. data/lib/UTF8String.rb +100 -0
  315. data/lib/UserManual.rb +282 -0
  316. data/lib/WorkingHours.rb +323 -0
  317. data/lib/XMLDocument.rb +54 -0
  318. data/lib/XMLElement.rb +175 -0
  319. data/lib/reports/CSVFile.rb +146 -0
  320. data/lib/reports/ColumnTable.rb +66 -0
  321. data/lib/reports/GanttChart.rb +308 -0
  322. data/lib/reports/GanttContainer.rb +107 -0
  323. data/lib/reports/GanttHeader.rb +141 -0
  324. data/lib/reports/GanttHeaderScaleItem.rb +42 -0
  325. data/lib/reports/GanttLine.rb +329 -0
  326. data/lib/reports/GanttLoadStack.rb +113 -0
  327. data/lib/reports/GanttMilestone.rb +80 -0
  328. data/lib/reports/GanttRouter.rb +375 -0
  329. data/lib/reports/GanttTaskBar.rb +95 -0
  330. data/lib/reports/HTMLGraphics.rb +65 -0
  331. data/lib/reports/Report.rb +344 -0
  332. data/lib/reports/ReportElement.rb +427 -0
  333. data/lib/reports/ReportTable.rb +144 -0
  334. data/lib/reports/ReportTableCell.rb +142 -0
  335. data/lib/reports/ReportTableColumn.rb +82 -0
  336. data/lib/reports/ReportTableElement.rb +852 -0
  337. data/lib/reports/ReportTableLegend.rb +167 -0
  338. data/lib/reports/ReportTableLine.rb +87 -0
  339. data/lib/reports/ResourceListRE.rb +72 -0
  340. data/lib/reports/TaskListRE.rb +73 -0
  341. data/lib/reports/TjpExportRE.rb +394 -0
  342. data/lib/taskjuggler3.rb +106 -0
  343. data/lib/tj3man.rb +88 -0
  344. data/manual/Day_To_Day_Juggling +168 -0
  345. data/manual/Getting_Started +61 -0
  346. data/manual/How_To_Contribute +185 -0
  347. data/manual/Installation +68 -0
  348. data/manual/Intro +102 -0
  349. data/manual/Reporting_Bugs +26 -0
  350. data/manual/Rich_Text_Attributes +90 -0
  351. data/manual/TaskJuggler_2x_Migration +40 -0
  352. data/manual/Tutorial +579 -0
  353. data/manual/fdl +450 -0
  354. data/prj_cfg.rb +43 -0
  355. data/setup.rb +1585 -0
  356. data/tasks/csts.rake +72 -0
  357. data/tasks/gem.rake +14 -0
  358. data/tasks/manual.rake +10 -0
  359. data/tasks/missing.rake +21 -0
  360. data/tasks/rcov.rake +14 -0
  361. data/tasks/rdoc.rake +17 -0
  362. data/tasks/rexml_fix.rb +16 -0
  363. data/tasks/rexml_fix_19.rb +49 -0
  364. data/tasks/show.rake +21 -0
  365. data/tasks/stats.rake +25 -0
  366. data/tasks/test.rake +11 -0
  367. data/test/MessageChecker.rb +53 -0
  368. data/test/TestSuite/CSV-Reports/celltext-Reference.csv +14 -0
  369. data/test/TestSuite/CSV-Reports/celltext.tjp +7 -0
  370. data/test/TestSuite/CSV-Reports/genrefs +6 -0
  371. data/test/TestSuite/CSV-Reports/project-1.tji +57 -0
  372. data/test/TestSuite/CSV-Reports/resourcereport-Reference.csv +4 -0
  373. data/test/TestSuite/CSV-Reports/resourcereport.tjp +10 -0
  374. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks-Reference.csv +22 -0
  375. data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +11 -0
  376. data/test/TestSuite/CSV-Reports/sortByTree-Reference.csv +14 -0
  377. data/test/TestSuite/CSV-Reports/sortByTree.tjp +8 -0
  378. data/test/TestSuite/CSV-Reports/sortBy_duration.down-Reference.csv +14 -0
  379. data/test/TestSuite/CSV-Reports/sortBy_duration.down.tjp +10 -0
  380. data/test/TestSuite/CSV-Reports/sortBy_effort.up-Reference.csv +14 -0
  381. data/test/TestSuite/CSV-Reports/sortBy_effort.up.tjp +10 -0
  382. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down-Reference.csv +14 -0
  383. data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +10 -0
  384. data/test/TestSuite/CSV-Reports/taskreport-Reference.csv +14 -0
  385. data/test/TestSuite/CSV-Reports/taskreport.tjp +10 -0
  386. data/test/TestSuite/CSV-Reports/taskreport_with_resources-Reference.csv +24 -0
  387. data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +11 -0
  388. data/test/TestSuite/Scheduler/Correct/Allocate.tjp +86 -0
  389. data/test/TestSuite/Scheduler/Correct/AutomaticMilestones.tjp +63 -0
  390. data/test/TestSuite/Scheduler/Correct/Booking.tjp +161 -0
  391. data/test/TestSuite/Scheduler/Correct/Depends.tjp +50 -0
  392. data/test/TestSuite/Scheduler/Correct/Duration.tjp +34 -0
  393. data/test/TestSuite/Scheduler/Correct/InheritStartEnd.tjp +129 -0
  394. data/test/TestSuite/Scheduler/Correct/Limits.tjp +81 -0
  395. data/test/TestSuite/Scheduler/Correct/MultipleMandatories.tjp +43 -0
  396. data/test/TestSuite/Scheduler/Correct/Optimize-1.tjp +28 -0
  397. data/test/TestSuite/Scheduler/Correct/Optimize-2.tjp +33 -0
  398. data/test/TestSuite/Scheduler/Correct/Optimize-3.tjp +33 -0
  399. data/test/TestSuite/Scheduler/Correct/Optimize-4.tjp +34 -0
  400. data/test/TestSuite/Scheduler/Correct/Optimize-5.tjp +62 -0
  401. data/test/TestSuite/Scheduler/Correct/Precedes.tjp +50 -0
  402. data/test/TestSuite/Scheduler/Correct/Shift.tjp +102 -0
  403. data/test/TestSuite/Scheduler/Errors/account_no_leaf.tjp +13 -0
  404. data/test/TestSuite/Scheduler/Errors/booking_conflict.tjp +10 -0
  405. data/test/TestSuite/Scheduler/Errors/booking_no_duty.tjp +9 -0
  406. data/test/TestSuite/Scheduler/Errors/booking_on_vacation.tjp +9 -0
  407. data/test/TestSuite/Scheduler/Errors/container_booking.tjp +14 -0
  408. data/test/TestSuite/Scheduler/Errors/container_duration.tjp +11 -0
  409. data/test/TestSuite/Scheduler/Errors/effort_no_allocations.tjp +7 -0
  410. data/test/TestSuite/Scheduler/Errors/loop_detected_1.tjp +19 -0
  411. data/test/TestSuite/Scheduler/Errors/loop_detected_10.tjp +36 -0
  412. data/test/TestSuite/Scheduler/Errors/loop_detected_11.tjp +27 -0
  413. data/test/TestSuite/Scheduler/Errors/loop_detected_12.tjp +20 -0
  414. data/test/TestSuite/Scheduler/Errors/loop_detected_13.tjp +27 -0
  415. data/test/TestSuite/Scheduler/Errors/loop_detected_14.tjp +26 -0
  416. data/test/TestSuite/Scheduler/Errors/loop_detected_2.tjp +24 -0
  417. data/test/TestSuite/Scheduler/Errors/loop_detected_3.tjp +18 -0
  418. data/test/TestSuite/Scheduler/Errors/loop_detected_4.tjp +36 -0
  419. data/test/TestSuite/Scheduler/Errors/loop_detected_5.tjp +37 -0
  420. data/test/TestSuite/Scheduler/Errors/loop_detected_6.tjp +35 -0
  421. data/test/TestSuite/Scheduler/Errors/loop_detected_7.tjp +46 -0
  422. data/test/TestSuite/Scheduler/Errors/loop_detected_8.tjp +51 -0
  423. data/test/TestSuite/Scheduler/Errors/loop_detected_9.tjp +20 -0
  424. data/test/TestSuite/Scheduler/Errors/maxend.tjp +8 -0
  425. data/test/TestSuite/Scheduler/Errors/maxstart.tjp +8 -0
  426. data/test/TestSuite/Scheduler/Errors/milestone_booking.tjp +10 -0
  427. data/test/TestSuite/Scheduler/Errors/milestone_duration.tjp +8 -0
  428. data/test/TestSuite/Scheduler/Errors/milestone_start_end.tjp +8 -0
  429. data/test/TestSuite/Scheduler/Errors/minend.tjp +8 -0
  430. data/test/TestSuite/Scheduler/Errors/minstart.tjp +8 -0
  431. data/test/TestSuite/Scheduler/Errors/multiple_durations.tjp +11 -0
  432. data/test/TestSuite/Scheduler/Errors/no_tasks.tjp +6 -0
  433. data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +8 -0
  434. data/test/TestSuite/Scheduler/Errors/task_depend_child.tjp +10 -0
  435. data/test/TestSuite/Scheduler/Errors/task_depend_multi.tjp +13 -0
  436. data/test/TestSuite/Scheduler/Errors/task_depend_parent.tjp +11 -0
  437. data/test/TestSuite/Scheduler/Errors/task_depend_self.tjp +10 -0
  438. data/test/TestSuite/Scheduler/Errors/task_depend_unknown.tjp +10 -0
  439. data/test/TestSuite/Scheduler/Errors/task_overspecified_1.tjp +9 -0
  440. data/test/TestSuite/Scheduler/Errors/task_overspecified_2.tjp +14 -0
  441. data/test/TestSuite/Scheduler/Errors/task_overspecified_3.tjp +14 -0
  442. data/test/TestSuite/Scheduler/Errors/task_underspecified_1.tjp +8 -0
  443. data/test/TestSuite/Scheduler/Errors/task_underspecified_2.tjp +8 -0
  444. data/test/TestSuite/Scheduler/Errors/task_underspecified_3.tjp +9 -0
  445. data/test/TestSuite/Syntax/Correct/Account.tjp +53 -0
  446. data/test/TestSuite/Syntax/Correct/Allocate-1.tjp +24 -0
  447. data/test/TestSuite/Syntax/Correct/Alternative.tjp +13 -0
  448. data/test/TestSuite/Syntax/Correct/AutoMacros.tjp +14 -0
  449. data/test/TestSuite/Syntax/Correct/Booking.tjp +26 -0
  450. data/test/TestSuite/Syntax/Correct/Caption.tjp +33 -0
  451. data/test/TestSuite/Syntax/Correct/Celltext.tjp +28 -0
  452. data/test/TestSuite/Syntax/Correct/Comments.tjp +29 -0
  453. data/test/TestSuite/Syntax/Correct/Complete.tjp +16 -0
  454. data/test/TestSuite/Syntax/Correct/CompletedWork.tji +20 -0
  455. data/test/TestSuite/Syntax/Correct/CriticalPath.tjp +31 -0
  456. data/test/TestSuite/Syntax/Correct/Currencyformat.tjp +12 -0
  457. data/test/TestSuite/Syntax/Correct/CustomAttributes.tjp +14 -0
  458. data/test/TestSuite/Syntax/Correct/Depends1.tjp +22 -0
  459. data/test/TestSuite/Syntax/Correct/Durations.tjp +29 -0
  460. data/test/TestSuite/Syntax/Correct/Efficiency.tjp +19 -0
  461. data/test/TestSuite/Syntax/Correct/Export.tjp +40 -0
  462. data/test/TestSuite/Syntax/Correct/Flags.tjp +32 -0
  463. data/test/TestSuite/Syntax/Correct/Freeze.tjp +28 -0
  464. data/test/TestSuite/Syntax/Correct/Gap.tjp +15 -0
  465. data/test/TestSuite/Syntax/Correct/HtmlTaskReport.tjp +33 -0
  466. data/test/TestSuite/Syntax/Correct/Limits-1.tjp +71 -0
  467. data/test/TestSuite/Syntax/Correct/LoadUnits.tjp +31 -0
  468. data/test/TestSuite/Syntax/Correct/Macro-1.tjp +19 -0
  469. data/test/TestSuite/Syntax/Correct/Mandatory.tjp +17 -0
  470. data/test/TestSuite/Syntax/Correct/Milestone.tjp +12 -0
  471. data/test/TestSuite/Syntax/Correct/MinMax.tjp +17 -0
  472. data/test/TestSuite/Syntax/Correct/Numberformat.tjp +12 -0
  473. data/test/TestSuite/Syntax/Correct/Period.tjp +16 -0
  474. data/test/TestSuite/Syntax/Correct/Persistent.tjp +11 -0
  475. data/test/TestSuite/Syntax/Correct/Precedes1.tjp +17 -0
  476. data/test/TestSuite/Syntax/Correct/Priority.tjp +30 -0
  477. data/test/TestSuite/Syntax/Correct/Project.tjp +21 -0
  478. data/test/TestSuite/Syntax/Correct/ProjectIDs.tjp +23 -0
  479. data/test/TestSuite/Syntax/Correct/RawHTML.tjp +29 -0
  480. data/test/TestSuite/Syntax/Correct/Reports.tjp +54 -0
  481. data/test/TestSuite/Syntax/Correct/Resource.tjp +20 -0
  482. data/test/TestSuite/Syntax/Correct/Responsible.tjp +16 -0
  483. data/test/TestSuite/Syntax/Correct/Scenario.tjp +15 -0
  484. data/test/TestSuite/Syntax/Correct/Scheduling.tjp +26 -0
  485. data/test/TestSuite/Syntax/Correct/Select.tjp +27 -0
  486. data/test/TestSuite/Syntax/Correct/Shift.tjp +55 -0
  487. data/test/TestSuite/Syntax/Correct/Simple.tjp +25 -0
  488. data/test/TestSuite/Syntax/Correct/String.tjp +12 -0
  489. data/test/TestSuite/Syntax/Correct/Supplement.tjp +24 -0
  490. data/test/TestSuite/Syntax/Correct/TaskRoot.tjp +34 -0
  491. data/test/TestSuite/Syntax/Correct/TimeFrame.tjp +19 -0
  492. data/test/TestSuite/Syntax/Correct/Timezone.tjp +8 -0
  493. data/test/TestSuite/Syntax/Correct/Vacation.tjp +33 -0
  494. data/test/TestSuite/Syntax/Correct/csvtest +16 -0
  495. data/test/TestSuite/Syntax/Correct/manual2example.rb +24 -0
  496. data/test/TestSuite/Syntax/Correct/tutorial.tjp +485 -0
  497. data/test/TestSuite/Syntax/Errors/bad_include.tjp +11 -0
  498. data/test/TestSuite/Syntax/Errors/booking_group.tjp +14 -0
  499. data/test/TestSuite/Syntax/Errors/booking_milestone.tjp +13 -0
  500. data/test/TestSuite/Syntax/Errors/booking_no_leaf.tjp +13 -0
  501. data/test/TestSuite/Syntax/Errors/chargeset.tjp +14 -0
  502. data/test/TestSuite/Syntax/Errors/chargeset_master.tjp +15 -0
  503. data/test/TestSuite/Syntax/Errors/container_attribute.tjp +13 -0
  504. data/test/TestSuite/Syntax/Errors/cost_acct_no_top.tjp +24 -0
  505. data/test/TestSuite/Syntax/Errors/cost_rev_same.tjp +24 -0
  506. data/test/TestSuite/Syntax/Errors/date_in_range.tjp +7 -0
  507. data/test/TestSuite/Syntax/Errors/effort_zero.tjp +8 -0
  508. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -0
  509. data/test/TestSuite/Syntax/Errors/export_bad_extn.tjp +9 -0
  510. data/test/TestSuite/Syntax/Errors/extend_id_cap.tjp +7 -0
  511. data/test/TestSuite/Syntax/Errors/interval_end_in_range.tjp +7 -0
  512. data/test/TestSuite/Syntax/Errors/interval_start_in_range.tjp +7 -0
  513. data/test/TestSuite/Syntax/Errors/leaf_resource_id_expected.tjp +12 -0
  514. data/test/TestSuite/Syntax/Errors/misaligned_date.tjp +7 -0
  515. data/test/TestSuite/Syntax/Errors/no_csv_suffix.tjp +10 -0
  516. data/test/TestSuite/Syntax/Errors/no_html_suffix.tjp +10 -0
  517. data/test/TestSuite/Syntax/Errors/operand_attribute.tjp +11 -0
  518. data/test/TestSuite/Syntax/Errors/operand_unkn_flag.tjp +11 -0
  519. data/test/TestSuite/Syntax/Errors/operand_unkn_scen.tjp +11 -0
  520. data/test/TestSuite/Syntax/Errors/overtime_range.tjp +13 -0
  521. data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +8 -0
  522. data/test/TestSuite/Syntax/Errors/purge_unknown_id.tjp +8 -0
  523. data/test/TestSuite/Syntax/Errors/report_end.tjp +10 -0
  524. data/test/TestSuite/Syntax/Errors/report_redifinition.tjp +10 -0
  525. data/test/TestSuite/Syntax/Errors/report_start.tjp +10 -0
  526. data/test/TestSuite/Syntax/Errors/resource_exists.tjp +7 -0
  527. data/test/TestSuite/Syntax/Errors/resource_id_expected.tjp +8 -0
  528. data/test/TestSuite/Syntax/Errors/rev_acct_no_top.tjp +24 -0
  529. data/test/TestSuite/Syntax/Errors/scenario_exists.tjp +7 -0
  530. data/test/TestSuite/Syntax/Errors/shift_assignment_overlap.tjp +15 -0
  531. data/test/TestSuite/Syntax/Errors/shift_exists.tjp +7 -0
  532. data/test/TestSuite/Syntax/Errors/shift_id_expected.tjp +7 -0
  533. data/test/TestSuite/Syntax/Errors/sloppy_range.tjp +13 -0
  534. data/test/TestSuite/Syntax/Errors/sort_direction.tjp +11 -0
  535. data/test/TestSuite/Syntax/Errors/sort_unknown_scen.tjp +11 -0
  536. data/test/TestSuite/Syntax/Errors/sorting_crit_exptd1.tjp +11 -0
  537. data/test/TestSuite/Syntax/Errors/sorting_crit_exptd2.tjp +11 -0
  538. data/test/TestSuite/Syntax/Errors/sorting_wbs.tjp +11 -0
  539. data/test/TestSuite/Syntax/Errors/start_before_end1.tjp +7 -0
  540. data/test/TestSuite/Syntax/Errors/start_before_end2.tjp +6 -0
  541. data/test/TestSuite/Syntax/Errors/task_complete.tjp +8 -0
  542. data/test/TestSuite/Syntax/Errors/task_exists.tjp +7 -0
  543. data/test/TestSuite/Syntax/Errors/task_priority.tjp +8 -0
  544. data/test/TestSuite/Syntax/Errors/task_without_chargeset.tjp +9 -0
  545. data/test/TestSuite/Syntax/Errors/time_interval.tjp +12 -0
  546. data/test/TestSuite/Syntax/Errors/too_many_bangs.tjp +10 -0
  547. data/test/TestSuite/Syntax/Errors/undecl_flag.tjp +6 -0
  548. data/test/TestSuite/Syntax/Errors/unknown_projectid.tjp +7 -0
  549. data/test/TestSuite/Syntax/Errors/unknown_scenario_id.tjp +6 -0
  550. data/test/TestSuite/Syntax/Errors/unknown_scenario_idx.tjp +11 -0
  551. data/test/TestSuite/Syntax/Errors/unknown_task.tjp +10 -0
  552. data/test/all.rb +31 -0
  553. data/test/test_BatchProcessor.rb +54 -0
  554. data/test/test_CSV-Reports.rb +101 -0
  555. data/test/test_Limits.rb +104 -0
  556. data/test/test_LogicalExpression.rb +110 -0
  557. data/test/test_MacroTable.rb +51 -0
  558. data/test/test_Project.rb +57 -0
  559. data/test/test_PropertySet.rb +71 -0
  560. data/test/test_Query.rb +83 -0
  561. data/test/test_RealFormat.rb +83 -0
  562. data/test/test_RichText.rb +869 -0
  563. data/test/test_Scheduler.rb +42 -0
  564. data/test/test_ShiftAssignments.rb +77 -0
  565. data/test/test_Syntax.rb +41 -0
  566. data/test/test_TextScanner.rb +95 -0
  567. data/test/test_TjTime.rb +114 -0
  568. data/test/test_TjpExample.rb +169 -0
  569. data/test/test_UTF8String.rb +84 -0
  570. data/test/test_WorkingHours.rb +56 -0
  571. metadata +649 -0
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = ReportTableCell.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ class TaskJuggler
14
+
15
+ # This class models the output format independent version of a cell in a
16
+ # ReportTableElement. It belongs to a certain ReportTableLine and
17
+ # ReportTableColumn. Normally a cell contains text on a colored background.
18
+ # By help of the @special variable it can alternatively contain any object the
19
+ # provides the necessary output methods such as to_html.
20
+ class ReportTableCell
21
+
22
+ attr_reader :line
23
+ attr_accessor :data, :text, :url, :category, :hidden, :alignment,
24
+ :padding, :indent, :fontSize, :fontColor, :bold, :width,
25
+ :rows, :columns, :special
26
+
27
+ # Create the ReportTableCell object and initialize the attributes to some
28
+ # default values. _line_ is the ReportTableLine this cell belongs to. _text_
29
+ # is the text that should appear in the cell. _headerCell_ is a flag that
30
+ # must be true only for table header cells.
31
+ def initialize(line, text = '', headerCell = false)
32
+ @line = line
33
+ @line.addCell(self) if line
34
+
35
+ @headerCell = headerCell
36
+ # The printable form of the cell content
37
+ @text = text
38
+ # A URL that is associated with the content of the cell.
39
+ @url = nil
40
+ # The original data of the cell content (optional, nil if not provided)
41
+ @data = nil
42
+ @category = nil
43
+ @hidden = false
44
+ # How to horizontally align the cell
45
+ @alignment = :center
46
+ # Horizontal padding between frame and cell content
47
+ @padding = 3
48
+ # Whether or not to indent the cell. If not nil, it is a Fixnum
49
+ # indicating the indentation level.
50
+ @indent = nil
51
+ @fontSize = nil
52
+ @fontColor = 0x000000
53
+ @bold = false
54
+ @width = nil
55
+ @rows = 1
56
+ @columns = 1
57
+ # Ignore everything and use this reference to generate the output.
58
+ @special = nil
59
+ end
60
+
61
+ # Return true if two cells are similar enough so that they can be merged in
62
+ # the report to a single, wider cell. _c_ is the cell to compare this cell
63
+ # with.
64
+ def ==(c)
65
+ @text == c.text &&
66
+ @alignment == c.alignment &&
67
+ @padding == c.padding &&
68
+ @indent == c.indent &&
69
+ @category == c.category
70
+ end
71
+
72
+ # Turn the abstract cell representation into an HTML element tree.
73
+ def to_html
74
+ return nil if @hidden
75
+ return @special.to_html if @special
76
+
77
+ # Determine cell attributes
78
+ attribs = { }
79
+ attribs['rowspan'] = "#{@rows}" if @rows > 1
80
+ attribs['colspan'] = "#{@columns}" if @columns > 1
81
+ attribs['class'] = @category ? @category : 'tabcell'
82
+ cell = XMLElement.new('td', attribs)
83
+
84
+ # Determine cell style
85
+ alignSymbols = [ :left, :center, :right ]
86
+ aligns = %w( left center right)
87
+ style = "text-align:#{aligns[alignSymbols.index(@alignment)]}; "
88
+ if @indent && @alignment != :center
89
+ if @alignment == :left
90
+ style += "padding-left:#{@padding + @indent * 8}px; "
91
+ style += "padding-right:#{@padding}px; " unless @padding == 3
92
+ elsif @alignment == :right
93
+ style += "padding-left:#{@padding}px; " unless @padding == 3
94
+ style += "padding-right:#{@padding +
95
+ (@line.table.maxIndent - @indent) * 8}px; "
96
+ end
97
+ elsif @padding != 3
98
+ style += "padding-left:#{@padding}px; padding-right:#{@padding}px; "
99
+ end
100
+ unless @text.is_a?(TaskJuggler::RichText)
101
+ style += 'font-weight:bold; ' if @bold
102
+ style += "font-size: #{@fontSize}px; " if fontSize
103
+ end
104
+ unless @fontColor == 0
105
+ style += "color:#{'#%06X' % @fontColor}; "
106
+ end
107
+ style += "width: #{@width}px; " if @width
108
+ if @text.is_a?(TaskJuggler::RichText) && @line && @line.table.equiLines
109
+ style += "height:#{@line.height - 3}px; "
110
+ end
111
+ cell << (div = XMLElement.new('div',
112
+ 'class' => @category ? 'celldiv' : 'headercelldiv', 'style' => style))
113
+
114
+ if url
115
+ div << (a = XMLElement.new('a', 'href' => @url))
116
+ a << XMLText.new(@text.is_a?(TaskJuggler::RichText) ? @text.to_s : text)
117
+ else
118
+ div << (@text.is_a?(TaskJuggler::RichText) ?
119
+ @text.to_html : XMLText.new(@text))
120
+ end
121
+
122
+ cell
123
+ end
124
+
125
+ # Add the text content of the cell to an Array of Arrays form of the table.
126
+ def to_csv(csv)
127
+ # We only support left indentation in CSV files as the spaces for right
128
+ # indentation will be disregarded by most applications.
129
+ indent = @indent && @alignment == :left ? ' ' * @indent : ''
130
+ if @special
131
+ csv[-1] << @special.to_csv
132
+ elsif @data && @data.is_a?(String)
133
+ csv[-1] << indent + @data
134
+ elsif @text
135
+ csv[-1] << indent + @text
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = ReportTableColumn.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ class TaskJuggler
14
+
15
+ # The ReportTableColumn class models the output format independend column of a
16
+ # ReportTable. It usually just contains the table header description. The
17
+ # table header comprises of one or two lines per column. So each column header
18
+ # consists of 2 cells. @cell1 is the top cell and must be present. @cell2 is
19
+ # the optional bottom cell. If @cell2 is hidden, @cell1 takes all the vertical
20
+ # space.
21
+ #
22
+ # For some columns, the table does not contain the usual grid lines but
23
+ # another abstract object that responds to the usual generator methods such as
24
+ # to_html(). In such a case, @cell1 references the embedded object via its
25
+ # special variable. The embedded object then replaced the complete column
26
+ # content.
27
+ class ReportTableColumn
28
+
29
+ attr_reader :definition, :cell1, :cell2
30
+ attr_accessor :scrollbar
31
+
32
+ # Create a new column. _table_ is a reference to the ReportTable this column
33
+ # belongs to. _definition_ is the TableColumnDefinition of the column from
34
+ # the project definition. _title_ is the text that is used for the column
35
+ # header.
36
+ def initialize(table, definition, title)
37
+ @table = table
38
+ # Register this new column with the ReportTable.
39
+ @table.addColumn(self)
40
+ @definition = definition
41
+ # Register this new column with the TableColumnDefinition.
42
+ definition.column = self if definition
43
+
44
+ # Create the 2 cells of the header.
45
+ @cell1 = ReportTableCell.new(nil, title, true)
46
+ @cell1.padding = 5
47
+ @cell2 = ReportTableCell.new(nil, '', true)
48
+ # Header text is always bold.
49
+ @cell1.bold = @cell2.bold = true
50
+ # This variable is set to true if the column requires a scrollbar later
51
+ # on.
52
+ @scrollbar = false
53
+ end
54
+
55
+ # Return the mininum required width for the column.
56
+ def minWidth
57
+ width = @cell1.width
58
+ width = @cell2.width if width.nil? || @cell2.width > width
59
+ width
60
+ end
61
+
62
+ # Convert the abstract representation into HTML elements.
63
+ def to_html(row)
64
+ if row == 1
65
+ @cell1.to_html
66
+ else
67
+ @cell2.to_html
68
+ end
69
+ end
70
+
71
+ # Put the abstract representation into an Array. _csv_ is an Array of Arrays
72
+ # of Strings. We have an Array with Strings for every cell. The outer Array
73
+ # holds the Arrays representing the lines.
74
+ def to_csv(csv)
75
+ # For CSV reports we can only include the first header line.
76
+ @cell1.to_csv(csv)
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
@@ -0,0 +1,852 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = ReportTableElement.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009 by Chris Schlaeger <cs@kde.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ require 'reports/GanttChart'
14
+ require 'reports/ReportTableLegend'
15
+ require 'reports/ColumnTable'
16
+ require 'Query'
17
+
18
+ class TaskJuggler
19
+
20
+ # This is base class for all types of tabular report elements. All tabular
21
+ # report elements are converted to an abstract (output independent)
22
+ # intermediate form first, before the are turned into the requested output
23
+ # format.
24
+ class ReportTableElement < ReportElement
25
+
26
+ attr_reader :legend
27
+
28
+ # Generate a new ReportTableElement object.
29
+ def initialize(report)
30
+ super
31
+
32
+ # Reference to the intermediate representation.
33
+ @table = nil
34
+
35
+ @legend = ReportTableLegend.new
36
+ end
37
+
38
+ # This is an abstract member that all sub classes must re-implement. It may
39
+ # or may not do something though.
40
+ def generateIntermediateFormat
41
+ raise 'This function must be overriden by derived classes.'
42
+ end
43
+
44
+ # Turn the ReportTableElement into an equivalent HTML element tree.
45
+ def to_html
46
+ html = []
47
+
48
+ # Make sure we have some margins around the report.
49
+ html << (frame = XMLElement.new('div',
50
+ 'style' => 'margin: 35px 5% 25px 5%; '))
51
+
52
+ if @prolog
53
+ @prolog.sectionNumbers = false
54
+ frame << @prolog.to_html
55
+ end
56
+
57
+ frame << (table = XMLElement.new('table', 'summary' => 'Report Table',
58
+ 'cellspacing' => '2', 'border' => '0',
59
+ 'cellpadding' => '0', 'align' => 'center',
60
+ 'class' => 'tabback'))
61
+
62
+ # The headline is put in a sub-table to appear bigger.
63
+ if @headline
64
+ table << (thead = XMLElement.new('thead'))
65
+ thead << (tr = XMLElement.new('tr'))
66
+ tr << (td = XMLElement.new('td'))
67
+ td << (table1 = XMLElement.new('table', 'summary' => 'headline',
68
+ 'cellspacing' => '1', 'border' => '0',
69
+ 'cellpadding' => '5',
70
+ 'align' => 'center', 'width' => '100%'))
71
+ table1 << (tr1 = XMLElement.new('tr'))
72
+ tr1 << (td1 = XMLElement.new('td', 'align' => 'center',
73
+ 'style' => 'font-size:16px; ' +
74
+ 'font-weight:bold',
75
+ 'class' => 'tabfront'))
76
+ td1 << XMLNamedText.new(@headline, 'p')
77
+ end
78
+
79
+ # Now generate the actual table with the data.
80
+ table << (tbody = XMLElement.new('tbody'))
81
+ tbody << (tr = XMLElement.new('tr'))
82
+ tr << (td = XMLElement.new('td'))
83
+ td << @table.to_html
84
+
85
+ # Embedd the caption as RichText into the table footer.
86
+ if @caption
87
+ tbody << (tr = XMLElement.new('tr'))
88
+ tr << (td = XMLElement.new('td', 'class' => 'tabback'))
89
+ td << (div = XMLElement.new('div', 'class' => 'caption',
90
+ 'style' => 'margin:1px'))
91
+ @caption.sectionNumbers = false
92
+ div << @caption.to_html
93
+ end
94
+
95
+ # A sub-table with the legend.
96
+ tbody << (tr = XMLElement.new('tr', 'style' => 'font-size:10px;'))
97
+ tr << (td = XMLElement.new('td', 'style' =>
98
+ 'padding-left:1px; padding-right:1px;'))
99
+ td << @legend.to_html
100
+
101
+ # The footer with some administrative information.
102
+ tbody << (tr = XMLElement.new('tr', 'style' => 'font-size:9px'))
103
+ tr << (td = XMLElement.new('td', 'class' => 'tabfooter'))
104
+ td << XMLText.new(@project['copyright'] + " - ") if @project['copyright']
105
+ td << XMLText.new("Project: #{@project['name']} " +
106
+ "Version: #{@project['version']} - " +
107
+ "Created on #{TjTime.now.to_s("%Y-%m-%d %H:%M:%S")} " +
108
+ "with ")
109
+ td << XMLNamedText.new("#{AppConfig.packageName}", 'a',
110
+ 'href' => "#{AppConfig.contact}")
111
+ td << XMLText.new(" v#{AppConfig.version}")
112
+
113
+ if @epilog
114
+ @epilog.sectionNumbers = false
115
+ frame << @epilog.to_html
116
+ end
117
+
118
+ html
119
+ end
120
+
121
+ # Convert the ReportElement into an Array of Arrays. It has one Array for
122
+ # each line. The nested Arrays have one String for each column.
123
+ def to_csv
124
+ @table.to_csv
125
+ end
126
+
127
+ protected
128
+
129
+ # Generates cells for the table header. _columnDef_ is the
130
+ # TableColumnDefinition object that describes the column. Based on the id of
131
+ # the column different actions need to be taken to generate the header text.
132
+ def generateHeaderCell(columnDef)
133
+ case columnDef.id
134
+ when 'chart'
135
+ # For the 'chart' column we generate a GanttChart object. The sizes are
136
+ # set so that the lines of the Gantt chart line up with the lines of the
137
+ # table.
138
+ gantt = GanttChart.new(@now, @weekStartsMonday, self)
139
+ gantt.generateByScale(@start, @end, columnDef.scale)
140
+ # The header consists of 2 lines separated by a 1 pixel boundary.
141
+ gantt.header.height = @table.headerLineHeight * 2 + 1
142
+ # The maximum width of the chart. In case it needs more space, a
143
+ # scrollbar is shown or the chart gets truncated depending on the output
144
+ # format.
145
+ gantt.viewWidth = columnDef.width
146
+ column = ReportTableColumn.new(@table, columnDef, '')
147
+ column.cell1.special = gantt
148
+ column.cell2.hidden = true
149
+ column.scrollbar = gantt.hasScrollbar?
150
+ @table.equiLines = true
151
+ when 'hourly'
152
+ genCalChartHeader(columnDef, @start.midnight, :sameTimeNextHour,
153
+ :weekdayAndDate, :hour)
154
+ when 'daily'
155
+ genCalChartHeader(columnDef, @start.midnight, :sameTimeNextDay,
156
+ :shortMonthName, :day)
157
+ when 'weekly'
158
+ genCalChartHeader(columnDef, @start.beginOfWeek(@weekStartsMonday),
159
+ :sameTimeNextWeek, :shortMonthName, :day)
160
+ when 'monthly'
161
+ genCalChartHeader(columnDef, @start.beginOfMonth, :sameTimeNextMonth,
162
+ :year, :shortMonthName)
163
+ when 'quarterly'
164
+ genCalChartHeader(columnDef, @start.beginOfQuarter,
165
+ :sameTimeNextQuarter, :year, :quarterName)
166
+ when 'yearly'
167
+ genCalChartHeader(columnDef, @start.beginOfYear, :sameTimeNextYear,
168
+ nil, :year)
169
+ else
170
+ # This is the most common case. It does not need any special treatment.
171
+ # We just set the pre-defined or user-defined column title in the first
172
+ # row of the header. The 2nd row is not visible.
173
+ column = ReportTableColumn.new(@table, columnDef, columnDef.title)
174
+ column.cell1.rows = 2
175
+ column.cell2.hidden = true
176
+ end
177
+ end
178
+
179
+ # Generate a ReportTableLine for each of the tasks in _taskList_. In case
180
+ # _resourceList_ is not nil, it also generates the nested resource lines for
181
+ # each resource that is assigned to the particular task. If _scopeLine_
182
+ # is defined, the generated task lines will be within the scope this resource
183
+ # line.
184
+ def generateTaskList(taskList, resourceList, scopeLine)
185
+ queryAttrs = { 'scopeProperty' => scopeLine ? scopeLine.property : nil,
186
+ 'loadUnit' => @loadUnit,
187
+ 'numberFormat' => @numberFormat,
188
+ 'currencyFormat' => @currencyFormat,
189
+ 'start' => @start, 'end' => @end,
190
+ 'costAccount' => @costAccount,
191
+ 'revenueAccount' => @revenueAccount }
192
+ taskList.query = Query.new(queryAttrs)
193
+ taskList.sort!
194
+
195
+ # The primary line counter. Is not used for enclosed lines.
196
+ no = 0
197
+ # The scope line counter. It's reset for each new scope.
198
+ lineNo = scopeLine ? scopeLine.lineNo : 0
199
+ # Init the variable to get a larger scope
200
+ line = nil
201
+ taskList.each do |task|
202
+ no += 1
203
+ Log.activity if lineNo % 10 == 0
204
+ lineNo += 1
205
+ @scenarios.each do |scenarioIdx|
206
+ # Generate line for each task.
207
+ line = ReportTableLine.new(@table, task, scopeLine)
208
+
209
+ line.no = no unless scopeLine
210
+ line.lineNo = lineNo
211
+ line.subLineNo = @table.lines
212
+ setIndent(line, @taskRoot, taskList.treeMode?)
213
+
214
+ # Generate a cell for each column in this line.
215
+ @columns.each do |columnDef|
216
+ next unless generateTableCell(line, task, columnDef, scenarioIdx)
217
+ end
218
+ end
219
+
220
+ if resourceList
221
+ # If we have a resourceList we generate nested lines for each of the
222
+ # resources that are assigned to this task and pass the user-defined
223
+ # filter.
224
+ resourceList.setSorting(@sortResources)
225
+ assignedResourceList = filterResourceList(resourceList, task,
226
+ @hideResource, @rollupResource)
227
+ assignedResourceList.sort!
228
+ lineNo = generateResourceList(assignedResourceList, nil, line)
229
+ end
230
+ end
231
+ lineNo
232
+ end
233
+
234
+ # Generate a ReportTableLine for each of the resources in _resourceList_. In
235
+ # case _taskList_ is not nil, it also generates the nested task lines for
236
+ # each task that the resource is assigned to. If _scopeLine_ is defined, the
237
+ # generated resource lines will be within the scope this task line.
238
+ def generateResourceList(resourceList, taskList, scopeLine)
239
+ queryAttrs = { 'scopeProperty' => scopeLine ? scopeLine.property : nil,
240
+ 'loadUnit' => @loadUnit,
241
+ 'numberFormat' => @numberFormat,
242
+ 'currencyFormat' => @currencyFormat,
243
+ 'start' => @start, 'end' => @end,
244
+ 'costAccount' => @costAccount,
245
+ 'revenueAccount' => @revenueAccount }
246
+ resourceList.query = Query.new(queryAttrs)
247
+ resourceList.sort!
248
+
249
+ # The primary line counter. Is not used for enclosed lines.
250
+ no = 0
251
+ # The scope line counter. It's reset for each new scope.
252
+ lineNo = scopeLine ? scopeLine.lineNo : 0
253
+ # Init the variable to get a larger scope
254
+ line = nil
255
+ resourceList.each do |resource|
256
+ no += 1
257
+ Log.activity if lineNo % 10 == 0
258
+ lineNo += 1
259
+ @scenarios.each do |scenarioIdx|
260
+ # Generate line for each resource.
261
+ line = ReportTableLine.new(@table, resource, scopeLine)
262
+
263
+ line.no = no unless scopeLine
264
+ line.lineNo = lineNo
265
+ line.subLineNo = @table.lines
266
+ setIndent(line, @resourceRoot, resourceList.treeMode?)
267
+
268
+ # Generate a cell for each column in this line.
269
+ @columns.each do |column|
270
+ next unless generateTableCell(line, resource, column, scenarioIdx)
271
+ end
272
+ end
273
+
274
+ if taskList
275
+ # If we have a taskList we generate nested lines for each of the
276
+ # tasks that the resource is assigned to and pass the user-defined
277
+ # filter.
278
+ taskList.setSorting(@sortTasks)
279
+ assignedTaskList = filterTaskList(taskList, resource,
280
+ @hideTask, @rollupTask)
281
+ assignedTaskList.sort!
282
+ lineNo = generateTaskList(assignedTaskList, nil, line)
283
+ end
284
+ end
285
+ lineNo
286
+ end
287
+
288
+ private
289
+
290
+ # Generate the header data for calendar tables. They consists of columns for
291
+ # each hour, day, week, etc. _columnDef_ is the definition of the columns.
292
+ # _t_ is the start time for the calendar. _sameTimeNextFunc_ is a function
293
+ # that is called to advance _t_ to the next table column interval.
294
+ # _name1Func_ and _name2Func_ are functions that return the upper and lower
295
+ # title of the particular column.
296
+ def genCalChartHeader(columnDef, t, sameTimeNextFunc, name1Func, name2Func)
297
+ tableColumn = ReportTableColumn.new(@table, columnDef, '')
298
+
299
+ # Calendar chars only work when all lines have same height.
300
+ @table.equiLines = true
301
+
302
+ # Embedded tables have unpredictable width. So we always need to make room
303
+ # for a potential scrollbar.
304
+ tableColumn.scrollbar = true
305
+
306
+ # Create the table that is embedded in this column.
307
+ tableColumn.cell1.special = table = ColumnTable.new
308
+ table.equiLines = true
309
+ tableColumn.cell2.hidden = true
310
+ table.maxWidth = columnDef.width
311
+
312
+ # Iterate over the report interval until we hit the end date. The
313
+ # iteration is done with 2 nested loops. The outer loops generates the
314
+ # intervals for the upper (larger) scale. The inner loop generates the
315
+ # lower (smaller) scale.
316
+ while t < @end
317
+ cellsInInterval = 0
318
+ # Label for upper scale. The yearly calendar only has a lower scale.
319
+ currentInterval = t.send(name1Func) if name1Func
320
+ firstColumn = nil
321
+ # The innter loops terminates when the label for the upper scale has
322
+ # changed to the next scale cell.
323
+ while t < @end && (name1Func.nil? || t.send(name1Func) == currentInterval)
324
+ # call TjTime::sameTimeNext... function to get the end of the column.
325
+ nextT = t.send(sameTimeNextFunc)
326
+ iv = Interval.new(t, nextT)
327
+ # Create the new column object.
328
+ column = ReportTableColumn.new(table, nil, '')
329
+ # Store the date of the column in the original form.
330
+ column.cell1.data = t.to_s(@timeFormat)
331
+ # The upper scale cells will be merged into one large cell that spans
332
+ # all lower scale cells that belong to this upper cell.
333
+ if firstColumn.nil?
334
+ firstColumn = column
335
+ column.cell1.text = currentInterval.to_s
336
+ else
337
+ column.cell1.hidden = true
338
+ end
339
+ column.cell2.text = t.send(name2Func).to_s
340
+ # TODO: The width should be taken from some data structure.
341
+ column.cell2.width = 20
342
+ # Off-duty cells will have a different color than working time cells.
343
+ unless @project.isWorkingTime(iv)
344
+ column.cell2.category = 'tabhead_offduty'
345
+ end
346
+ cellsInInterval += 1
347
+
348
+ t = nextT
349
+ end
350
+ # The the first upper scale cell how many trailing hidden cells are
351
+ # following.
352
+ firstColumn.cell1.columns = cellsInInterval
353
+ end
354
+ end
355
+
356
+ # Generate a cell of the table. _line_ is the ReportTableLine that this cell
357
+ # should belong to. _property_ is the PropertyTreeNode that is reported in
358
+ # this _line_. _columnDef_ is the TableColumnDefinition of the column this
359
+ # cell should belong to. _scenarioIdx_ is the index of the scenario that is
360
+ # reported in this _line_.
361
+ #
362
+ # There are 4 kinds of cells. The most simple one is the standard cell. It
363
+ # literally reports the value of a property attribute. Calculated cells are
364
+ # more flexible. They contain computed values. The values are computed at
365
+ # cell generation time. The calendar columns consist of multiple sub
366
+ # columns. In such a case many cells are generated with a single call of
367
+ # this method. The last kind of cell is actually not a cell. It just
368
+ # generates the chart objects that belong to the property in this line.
369
+ def generateTableCell(line, property, columnDef, scenarioIdx)
370
+ case columnDef.id
371
+ when 'chart'
372
+ # Generate a hidden cell. The real meat is in the actual chart object,
373
+ # not in this cell.
374
+ cell = ReportTableCell.new(line)
375
+ cell.hidden = true
376
+ cell.text = nil
377
+ # The GanttChart can be reached via the special variable of the column
378
+ # header.
379
+ chart = columnDef.column.cell1.special
380
+ GanttLine.new(chart, property,
381
+ line.scopeLine ? line.scopeLine.property : nil,
382
+ scenarioIdx, (line.subLineNo - 1) * (line.height + 1),
383
+ line.height)
384
+ return true
385
+ # The calendar cells can be all generated by the same function. But we
386
+ # need to use different parameters.
387
+ when 'hourly'
388
+ start = @start.midnight
389
+ sameTimeNextFunc = :sameTimeNextHour
390
+ when 'daily'
391
+ start = @start.midnight
392
+ sameTimeNextFunc = :sameTimeNextDay
393
+ when 'weekly'
394
+ start = @start.beginOfWeek(@weekStartsMonday)
395
+ sameTimeNextFunc = :sameTimeNextWeek
396
+ when 'monthly'
397
+ start = @start.beginOfMonth
398
+ sameTimeNextFunc = :sameTimeNextMonth
399
+ when 'quarterly'
400
+ start = @start.beginOfQuarter
401
+ sameTimeNextFunc = :sameTimeNextQuarter
402
+ when 'yearly'
403
+ start = @start.beginOfYear
404
+ sameTimeNextFunc = :sameTimeNextYear
405
+ else
406
+ if calculated?(columnDef.id)
407
+ genCalculatedCell(scenarioIdx, line, columnDef, property)
408
+ return true
409
+ else
410
+ return genStandardCell(scenarioIdx, line, columnDef)
411
+ end
412
+ end
413
+
414
+ # The calendar cells don't live in this ReportTable but in an embedded
415
+ # ReportTable that can be reached via the column header special variable.
416
+ # For embedded column tables we need to create a new line.
417
+ tcLine = ReportTableLine.new(columnDef.column.cell1.special,
418
+ line.property, line.scopeLine)
419
+
420
+ # Depending on the property type we use different generator functions.
421
+ if property.is_a?(Task)
422
+ genCalChartTaskCell(scenarioIdx, tcLine, columnDef, start,
423
+ sameTimeNextFunc)
424
+ elsif property.is_a?(Resource)
425
+ genCalChartResourceCell(scenarioIdx, tcLine, columnDef, start,
426
+ sameTimeNextFunc)
427
+ else
428
+ raise "Unknown property type #{property.class}"
429
+ end
430
+ true
431
+ end
432
+
433
+ # Generate a ReportTableCell filled the value of an attribute of the
434
+ # property that line is for. It returns true if the cell exists, false for a
435
+ # hidden cell.
436
+ def genStandardCell(scenarioIdx, line, columnDef)
437
+ property = line.property
438
+ # Create a new cell
439
+ cell = newCell(line, cellText(property, scenarioIdx, columnDef.id))
440
+
441
+ if property.is_a?(Task)
442
+ properties = @project.tasks
443
+ elsif property.is_a?(Resource)
444
+ properties = @project.resources
445
+ else
446
+ raise "Unknown property type #{property.class}"
447
+ end
448
+
449
+ # Check if we are dealing with multiple scenarios.
450
+ if @scenarios.length > 1
451
+ # Check if the attribute is not scenario specific
452
+ unless properties.scenarioSpecific?(columnDef.id)
453
+ if scenarioIdx == @scenarios.first
454
+ # Use a somewhat bigger font.
455
+ cell.fontSize = 15
456
+ else
457
+ # And hide the cells for all but the first scenario.
458
+ cell.hidden = true
459
+ return false
460
+ end
461
+ cell.rows = @scenarios.length
462
+ end
463
+ end
464
+
465
+ setStandardCellAttributes(cell, columnDef,
466
+ properties.attributeType(columnDef.id), line)
467
+
468
+ scopeProperty = line.scopeLine ? line.scopeLine.property : nil
469
+ query = Query.new('property' => property,
470
+ 'scopeProperty' => scopeProperty,
471
+ 'attributeId' => columnDef.id,
472
+ 'scenarioIdx' => scenarioIdx, 'loadUnit' => @loadUnit,
473
+ 'numberFormat' => @numberFormat,
474
+ 'currencyFormat' => @currencyFormat,
475
+ 'start' => @start, 'end' => @end,
476
+ 'costAccount' => @costAccount,
477
+ 'revenueAccount' => @revenueAccount)
478
+ if cell.text
479
+ if columnDef.cellText
480
+ cell.text = expandMacros(columnDef.cellText, cell.text, query)
481
+ end
482
+ else
483
+ cell.text = '<Error>'
484
+ cell.fontColor = 0xFF0000
485
+ end
486
+
487
+ setCellURL(cell, columnDef, query)
488
+ true
489
+ end
490
+
491
+ # Generate a ReportTableCell filled with a calculted value from the property
492
+ # or other sources of information. It returns true if the cell exists, false
493
+ # for a hidden cell. _scenarioIdx_ is the index of the reported scenario.
494
+ # _line_ is the ReportTableLine of the cell. _columnDef_ is the
495
+ # TableColumnDefinition of the column. _property_ is the PropertyTreeNode
496
+ # that is reported in this cell.
497
+ def genCalculatedCell(scenarioIdx, line, columnDef, property)
498
+ # Create a new cell
499
+ cell = newCell(line)
500
+
501
+ unless scenarioSpecific?(columnDef.id)
502
+ if scenarioIdx != @scenarios.first
503
+ cell.hidden = true
504
+ return false
505
+ end
506
+ cell.rows = @scenarios.length
507
+ end
508
+
509
+ setStandardCellAttributes(cell, columnDef, nil, line)
510
+
511
+ return if columnDef.hideCellText &&
512
+ endcolumnDef.hideCellText.eval(property, scopeProperty)
513
+
514
+ scopeProperty = line.scopeLine ? line.scopeLine.property : nil
515
+ query = Query.new('property' => property,
516
+ 'scopeProperty' => scopeProperty,
517
+ 'attributeId' => columnDef.id,
518
+ 'scenarioIdx' => scenarioIdx, 'loadUnit' => @loadUnit,
519
+ 'numberFormat' => @numberFormat,
520
+ 'currencyFormat' => @currencyFormat,
521
+ 'start' => @start, 'end' => @end,
522
+ 'costAccount' => @costAccount,
523
+ 'revenueAccount' => @revenueAccount)
524
+ query.process
525
+ cell.text = query.result
526
+
527
+ # Some columns need some extra care.
528
+ case columnDef.id
529
+ when 'line'
530
+ cell.text = line.lineNo.to_s
531
+ when 'no'
532
+ cell.text = line.no.to_s
533
+ when 'wbs'
534
+ cell.indent = 2 if line.scopeLine
535
+ end
536
+
537
+ if columnDef.cellText
538
+ cell.text = expandMacros(columnDef.cellText, cell.text, query)
539
+ end
540
+ setCellURL(cell, columnDef, query)
541
+ end
542
+
543
+ # Generate the cells for the task lines of a calendar column. These lines do
544
+ # not directly belong to the @table object but to an embedded ColumnTable
545
+ # object. Therefor a single @table column usually has many cells on each
546
+ # single line. _scenarioIdx_ is the index of the scenario that is reported
547
+ # in this line. _line_ is the @table line. _t_ is the start date for the
548
+ # calendar. _sameTimeNextFunc_ is the function that will move the date to
549
+ # the next cell.
550
+ def genCalChartTaskCell(scenarioIdx, line, columnDef, t, sameTimeNextFunc)
551
+ task = line.property
552
+ # Find out if we have an enclosing resource scope.
553
+ if line.scopeLine && line.scopeLine.property.is_a?(Resource)
554
+ resource = line.scopeLine.property
555
+ else
556
+ resource = nil
557
+ end
558
+
559
+ # Get the interval of the task. In case a date is invalid due to a
560
+ # scheduling problem, we use the full project interval.
561
+ taskIv = Interval.new(task['start', scenarioIdx].nil? ?
562
+ @project['start'] : task['start', scenarioIdx],
563
+ task['end', scenarioIdx].nil? ?
564
+ @project['end'] : task['end', scenarioIdx])
565
+
566
+ query = Query.new('property' => task, 'scopeProperty' => resource,
567
+ 'scenarioIdx' => scenarioIdx, 'loadUnit' => @loadUnit,
568
+ 'numberFormat' => @numberFormat,
569
+ 'currencyFormat' => @currencyFormat,
570
+ 'costAccount' => @costAccount,
571
+ 'revenueAccount' => @revenueAccount)
572
+
573
+ firstCell = nil
574
+ while t < @end
575
+ # Create a new cell
576
+ cell = newCell(line)
577
+
578
+ # call TjTime::sameTimeNext... function
579
+ nextT = t.send(sameTimeNextFunc)
580
+ cellIv = Interval.new(t, nextT)
581
+ case columnDef.content
582
+ when 'empty'
583
+ # We only generate cells will different background colors.
584
+ when 'load'
585
+ query.attributeId = 'effort'
586
+ query.startIdx = t
587
+ query.endIdx = nextT
588
+ query.process
589
+ # To increase readability, we don't show 0.0 values.
590
+ cell.text = query.result if query.numericalResult > 0.0
591
+ else
592
+ raise "Unknown column content #{column.content}"
593
+ end
594
+
595
+ # Determine cell category (mostly the background color)
596
+ if cellIv.overlaps?(taskIv)
597
+ cell.category = task.container? ? 'calconttask' : 'caltask'
598
+ elsif !@project.isWorkingTime(cellIv)
599
+ cell.category = 'offduty'
600
+ else
601
+ cell.category = 'taskcell'
602
+ end
603
+ cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
604
+
605
+ tryCellMerging(cell, line, firstCell)
606
+
607
+ t = nextT
608
+ firstCell = cell unless firstCell
609
+ end
610
+
611
+ legend.addCalendarItem('Container Task', 'calconttask1')
612
+ legend.addCalendarItem('Task', 'caltask1')
613
+ legend.addCalendarItem('Off duty time', 'offduty')
614
+ end
615
+
616
+ # Generate the cells for the resource lines of a calendar column. These
617
+ # lines do not directly belong to the @table object but to an embedded
618
+ # ColumnTable object. Therefor a single @table column usually has many cells
619
+ # on each single line. _scenarioIdx_ is the index of the scenario that is
620
+ # reported in this line. _line_ is the @table line. _t_ is the start date
621
+ # for the calendar. _sameTimeNextFunc_ is the function that will move the
622
+ # date to the next cell.
623
+ def genCalChartResourceCell(scenarioIdx, line, columnDef, t,
624
+ sameTimeNextFunc)
625
+ resource = line.property
626
+ # Find out if we have an enclosing task scope.
627
+ if line.scopeLine && line.scopeLine.property.is_a?(Task)
628
+ task = line.scopeLine.property
629
+ # Get the interval of the task. In case a date is invalid due to a
630
+ # scheduling problem, we use the full project interval.
631
+ taskIv = Interval.new(task['start', scenarioIdx].nil? ?
632
+ @project['start'] : task['start', scenarioIdx],
633
+ task['end', scenarioIdx].nil? ?
634
+ @project['end'] : task['end', scenarioIdx])
635
+ else
636
+ task = nil
637
+ end
638
+
639
+ query = Query.new('property' => resource,
640
+ 'scenarioIdx' => scenarioIdx, 'loadUnit' => @loadUnit,
641
+ 'numberFormat' => @numberFormat,
642
+ 'currencyFormat' => @currencyFormat,
643
+ 'costAccount' => @costAccount,
644
+ 'revenueAccount' => @revenueAccount)
645
+
646
+ firstCell = nil
647
+ while t < @end
648
+ # Create a new cell
649
+ cell = newCell(line)
650
+
651
+ # call TjTime::sameTimeNext... function
652
+ nextT = t.send(sameTimeNextFunc)
653
+ cellIv = Interval.new(t, nextT)
654
+ # Get work load for all tasks.
655
+ query.scopeProperty = nil
656
+ query.attributeId = 'effort'
657
+ query.startIdx = @project.dateToIdx(t, true)
658
+ query.endIdx = @project.dateToIdx(nextT, true) - 1
659
+ query.process
660
+ workLoad = query.numericalResult
661
+ scaledWorkLoad = query.result
662
+ if task
663
+ # Get work load for the particular task.
664
+ query.scopeProperty = task
665
+ query.process
666
+ workLoadTask = query.numericalResult
667
+ scaledWorkLoad = query.result
668
+ else
669
+ workLoadTask = 0.0
670
+ end
671
+ # Get unassigned work load.
672
+ query.attributeId = 'freework'
673
+ query.process
674
+ freeLoad = query.numericalResult
675
+ case columnDef.content
676
+ when 'empty'
677
+ # We only generate cells will different background colors.
678
+ when 'load'
679
+ # Report the workload of the resource in this time interval.
680
+ # To increase readability, we don't show 0.0 values.
681
+ wLoad = task ? workLoadTask : workLoad
682
+ if wLoad > 0.0
683
+ cell.text = scaledWorkLoad
684
+ end
685
+ else
686
+ raise "Unknown column content #{column.content}"
687
+ end
688
+
689
+ # Determine cell category (mostly the background color)
690
+ cell.category = if task
691
+ if cellIv.overlaps?(taskIv)
692
+ if workLoadTask > 0.0 && freeLoad == 0.0
693
+ 'busy'
694
+ elsif workLoad == 0.0 && freeLoad == 0.0
695
+ 'offduty'
696
+ else
697
+ 'loaded'
698
+ end
699
+ else
700
+ if freeLoad > 0.0
701
+ 'free'
702
+ elsif workLoad == 0.0 && freeLoad == 0.0
703
+ 'offduty'
704
+ else
705
+ 'resourcecell'
706
+ end
707
+ end
708
+ else
709
+ if workLoad > 0.0 && freeLoad == 0.0
710
+ 'busy'
711
+ elsif workLoad > 0.0 && freeLoad > 0.0
712
+ 'loaded'
713
+ elsif workLoad == 0.0 && freeLoad > 0.0
714
+ 'free'
715
+ else
716
+ 'offduty'
717
+ end
718
+ end
719
+ cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
720
+
721
+ tryCellMerging(cell, line, firstCell)
722
+
723
+ t = nextT
724
+ firstCell = cell unless firstCell
725
+ end
726
+
727
+ legend.addCalendarItem('Resource is fully loaded', 'busy1')
728
+ legend.addCalendarItem('Resource is partially loaded', 'loaded1')
729
+ legend.addCalendarItem('Resource is available', 'free')
730
+ legend.addCalendarItem('Off duty time', 'offduty')
731
+ end
732
+
733
+ def setStandardCellAttributes(cell, columnDef, attributeType, line)
734
+ # Determine whether it should be indented
735
+ if indent(columnDef.id, attributeType)
736
+ cell.indent = line.indentation
737
+ end
738
+
739
+ # Determine the cell alignment
740
+ cell.alignment = alignment(columnDef.id, attributeType)
741
+
742
+ # Set background color
743
+ if line.property.is_a?(Task)
744
+ cell.category = line.property.get('index') % 2 == 1 ?
745
+ 'taskcell1' : 'taskcell2'
746
+ else
747
+ cell.category = line.property.get('index') % 2 == 1 ?
748
+ 'resourcecell1' : 'resourcecell2'
749
+ end
750
+ end
751
+
752
+ # Create a new ReportTableCell object and initialize some common values.
753
+ def newCell(line, text = '')
754
+ property = line.property
755
+ cell = ReportTableCell.new(line, text)
756
+
757
+ # Cells for containers should be using bold font face.
758
+ cell.bold = true if property.container?
759
+
760
+ cell
761
+ end
762
+
763
+ # Determine the indentation for this line.
764
+ def setIndent(line, propertyRoot, treeMode)
765
+ property = line.property
766
+ scopeLine = line.scopeLine
767
+ level = property.level - (propertyRoot ? propertyRoot.level : 0)
768
+ # We indent at least as much as the scopeline + 1, if we have a scope.
769
+ line.indentation = scopeLine.indentation + 1 if scopeLine
770
+ # In tree mode we indent according to the level.
771
+ line.indentation += level if treeMode
772
+ end
773
+
774
+ # Set the URL associated with the cell text. _cell_ is the ReportTableCell.
775
+ # _columnDef_ is the user specified definition for the cell content and
776
+ # look. _query_ is the query used to resolve dynamic macros in the cellURL.
777
+ def setCellURL(cell, columnDef, query)
778
+ return unless columnDef.cellURL
779
+
780
+ url = expandMacros(columnDef.cellURL, cell.text, query)
781
+ cell.url = url unless url.empty?
782
+ end
783
+
784
+ # Try to merge equal cells without text to multi-column cells.
785
+ def tryCellMerging(cell, line, firstCell)
786
+ if cell.text == '' && firstCell && (c = line.last(1)) && c == cell
787
+ cell.hidden = true
788
+ c.columns += 1
789
+ end
790
+ end
791
+
792
+ # Expand the run-time macros in _pattern_. ${0} is a special case and will
793
+ # be replaced with the _originalText_. For all other macros the _query_ will
794
+ # be used with the macro name used for the attributeId of the query. The
795
+ # method returns the expanded pattern.
796
+ def expandMacros(pattern, originalText, query)
797
+ return pattern unless pattern.include?('${')
798
+
799
+ out = ''
800
+ # Scan the pattern for macros ${...}
801
+ i = 0
802
+ while i < pattern.length
803
+ c = pattern[i]
804
+ if c == ?$
805
+ # This could be a macro
806
+ if pattern[i + 1] != ?{
807
+ # It's not. Just append the '$'
808
+ out << c
809
+ else
810
+ # It is a macro.
811
+ i += 2
812
+ macro = ''
813
+ # Scan for the end '}' and get the macro name.
814
+ while i < pattern.length && pattern[i] != ?}
815
+ macro << pattern[i]
816
+ i += 1
817
+ end
818
+ if macro == '0'
819
+ # This turns RichText into plain ASCII!
820
+ out += originalText
821
+ else
822
+ # resolve by query
823
+ # If the macro is prefixed by a '?' it may be undefined.
824
+ if macro[0] == ??
825
+ macro = macro[1..-1]
826
+ ignoreErrors = true
827
+ else
828
+ ignoreErrors = false
829
+ end
830
+ query.attributeId = macro
831
+ query.process
832
+ unless query.ok || ignoreErrors
833
+ raise TjException.new, query.errorMessage
834
+ end
835
+ # This turns RichText into plain ASCII!
836
+ out += query.result
837
+ end
838
+ end
839
+ else
840
+ # Just append the character to the output.
841
+ out << c
842
+ end
843
+ i += 1
844
+ end
845
+
846
+ out
847
+ end
848
+
849
+ end
850
+
851
+ end
852
+