taskjuggler 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (544) hide show
  1. data/CHANGELOG +2086 -0
  2. data/benchmarks/666tasks.tjp +3183 -0
  3. data/benchmarks/booking.tjp +14 -10
  4. data/doc/AppConfig.html +95 -73
  5. data/doc/Arguments.html +22 -2
  6. data/doc/CHANGELOG.html +2587 -0
  7. data/doc/COPYING.html +21 -1
  8. data/doc/Object.html +161 -122
  9. data/doc/README.html +21 -1
  10. data/doc/RuntimeConfig.html +26 -6
  11. data/doc/String.html +38 -18
  12. data/doc/StringIO.html +579 -0
  13. data/doc/TaskJuggler.html +251 -143
  14. data/doc/TaskJuggler/Account.html +26 -6
  15. data/doc/TaskJuggler/AccountAttribute.html +28 -8
  16. data/doc/TaskJuggler/AccountScenario.html +24 -4
  17. data/doc/TaskJuggler/Allocation.html +30 -10
  18. data/doc/TaskJuggler/AllocationAttribute.html +28 -8
  19. data/doc/TaskJuggler/AttributeBase.html +46 -26
  20. data/doc/TaskJuggler/AttributeDefinition.html +22 -2
  21. data/doc/TaskJuggler/BatchProcessor.html +40 -20
  22. data/doc/TaskJuggler/Booking.html +26 -6
  23. data/doc/TaskJuggler/BookingListAttribute.html +28 -8
  24. data/doc/TaskJuggler/BooleanAttribute.html +28 -8
  25. data/doc/TaskJuggler/CSVFile.html +308 -146
  26. data/doc/TaskJuggler/CellSettingPattern.html +22 -2
  27. data/doc/TaskJuggler/CellSettingPatternList.html +26 -6
  28. data/doc/TaskJuggler/Charge.html +26 -6
  29. data/doc/TaskJuggler/ChargeListAttribute.html +26 -6
  30. data/doc/TaskJuggler/ChargeSet.html +33 -13
  31. data/doc/TaskJuggler/ChargeSetListAttribute.html +28 -8
  32. data/doc/TaskJuggler/ColumnListAttribute.html +26 -6
  33. data/doc/TaskJuggler/ColumnTable.html +24 -4
  34. data/doc/TaskJuggler/Daemon.html +26 -6
  35. data/doc/TaskJuggler/DateAttribute.html +26 -6
  36. data/doc/TaskJuggler/DefinitionListAttribute.html +22 -2
  37. data/doc/TaskJuggler/DependencyListAttribute.html +28 -8
  38. data/doc/TaskJuggler/DurationAttribute.html +28 -8
  39. data/doc/TaskJuggler/FixnumAttribute.html +24 -4
  40. data/doc/TaskJuggler/FlagListAttribute.html +28 -8
  41. data/doc/TaskJuggler/FloatAttribute.html +26 -6
  42. data/doc/TaskJuggler/FormatListAttribute.html +24 -4
  43. data/doc/TaskJuggler/GanttChart.html +147 -126
  44. data/doc/TaskJuggler/GanttContainer.html +34 -14
  45. data/doc/TaskJuggler/GanttHeader.html +28 -8
  46. data/doc/TaskJuggler/GanttHeaderScaleItem.html +24 -4
  47. data/doc/TaskJuggler/GanttLine.html +38 -18
  48. data/doc/TaskJuggler/GanttLoadStack.html +26 -6
  49. data/doc/TaskJuggler/GanttMilestone.html +34 -14
  50. data/doc/TaskJuggler/GanttRouter.html +50 -30
  51. data/doc/TaskJuggler/GanttTaskBar.html +34 -14
  52. data/doc/TaskJuggler/HTMLDocument.html +26 -6
  53. data/doc/TaskJuggler/HTMLGraphics.html +30 -10
  54. data/doc/TaskJuggler/Interval.html +40 -22
  55. data/doc/TaskJuggler/IntervalListAttribute.html +28 -8
  56. data/doc/TaskJuggler/JobInfo.html +24 -4
  57. data/doc/TaskJuggler/Journal.html +226 -147
  58. data/doc/TaskJuggler/JournalEntry.html +22 -2
  59. data/doc/TaskJuggler/JournalEntryList.html +129 -112
  60. data/doc/TaskJuggler/KeywordArray.html +26 -6
  61. data/doc/TaskJuggler/KeywordDocumentation.html +46 -26
  62. data/doc/TaskJuggler/Limits.html +152 -123
  63. data/doc/TaskJuggler/Limits/Limit.html +149 -70
  64. data/doc/TaskJuggler/LimitsAttribute.html +36 -51
  65. data/doc/TaskJuggler/ListAttributeBase.html +24 -4
  66. data/doc/TaskJuggler/Log.html +50 -32
  67. data/doc/TaskJuggler/LogFile.html +37 -17
  68. data/doc/TaskJuggler/LogicalAttribute.html +53 -33
  69. data/doc/TaskJuggler/LogicalExpression.html +26 -6
  70. data/doc/TaskJuggler/LogicalExpressionAttribute.html +32 -12
  71. data/doc/TaskJuggler/LogicalFlag.html +42 -22
  72. data/doc/TaskJuggler/LogicalFunction.html +204 -140
  73. data/doc/TaskJuggler/LogicalOperation.html +135 -111
  74. data/doc/TaskJuggler/Macro.html +22 -2
  75. data/doc/TaskJuggler/MacroParser.html +32 -12
  76. data/doc/TaskJuggler/MacroTable.html +32 -12
  77. data/doc/TaskJuggler/ManagerResponsibilities.html +24 -4
  78. data/doc/TaskJuggler/ManagerStatusRecord.html +24 -4
  79. data/doc/TaskJuggler/Message.html +24 -4
  80. data/doc/TaskJuggler/MessageHandler.html +24 -4
  81. data/doc/TaskJuggler/Navigator.html +104 -71
  82. data/doc/TaskJuggler/NavigatorElement.html +32 -12
  83. data/doc/TaskJuggler/NikuProject.html +22 -2
  84. data/doc/TaskJuggler/NikuReport.html +310 -228
  85. data/doc/TaskJuggler/NikuResource.html +22 -2
  86. data/doc/TaskJuggler/NodeListAttribute.html +615 -0
  87. data/doc/TaskJuggler/OnShiftCache.html +32 -12
  88. data/doc/TaskJuggler/ProcessIntercom.html +205 -78
  89. data/doc/TaskJuggler/ProcessIntercomIface.html +26 -6
  90. data/doc/TaskJuggler/Project.html +708 -660
  91. data/doc/TaskJuggler/ProjectBroker.html +506 -304
  92. data/doc/TaskJuggler/ProjectBrokerIface.html +61 -41
  93. data/doc/TaskJuggler/ProjectFileParser.html +429 -373
  94. data/doc/TaskJuggler/ProjectFileScanner.html +1790 -0
  95. data/doc/TaskJuggler/ProjectRecord.html +80 -60
  96. data/doc/TaskJuggler/ProjectServer.html +312 -237
  97. data/doc/TaskJuggler/ProjectServerIface.html +101 -43
  98. data/doc/TaskJuggler/PropertyAttribute.html +32 -12
  99. data/doc/TaskJuggler/PropertyList.html +166 -145
  100. data/doc/TaskJuggler/PropertySet.html +254 -224
  101. data/doc/TaskJuggler/PropertyTreeNode.html +670 -536
  102. data/doc/TaskJuggler/Query.html +169 -148
  103. data/doc/TaskJuggler/RTFHandlers.html +622 -0
  104. data/doc/TaskJuggler/RTFNavigator.html +28 -8
  105. data/doc/TaskJuggler/RTFQuery.html +40 -20
  106. data/doc/TaskJuggler/RTFReport.html +62 -25
  107. data/doc/TaskJuggler/RTFReportLink.html +765 -0
  108. data/doc/TaskJuggler/RealFormat.html +26 -6
  109. data/doc/TaskJuggler/RealFormatAttribute.html +26 -6
  110. data/doc/TaskJuggler/ReferenceAttribute.html +59 -39
  111. data/doc/TaskJuggler/Report.html +402 -251
  112. data/doc/TaskJuggler/ReportBase.html +162 -137
  113. data/doc/TaskJuggler/ReportContext.html +112 -29
  114. data/doc/TaskJuggler/ReportServer.html +89 -64
  115. data/doc/TaskJuggler/ReportServerIface.html +75 -55
  116. data/doc/TaskJuggler/ReportServerRecord.html +54 -31
  117. data/doc/TaskJuggler/ReportServlet.html +980 -0
  118. data/doc/TaskJuggler/ReportTable.html +41 -21
  119. data/doc/TaskJuggler/ReportTableCell.html +214 -170
  120. data/doc/TaskJuggler/ReportTableColumn.html +30 -10
  121. data/doc/TaskJuggler/ReportTableLegend.html +36 -16
  122. data/doc/TaskJuggler/ReportTableLine.html +32 -12
  123. data/doc/TaskJuggler/Resource.html +99 -87
  124. data/doc/TaskJuggler/ResourceListAttribute.html +59 -39
  125. data/doc/TaskJuggler/ResourceListRE.html +47 -26
  126. data/doc/TaskJuggler/ResourceScenario.html +403 -437
  127. data/doc/TaskJuggler/RichText.html +26 -6
  128. data/doc/TaskJuggler/RichTextAttribute.html +50 -30
  129. data/doc/TaskJuggler/RichTextDocument.html +37 -17
  130. data/doc/TaskJuggler/RichTextElement.html +475 -413
  131. data/doc/TaskJuggler/RichTextException.html +22 -2
  132. data/doc/TaskJuggler/RichTextFunctionExample.html +28 -8
  133. data/doc/TaskJuggler/RichTextFunctionHandler.html +24 -4
  134. data/doc/TaskJuggler/RichTextImage.html +22 -2
  135. data/doc/TaskJuggler/RichTextIntermediate.html +38 -18
  136. data/doc/TaskJuggler/RichTextParser.html +56 -34
  137. data/doc/TaskJuggler/RichTextScanner.html +82 -61
  138. data/doc/TaskJuggler/RichTextSnip.html +34 -14
  139. data/doc/TaskJuggler/RichTextSyntaxRules.html +507 -353
  140. data/doc/TaskJuggler/Scenario.html +22 -2
  141. data/doc/TaskJuggler/ScenarioData.html +30 -46
  142. data/doc/TaskJuggler/ScenarioListAttribute.html +38 -18
  143. data/doc/TaskJuggler/Scoreboard.html +42 -22
  144. data/doc/TaskJuggler/SheetHandlerBase.html +40 -20
  145. data/doc/TaskJuggler/SheetReceiver.html +333 -295
  146. data/doc/TaskJuggler/SheetSender.html +253 -230
  147. data/doc/TaskJuggler/Shift.html +26 -6
  148. data/doc/TaskJuggler/ShiftAssignment.html +89 -73
  149. data/doc/TaskJuggler/ShiftAssignments.html +226 -234
  150. data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +39 -54
  151. data/doc/TaskJuggler/ShiftScenario.html +28 -8
  152. data/doc/TaskJuggler/SortListAttribute.html +34 -14
  153. data/doc/TaskJuggler/SourceFileInfo.html +24 -4
  154. data/doc/TaskJuggler/StatusSheetReceiver.html +24 -3
  155. data/doc/TaskJuggler/StatusSheetReport.html +168 -153
  156. data/doc/TaskJuggler/StatusSheetSender.html +24 -3
  157. data/doc/TaskJuggler/StringAttribute.html +38 -18
  158. data/doc/TaskJuggler/SymbolAttribute.html +32 -12
  159. data/doc/TaskJuggler/SyntaxReference.html +40 -20
  160. data/doc/TaskJuggler/TOCEntry.html +26 -6
  161. data/doc/TaskJuggler/TSResourceRecord.html +22 -2
  162. data/doc/TaskJuggler/TSTaskRecord.html +22 -2
  163. data/doc/TaskJuggler/TableColumnDefinition.html +59 -22
  164. data/doc/TaskJuggler/TableOfContents.html +26 -6
  165. data/doc/TaskJuggler/TableReport.html +937 -904
  166. data/doc/TaskJuggler/Task.html +55 -36
  167. data/doc/TaskJuggler/TaskDependency.html +24 -4
  168. data/doc/TaskJuggler/TaskListAttribute.html +50 -30
  169. data/doc/TaskJuggler/TaskListRE.html +27 -7
  170. data/doc/TaskJuggler/TaskScenario.html +1273 -1153
  171. data/doc/TaskJuggler/TextFormatter.html +28 -8
  172. data/doc/TaskJuggler/TextParser.html +585 -338
  173. data/doc/TaskJuggler/TextParser/Pattern.html +54 -34
  174. data/doc/TaskJuggler/TextParser/Rule.html +95 -73
  175. data/doc/TaskJuggler/TextParser/StackElement.html +39 -17
  176. data/doc/TaskJuggler/TextParser/TextParserResultArray.html +24 -4
  177. data/doc/TaskJuggler/TextParser/TokenDoc.html +22 -2
  178. data/doc/TaskJuggler/TextReport.html +28 -8
  179. data/doc/TaskJuggler/TextScanner.html +400 -1404
  180. data/doc/TaskJuggler/TextScanner/BufferStreamHandle.html +28 -240
  181. data/doc/TaskJuggler/TextScanner/FileStreamHandle.html +37 -184
  182. data/doc/TaskJuggler/TextScanner/MacroStackEntry.html +682 -0
  183. data/doc/TaskJuggler/TextScanner/StreamHandle.html +342 -67
  184. data/doc/TaskJuggler/TimeSheet.html +48 -28
  185. data/doc/TaskJuggler/TimeSheetReceiver.html +24 -3
  186. data/doc/TaskJuggler/TimeSheetRecord.html +47 -27
  187. data/doc/TaskJuggler/TimeSheetReport.html +154 -133
  188. data/doc/TaskJuggler/TimeSheetSender.html +24 -3
  189. data/doc/TaskJuggler/TimeSheetSummary.html +137 -91
  190. data/doc/TaskJuggler/TimeSheets.html +26 -6
  191. data/doc/TaskJuggler/Tj3AppBase.html +85 -58
  192. data/doc/TaskJuggler/Tj3Client.html +292 -238
  193. data/doc/TaskJuggler/Tj3Daemon.html +159 -74
  194. data/doc/TaskJuggler/Tj3SheetAppBase.html +26 -6
  195. data/doc/TaskJuggler/Tj3SsReceiver.html +26 -6
  196. data/doc/TaskJuggler/Tj3SsSender.html +53 -26
  197. data/doc/TaskJuggler/Tj3TsReceiver.html +28 -7
  198. data/doc/TaskJuggler/Tj3TsSender.html +26 -6
  199. data/doc/TaskJuggler/Tj3TsSummary.html +26 -6
  200. data/doc/TaskJuggler/TjException.html +22 -2
  201. data/doc/TaskJuggler/TjTime.html +216 -160
  202. data/doc/TaskJuggler/TjpExample.html +34 -14
  203. data/doc/TaskJuggler/TjpExportRE.html +403 -407
  204. data/doc/TaskJuggler/TjpSyntaxRules.html +4805 -4408
  205. data/doc/TaskJuggler/URLParameter.html +649 -0
  206. data/doc/TaskJuggler/UserManual.html +42 -22
  207. data/doc/TaskJuggler/WebServer.html +702 -0
  208. data/doc/TaskJuggler/WorkingHours.html +38 -18
  209. data/doc/TaskJuggler/WorkingHoursAttribute.html +61 -41
  210. data/doc/TaskJuggler/XMLBlob.html +24 -4
  211. data/doc/TaskJuggler/XMLComment.html +24 -4
  212. data/doc/TaskJuggler/XMLDocument.html +30 -10
  213. data/doc/TaskJuggler/XMLElement.html +34 -14
  214. data/doc/TaskJuggler/XMLNamedText.html +22 -2
  215. data/doc/TaskJuggler/XMLText.html +24 -4
  216. data/doc/index.html +1841 -1666
  217. data/doc/lib/AccountScenario_rb.html +1 -1
  218. data/doc/lib/Account_rb.html +1 -1
  219. data/doc/lib/Allocation_rb.html +1 -1
  220. data/doc/lib/AppConfig_rb.html +2 -2
  221. data/doc/lib/AttributeBase_rb.html +1 -1
  222. data/doc/lib/AttributeDefinition_rb.html +1 -1
  223. data/doc/lib/Attributes_rb.html +2 -2
  224. data/doc/lib/BatchProcessor_rb.html +1 -1
  225. data/doc/lib/Booking_rb.html +1 -1
  226. data/doc/lib/ChargeSet_rb.html +1 -1
  227. data/doc/lib/Charge_rb.html +1 -1
  228. data/doc/lib/HTMLDocument_rb.html +1 -1
  229. data/doc/lib/Interval_rb.html +1 -1
  230. data/doc/lib/Journal_rb.html +2 -2
  231. data/doc/lib/KeywordArray_rb.html +1 -1
  232. data/doc/lib/KeywordDocumentation_rb.html +1 -1
  233. data/doc/lib/Limits_rb.html +2 -2
  234. data/doc/lib/LogFile_rb.html +2 -2
  235. data/doc/lib/Log_rb.html +1 -1
  236. data/doc/lib/LogicalExpression_rb.html +1 -1
  237. data/doc/lib/LogicalFunction_rb.html +2 -2
  238. data/doc/lib/LogicalOperation_rb.html +2 -2
  239. data/doc/lib/MacroParser_rb.html +1 -1
  240. data/doc/lib/MacroTable_rb.html +1 -1
  241. data/doc/lib/MessageHandler_rb.html +1 -1
  242. data/doc/lib/Message_rb.html +1 -1
  243. data/doc/lib/ProjectFileParser_rb.html +4 -8
  244. data/doc/lib/ProjectFileScanner_rb.html +67 -0
  245. data/doc/lib/Project_rb.html +2 -2
  246. data/doc/lib/PropertyList_rb.html +2 -2
  247. data/doc/lib/PropertySet_rb.html +2 -2
  248. data/doc/lib/PropertyTreeNode_rb.html +2 -2
  249. data/doc/lib/Query_rb.html +2 -2
  250. data/doc/lib/RTFHandlers_rb.html +73 -0
  251. data/doc/lib/RTFNavigator_rb.html +1 -1
  252. data/doc/lib/RTFQuery_rb.html +1 -1
  253. data/doc/lib/RTFReportLink_rb.html +71 -0
  254. data/doc/lib/RTFReport_rb.html +2 -2
  255. data/doc/lib/RealFormat_rb.html +1 -1
  256. data/doc/lib/ResourceScenario_rb.html +2 -2
  257. data/doc/lib/Resource_rb.html +2 -2
  258. data/doc/lib/RichTextDocument_rb.html +1 -1
  259. data/doc/lib/RichTextElement_rb.html +2 -2
  260. data/doc/lib/RichTextFunctionExample_rb.html +1 -1
  261. data/doc/lib/RichTextFunctionHandler_rb.html +1 -1
  262. data/doc/lib/RichTextParser_rb.html +2 -2
  263. data/doc/lib/RichTextScanner_rb.html +2 -2
  264. data/doc/lib/RichTextSnip_rb.html +1 -1
  265. data/doc/lib/RichTextSyntaxRules_rb.html +2 -2
  266. data/doc/lib/RichText_rb.html +1 -1
  267. data/doc/lib/RuntimeConfig_rb.html +1 -1
  268. data/doc/lib/ScenarioData_rb.html +2 -2
  269. data/doc/lib/Scenario_rb.html +1 -1
  270. data/doc/lib/Scoreboard_rb.html +1 -1
  271. data/doc/lib/SheetHandlerBase_rb.html +1 -1
  272. data/doc/lib/SheetReceiver_rb.html +2 -2
  273. data/doc/lib/SheetSender_rb.html +4 -2
  274. data/doc/lib/ShiftAssignments_rb.html +4 -2
  275. data/doc/lib/ShiftScenario_rb.html +1 -1
  276. data/doc/lib/Shift_rb.html +1 -1
  277. data/doc/lib/SourceFileInfo_rb.html +1 -1
  278. data/doc/lib/StatusSheetReceiver_rb.html +2 -2
  279. data/doc/lib/StatusSheetSender_rb.html +2 -2
  280. data/doc/lib/SyntaxReference_rb.html +1 -1
  281. data/doc/lib/TOCEntry_rb.html +1 -1
  282. data/doc/lib/TableColumnDefinition_rb.html +2 -2
  283. data/doc/lib/TableOfContents_rb.html +1 -1
  284. data/doc/lib/TaskDependency_rb.html +1 -1
  285. data/doc/lib/TaskJuggler_rb.html +2 -2
  286. data/doc/lib/TaskScenario_rb.html +2 -2
  287. data/doc/lib/Task_rb.html +2 -2
  288. data/doc/lib/TextFormatter_rb.html +1 -1
  289. data/doc/lib/TextParser/Pattern_rb.html +1 -1
  290. data/doc/lib/TextParser/Rule_rb.html +2 -2
  291. data/doc/lib/TextParser/StackElement_rb.html +2 -2
  292. data/doc/lib/TextParser/TokenDoc_rb.html +1 -1
  293. data/doc/lib/TextParser_rb.html +2 -2
  294. data/doc/lib/TextScanner_rb.html +6 -2
  295. data/doc/lib/TimeSheetReceiver_rb.html +2 -2
  296. data/doc/lib/TimeSheetSender_rb.html +2 -2
  297. data/doc/lib/TimeSheetSummary_rb.html +2 -2
  298. data/doc/lib/TimeSheets_rb.html +2 -2
  299. data/doc/lib/Tj3AppBase_rb.html +2 -2
  300. data/doc/lib/Tj3Config_rb.html +2 -2
  301. data/doc/lib/Tj3SheetAppBase_rb.html +2 -2
  302. data/doc/lib/TjException_rb.html +1 -1
  303. data/doc/lib/TjTime_rb.html +2 -2
  304. data/doc/lib/TjpExample_rb.html +1 -1
  305. data/doc/lib/TjpSyntaxRules_rb.html +2 -2
  306. data/doc/lib/URLParameter_rb.html +67 -0
  307. data/doc/lib/UTF8String_rb.html +1 -1
  308. data/doc/lib/UserManual_rb.html +1 -1
  309. data/doc/lib/WorkingHours_rb.html +1 -1
  310. data/doc/lib/XMLDocument_rb.html +2 -2
  311. data/doc/lib/XMLElement_rb.html +1 -1
  312. data/doc/lib/daemon/Daemon_rb.html +1 -1
  313. data/doc/lib/daemon/ProcessIntercom_rb.html +2 -2
  314. data/doc/lib/daemon/ProjectBroker_rb.html +4 -2
  315. data/doc/lib/daemon/ProjectServer_rb.html +2 -2
  316. data/doc/lib/daemon/ReportServer_rb.html +2 -2
  317. data/doc/lib/daemon/WebServer_rb.html +75 -0
  318. data/doc/lib/deep_copy_rb.html +2 -2
  319. data/doc/lib/reports/CSVFile_rb.html +2 -2
  320. data/doc/lib/reports/ColumnTable_rb.html +1 -1
  321. data/doc/lib/reports/GanttChart_rb.html +2 -2
  322. data/doc/lib/reports/GanttContainer_rb.html +1 -1
  323. data/doc/lib/reports/GanttHeaderScaleItem_rb.html +1 -1
  324. data/doc/lib/reports/GanttHeader_rb.html +1 -1
  325. data/doc/lib/reports/GanttLine_rb.html +1 -1
  326. data/doc/lib/reports/GanttLoadStack_rb.html +1 -1
  327. data/doc/lib/reports/GanttMilestone_rb.html +1 -1
  328. data/doc/lib/reports/GanttRouter_rb.html +1 -1
  329. data/doc/lib/reports/GanttTaskBar_rb.html +1 -1
  330. data/doc/lib/reports/HTMLGraphics_rb.html +1 -1
  331. data/doc/lib/reports/Navigator_rb.html +2 -2
  332. data/doc/lib/reports/NikuReport_rb.html +2 -2
  333. data/doc/lib/reports/ReportBase_rb.html +2 -2
  334. data/doc/lib/reports/ReportContext_rb.html +2 -2
  335. data/doc/lib/reports/ReportTableCell_rb.html +2 -2
  336. data/doc/lib/reports/ReportTableColumn_rb.html +1 -1
  337. data/doc/lib/reports/ReportTableLegend_rb.html +1 -1
  338. data/doc/lib/reports/ReportTableLine_rb.html +1 -1
  339. data/doc/lib/reports/ReportTable_rb.html +2 -2
  340. data/doc/lib/reports/Report_rb.html +2 -2
  341. data/doc/lib/reports/ResourceListRE_rb.html +2 -2
  342. data/doc/lib/reports/StatusSheetReport_rb.html +2 -2
  343. data/doc/lib/reports/TableReport_rb.html +2 -2
  344. data/doc/lib/reports/TaskListRE_rb.html +2 -2
  345. data/doc/lib/reports/TextReport_rb.html +1 -1
  346. data/doc/lib/reports/TimeSheetReport_rb.html +2 -2
  347. data/doc/lib/reports/TjpExportRE_rb.html +2 -2
  348. data/doc/lib/ruby-signal-bug_rb.html +1 -1
  349. data/doc/lib/taskjuggler3_rb.html +2 -2
  350. data/doc/lib/tj3client_rb.html +2 -2
  351. data/doc/lib/tj3d_rb.html +2 -2
  352. data/doc/lib/tj3man_rb.html +1 -1
  353. data/doc/lib/tj3ss_receiver_rb.html +1 -1
  354. data/doc/lib/tj3ss_sender_rb.html +2 -2
  355. data/doc/lib/tj3ts_receiver_rb.html +2 -2
  356. data/doc/lib/tj3ts_sender_rb.html +1 -1
  357. data/doc/lib/tj3ts_summary_rb.html +1 -1
  358. data/doc/rdoc.css +9 -4
  359. data/examples/tutorial.tjp +17 -15
  360. data/gem_spec.rb +3 -0
  361. data/lib/AppConfig.rb +3 -1
  362. data/lib/Attributes.rb +10 -8
  363. data/lib/Journal.rb +55 -20
  364. data/lib/Limits.rb +72 -46
  365. data/lib/LogFile.rb +3 -3
  366. data/lib/LogicalFunction.rb +19 -6
  367. data/lib/LogicalOperation.rb +5 -1
  368. data/lib/Project.rb +37 -9
  369. data/lib/ProjectFileParser.rb +25 -22
  370. data/lib/ProjectFileScanner.rb +365 -0
  371. data/lib/PropertyList.rb +2 -1
  372. data/lib/PropertySet.rb +14 -4
  373. data/lib/PropertyTreeNode.rb +42 -29
  374. data/lib/Query.rb +3 -1
  375. data/lib/RTFHandlers.rb +35 -0
  376. data/lib/RTFReport.rb +23 -6
  377. data/lib/RTFReportLink.rb +72 -0
  378. data/lib/Resource.rb +8 -16
  379. data/lib/ResourceScenario.rb +1 -22
  380. data/lib/RichTextElement.rb +42 -0
  381. data/lib/RichTextParser.rb +6 -4
  382. data/lib/RichTextScanner.rb +5 -5
  383. data/lib/RichTextSyntaxRules.rb +48 -10
  384. data/lib/ScenarioData.rb +5 -3
  385. data/lib/SheetReceiver.rb +24 -6
  386. data/lib/SheetSender.rb +17 -13
  387. data/lib/ShiftAssignments.rb +56 -52
  388. data/lib/StatusSheetReceiver.rb +1 -0
  389. data/lib/StatusSheetSender.rb +1 -0
  390. data/lib/TableColumnDefinition.rb +4 -2
  391. data/lib/Task.rb +8 -9
  392. data/lib/TaskJuggler.rb +21 -11
  393. data/lib/TaskScenario.rb +61 -26
  394. data/lib/TextParser.rb +268 -106
  395. data/lib/TextParser/Rule.rb +4 -2
  396. data/lib/TextParser/StackElement.rb +6 -4
  397. data/lib/TextScanner.rb +283 -700
  398. data/lib/TimeSheetReceiver.rb +1 -0
  399. data/lib/TimeSheetSender.rb +1 -0
  400. data/lib/TimeSheetSummary.rb +51 -26
  401. data/lib/TimeSheets.rb +1 -1
  402. data/lib/Tj3AppBase.rb +8 -1
  403. data/lib/Tj3Config.rb +1 -1
  404. data/lib/TjTime.rb +5 -0
  405. data/lib/TjpSyntaxRules.rb +360 -144
  406. data/lib/URLParameter.rb +30 -0
  407. data/lib/XMLDocument.rb +2 -2
  408. data/lib/daemon/ProcessIntercom.rb +50 -9
  409. data/lib/daemon/ProjectBroker.rb +63 -10
  410. data/lib/daemon/ProjectServer.rb +47 -16
  411. data/lib/daemon/ReportServer.rb +9 -4
  412. data/lib/daemon/WebServer.rb +204 -0
  413. data/lib/deep_copy.rb +4 -1
  414. data/lib/reports/CSVFile.rb +150 -66
  415. data/lib/reports/GanttChart.rb +2 -1
  416. data/lib/reports/Navigator.rb +18 -5
  417. data/lib/reports/NikuReport.rb +32 -2
  418. data/lib/reports/Report.rb +65 -37
  419. data/lib/reports/ReportBase.rb +14 -9
  420. data/lib/reports/ReportContext.rb +19 -4
  421. data/lib/reports/ReportTable.rb +2 -2
  422. data/lib/reports/ReportTableCell.rb +54 -30
  423. data/lib/reports/ResourceListRE.rb +4 -3
  424. data/lib/reports/StatusSheetReport.rb +8 -13
  425. data/lib/reports/TableReport.rb +47 -32
  426. data/lib/reports/TaskListRE.rb +3 -3
  427. data/lib/reports/TimeSheetReport.rb +14 -5
  428. data/lib/reports/TjpExportRE.rb +14 -19
  429. data/lib/taskjuggler3.rb +15 -0
  430. data/lib/tj3client.rb +9 -7
  431. data/lib/tj3d.rb +38 -10
  432. data/lib/tj3ss_sender.rb +7 -0
  433. data/lib/tj3ts_receiver.rb +1 -0
  434. data/manual/Day_To_Day_Juggling +1 -1
  435. data/manual/Rich_Text_Attributes +8 -0
  436. data/manual/TaskJuggler_2x_Migration +7 -0
  437. data/manual/The_TaskJuggler_Syntax +20 -6
  438. data/prj_cfg.rb +3 -2
  439. data/tasks/changelog.rake +36 -0
  440. data/tasks/csts.rake +2 -3
  441. data/tasks/gem.rake +10 -0
  442. data/tasks/missing.rake +0 -17
  443. data/test/TestSuite/ReportGenerator/Correct/Journal.html +63 -0
  444. data/test/TestSuite/ReportGenerator/Correct/Journal.tjp +14 -0
  445. data/test/TestSuite/{HTML-Reports/LogicalFunctions.tjp → ReportGenerator/Correct/LogicalFunctions1.tjp} +2 -2
  446. data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.csv +3 -0
  447. data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.tjp +19 -0
  448. data/test/TestSuite/ReportGenerator/Correct/css/tjmanual.css +66 -0
  449. data/test/TestSuite/ReportGenerator/Correct/css/tjreport.css +407 -0
  450. data/test/TestSuite/ReportGenerator/Correct/icons/details.png +0 -0
  451. data/test/TestSuite/ReportGenerator/Correct/icons/flag-green.png +0 -0
  452. data/test/TestSuite/ReportGenerator/Correct/icons/flag-red.png +0 -0
  453. data/test/TestSuite/ReportGenerator/Correct/icons/flag-yellow.png +0 -0
  454. data/test/TestSuite/ReportGenerator/Correct/icons/resource.png +0 -0
  455. data/test/TestSuite/ReportGenerator/Correct/icons/resourcegroup.png +0 -0
  456. data/test/TestSuite/ReportGenerator/Correct/icons/task.png +0 -0
  457. data/test/TestSuite/ReportGenerator/Correct/icons/taskgroup.png +0 -0
  458. data/test/TestSuite/ReportGenerator/Correct/icons/trend-down.png +0 -0
  459. data/test/TestSuite/ReportGenerator/Correct/icons/trend-flat.png +0 -0
  460. data/test/TestSuite/ReportGenerator/Correct/icons/trend-up.png +0 -0
  461. data/test/TestSuite/ReportGenerator/Correct/opennodes.csv +2 -0
  462. data/test/TestSuite/ReportGenerator/Correct/opennodes.tjp +26 -0
  463. data/test/TestSuite/ReportGenerator/Correct/refs/Journal-1.csv +6 -0
  464. data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions1-1.csv +7 -0
  465. data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions2-1.csv +2 -0
  466. data/test/TestSuite/ReportGenerator/Correct/refs/opennodes-1.csv +2 -0
  467. data/test/TestSuite/ReportGenerator/Correct/scripts/wz_tooltip.js +1301 -0
  468. data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.tjp +20 -0
  469. data/test/TestSuite/Scheduler/Correct/Container.html +349 -0
  470. data/test/TestSuite/Scheduler/Correct/Limits.tjp +11 -4
  471. data/test/TestSuite/Scheduler/Correct/Shift2.html +464 -150
  472. data/test/TestSuite/Scheduler/Correct/TimeSheet2.html +108 -0
  473. data/test/TestSuite/Scheduler/Correct/TimeSheet2.tjp +7 -0
  474. data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +14 -0
  475. data/test/TestSuite/Scheduler/Correct/css/tjreport.css +233 -21
  476. data/test/TestSuite/Scheduler/Correct/scripts/wz_tooltip.js +20 -20
  477. data/test/TestSuite/StatusSheetTemplates/project.tji +35 -0
  478. data/test/TestSuite/StatusSheetTemplates/project.tjp +56 -0
  479. data/test/TestSuite/StatusSheets/run +3 -2
  480. data/test/TestSuite/Syntax/Correct/Include.tjp +1 -1
  481. data/test/TestSuite/Syntax/Correct/Macro-1.tjp +1 -1
  482. data/test/TestSuite/Syntax/Correct/Macro-2.tjp +6 -0
  483. data/test/TestSuite/Syntax/Correct/Macro-3.tjp +14 -0
  484. data/test/TestSuite/Syntax/Correct/ResourcePrefix.html +32 -0
  485. data/test/TestSuite/Syntax/Correct/css/tjmanual.css +66 -0
  486. data/test/TestSuite/Syntax/Correct/css/tjreport.css +407 -0
  487. data/test/TestSuite/Syntax/Correct/icons/details.png +0 -0
  488. data/test/TestSuite/Syntax/Correct/icons/flag-green.png +0 -0
  489. data/test/TestSuite/Syntax/Correct/icons/flag-red.png +0 -0
  490. data/test/TestSuite/Syntax/Correct/icons/flag-yellow.png +0 -0
  491. data/test/TestSuite/Syntax/Correct/icons/resource.png +0 -0
  492. data/test/TestSuite/Syntax/Correct/icons/resourcegroup.png +0 -0
  493. data/test/TestSuite/Syntax/Correct/icons/task.png +0 -0
  494. data/test/TestSuite/Syntax/Correct/icons/taskgroup.png +0 -0
  495. data/test/TestSuite/Syntax/Correct/icons/trend-down.png +0 -0
  496. data/test/TestSuite/Syntax/Correct/icons/trend-flat.png +0 -0
  497. data/test/TestSuite/Syntax/Correct/icons/trend-up.png +0 -0
  498. data/test/TestSuite/Syntax/Correct/include/dir1/file2.tji +3 -0
  499. data/test/TestSuite/Syntax/Correct/include/dir1/file5.tji +2 -0
  500. data/test/TestSuite/Syntax/Correct/include/dir3/all.tji +3 -0
  501. data/test/TestSuite/Syntax/Correct/include/dir3/file1.tji +2 -0
  502. data/test/TestSuite/Syntax/Correct/include/dir3/file2.tji +1 -0
  503. data/test/TestSuite/Syntax/Correct/scripts/wz_tooltip.js +1301 -0
  504. data/test/TestSuite/Syntax/Correct/tutorial.tjp +13 -13
  505. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
  506. data/test/TestSuite/Syntax/Errors/include_recursion.tjp +1 -0
  507. data/test/TestSuite/Syntax/Errors/macro_stack_overflow.tjp +2 -1
  508. data/test/TestSuite/Syntax/Errors/{eof_in_istring1.tjp → no_token_match1.tjp} +2 -2
  509. data/test/TestSuite/Syntax/Errors/{eof_in_istring2.tjp → no_token_match2.tjp} +2 -2
  510. data/test/TestSuite/Syntax/Errors/{eof_in_istring3.tjp → no_token_match3.tjp} +1 -1
  511. data/test/TestSuite/Syntax/Errors/{eof_in_istring4.tjp → no_token_match4.tjp} +1 -1
  512. data/test/TestSuite/Syntax/Errors/{eof_in_istring5.tjp → no_token_match5.tjp} +1 -1
  513. data/test/TestSuite/Syntax/Errors/not_scheduled.tjp +13 -0
  514. data/test/TestSuite/Syntax/Errors/unsupported_token.tjp +1 -1
  515. data/test/TestSuite/TimeSheets/run +5 -5
  516. data/test/test_CSVFile.rb +75 -0
  517. data/test/test_Limits.rb +63 -5
  518. data/test/test_ProjectFileScanner.rb +163 -0
  519. data/test/test_ReportGenerator.rb +81 -0
  520. data/test/test_RichText.rb +21 -3
  521. data/test/test_Scheduler.rb +1 -1
  522. data/test/test_ShiftAssignments.rb +4 -4
  523. data/test/test_Syntax.rb +1 -1
  524. data/test/test_URLParameter.rb +30 -0
  525. metadata +126 -32
  526. data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +0 -8
  527. data/test/TestSuite/Syntax/Errors/bad_comment.tjp +0 -7
  528. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/boss_2002-03-01.tji +0 -36
  529. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev1_2002-03-01.tji +0 -48
  530. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev2_2002-03-01.tji +0 -67
  531. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev3_2002-03-01.tji +0 -67
  532. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/doc_2002-03-01.tji +0 -48
  533. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/resources.yml +0 -31
  534. data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/test_2002-03-01.tji +0 -36
  535. data/test/TestSuite/TimeSheets/TimeSheetTemplates/acceptable_intervals +0 -1
  536. data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/all.tji +0 -1
  537. data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/dev2_2002-03-01.tji +0 -54
  538. data/test/TestSuite/TimeSheets/TimeSheets/all.tji +0 -2
  539. data/test/TestSuite/TimeSheets/receiver.log +0 -102
  540. data/test/TestSuite/TimeSheets/sender.log +0 -794
  541. data/test/TestSuite/TimeSheets/summary.log +0 -884
  542. data/test/TestSuite/TimeSheets/timesheets.log +0 -45
  543. data/test/TestSuite/TimeSheets/tj3d.log +0 -292
  544. data/test/test_TextScanner.rb +0 -95
@@ -34,6 +34,7 @@ class TaskJuggler
34
34
  @sheetHeader = /^[ ]*timesheet\s([a-z][a-z0-9_]*)\s[0-9\-:+]*\s-\s([0-9]*-[0-9]*-[0-9]*)/
35
35
  # Regular expression to extract the sheet signature (time period).
36
36
  @signatureFilter = /^[ ]*timesheet\s[a-z][a-z0-9_]*\s([0-9:\-+]*\s-\s[0-9:\-+]*)/
37
+ @emailSubject = "Report from %s for %s"
37
38
  end
38
39
 
39
40
  end
@@ -48,6 +48,7 @@ encoded and the time sheet header from 'timesheet' to the period end
48
48
  date must be in a single line that starts at the beginning of the line.
49
49
 
50
50
  EOT
51
+ @mailSubject = 'Your weekly time sheet template for %s'
51
52
  end
52
53
 
53
54
  end
@@ -27,7 +27,7 @@ class TaskJuggler
27
27
  super('tj3ts_summary', 'summary')
28
28
 
29
29
  # This is a LogicalExpression string that controls what resources should
30
- # not be getting a time sheet.
30
+ # not be considered in the summary.
31
31
  @hideResource = '0'
32
32
  # The base directory of the time sheet templates.
33
33
  @templateDir = 'TimeSheetTemplates'
@@ -44,22 +44,23 @@ class TaskJuggler
44
44
  @resourceIntro = " Weekly Report from %s\n\n"
45
45
  @resourceSheetSubject = "Weekly report %s"
46
46
  @summarySubject = "Weekly staff reports %s"
47
- @reminderSubject = "Your weekly report %s is overdue!"
47
+ @reminderSubject = "Your time sheet for the period ending %s is overdue!"
48
48
  @reminderText = <<'EOT'
49
- The deadline for your report submission has passed but we haven't
50
- received it yet. Please submit your report immediately so the content
51
- can still be included in the management reports. Please send a copy
52
- of your submission noticiation email to your manager. If possible,
53
- your manager will still try to include your report data in his/her
54
- report.
49
+ The deadline for your time sheet submission has passed but we haven't received
50
+ it yet. Please submit your time sheet immediately so the content can still be
51
+ included in the management reports. Please send a copy of your submission
52
+ notification email to your manager. If possible, your manager will still try
53
+ to include your report data in his/her report.
55
54
 
56
- Please be aware that post deadline submissions must be processed
57
- manually and create an additional load for your manager and/or
58
- project manager. Please try to submit in time in the future.
55
+ Please be aware that post deadline submissions must be processed manually and
56
+ create an additional load for your manager and/or project manager. Please try
57
+ to submit in time in the future.
59
58
 
60
59
  Thanks for your cooperation!
61
60
 
62
61
  EOT
62
+ @defaulterHeader = "The following %d person(s) have not yet submitted " +
63
+ "their time sheets:\n\n"
63
64
  end
64
65
 
65
66
  def sendSummary(resourceIds)
@@ -77,37 +78,61 @@ EOT
77
78
  sheetFile = "#{@sheetDir}/#{@date}/#{resourceId}_#{@date}.tji"
78
79
  if File.exist?(templateFile)
79
80
  if File.exists?(sheetFile)
80
- # Resource has submitted a time sheet
81
- sheet = getResourceJournal(sheetFile)
82
- summary += sprintf(@resourceIntro, resourceName)
83
- summary += sheet
84
- info("Adding report from #{resourceName} to summary")
85
-
86
- @sheetRecipients.each do |to|
87
- sendEmail(to, sprintf(@resourceSheetSubject, @date), sheet,
88
- nil, resourceEmail)
81
+ # If there are no recipients specified, we don't need to compile
82
+ # the summary.
83
+ unless @digestRecipients.empty? && @sheetRecipients.empty?
84
+ # Resource has submitted a time sheet
85
+ sheet = getResourceJournal(sheetFile)
86
+ summary += sprintf(@resourceIntro, resourceName)
87
+ summary += sheet + "\n#{'-' * 74}\n\n"
88
+ info("Adding report from #{resourceName} to summary")
89
+
90
+ @sheetRecipients.each do |to|
91
+ sendEmail(to, sprintf(@resourceSheetSubject, @date), sheet,
92
+ nil, "#{resourceName} <#{resourceEmail}>")
93
+ end
89
94
  end
90
95
  else
91
96
  defaulterList << resource
92
97
  # Resource did not submit a time sheet
93
- summary += "\n Report from #{resourceName} is missing\n\n"
94
98
  info("Report from #{resourceId} is missing")
95
99
  end
96
- summary += "\n#{'-' * 74}\n\n"
97
100
  end
98
101
  end
99
102
 
100
- # If there is a reminder text defined, resend the template to those
101
- # individuals that have not yet submitted their report yet.
102
- if @reminderText && !@reminderText.empty?
103
+ unless defaulterList.empty?
104
+ # Prepend the defaulter list to the summary.
105
+ text = sprintf(@defaulterHeader, defaulterList.length)
103
106
  defaulterList.each do |resource|
104
- sendReminder(resource[0], resource[1], resource[2])
107
+ text += " * #{resource[1]}\n"
108
+ end
109
+ text += "\n#{'-' * 74}\n\n"
110
+ summary = text + summary
111
+
112
+ # Create a file with the IDs of the resources who's reports are
113
+ # missing.
114
+ missingFile = "#{@sheetDir}/#{@date}/missing-reports"
115
+ begin
116
+ File.open(missingFile, 'w') do |f|
117
+ defaulterList.each { |resource| f.puts resource[0] }
118
+ end
119
+ rescue
120
+ error("Cannot write file with missing reports (#missingFile): #{$!}")
105
121
  end
106
122
  end
107
123
 
124
+ # Send out the summary text to the list of digest recipients.
108
125
  @digestRecipients.each do |to|
109
126
  sendEmail(to, sprintf(@summarySubject, @date), summary)
110
127
  end
128
+
129
+ # If there is a reminder text defined, resend the template to those
130
+ # individuals that have not yet submitted their report yet.
131
+ if @reminderText && !@reminderText.empty?
132
+ defaulterList.each do |resource|
133
+ sendReminder(resource[0], resource[1], resource[2])
134
+ end
135
+ end
111
136
  end
112
137
 
113
138
  private
data/lib/TimeSheets.rb CHANGED
@@ -212,7 +212,7 @@ class TaskJuggler
212
212
  resource = @timeSheet.resource
213
213
  project = resource.project
214
214
  scenarioIdx = @timeSheet.scenarioIdx
215
- startIdx = project.dateToIdx(project['now'])
215
+ startIdx = project.dateToIdx(project['now'], true)
216
216
  endIdx = project.dateToIdx(@task['end', scenarioIdx])
217
217
  remainingWork = @task.getEffectiveWork(scenarioIdx, startIdx, endIdx,
218
218
  resource)
data/lib/Tj3AppBase.rb CHANGED
@@ -55,6 +55,9 @@ class TaskJuggler
55
55
  format("Don't show program and progress information")) do
56
56
  @silent = true
57
57
  end
58
+ @opts.on('--debug', format('Enable Ruby debug mode')) do
59
+ $DEBUG = true
60
+ end
58
61
 
59
62
  yield
60
63
 
@@ -81,13 +84,17 @@ class TaskJuggler
81
84
 
82
85
  def main
83
86
  # Install signal handler to exit gracefully on CTRL-C.
84
- Kernel.trap('INT') do
87
+ intHandler = Kernel.trap('INT') do
85
88
  puts "\nAborting on user request!"
86
89
  exit 1
87
90
  end
88
91
 
89
92
  args = processArguments(ARGV)
90
93
 
94
+ # If DEBUG mode has been enabled, we restore the INT trap handler again
95
+ # to get Ruby backtrackes.
96
+ Kernel.trap('INT', intHandler) if $DEBUG
97
+
91
98
  unless @silent
92
99
  puts "#{AppConfig.softwareName} v#{AppConfig.version} - " +
93
100
  "#{AppConfig.packageInfo}\n\n" +
data/lib/Tj3Config.rb CHANGED
@@ -13,7 +13,7 @@
13
13
  require 'UTF8String'
14
14
  require 'AppConfig'
15
15
 
16
- AppConfig.version = '0.0.5'
16
+ AppConfig.version = '0.0.6'
17
17
  AppConfig.packageName = 'taskjuggler'
18
18
  AppConfig.softwareName = 'TaskJuggler III'
19
19
  AppConfig.packageInfo = 'A Project Management Software'
data/lib/TjTime.rb CHANGED
@@ -348,6 +348,11 @@ class TaskJuggler
348
348
  @time.to_i
349
349
  end
350
350
 
351
+ def to_ary
352
+ to_s
353
+ end
354
+
355
+
351
356
  # Return the abbreviated month name.
352
357
  def shortMonthName
353
358
  @time.strftime('%b')
@@ -56,10 +56,11 @@ EOT
56
56
  @property = @project.accout(@accountprefix)
57
57
  end
58
58
  if @val[1] && @project.account(@val[1])
59
- error('account_exists', "Account #{@val[1]} has already been defined.")
59
+ error('account_exists', "Account #{@val[1]} has already been defined.",
60
+ @property, @sourceFileInfo[1])
60
61
  end
61
62
  @property = Account.new(@project, @val[1], @val[2], @property)
62
- @property.sourceFileInfo = @scanner.sourceFileInfo
63
+ @property.sourceFileInfo = @sourceFileInfo[0]
63
64
  @property.inheritAttributes
64
65
  @scenarioIdx = 0
65
66
  })
@@ -73,7 +74,8 @@ EOT
73
74
  # In case we have a nested supplement, we need to prepend the parent ID.
74
75
  id = @property.fullId + '.' + id if @property && @property.is_a?(Account)
75
76
  if (account = @project.account(id)).nil?
76
- error('unknown_account', "Unknown account #{id}")
77
+ error('unknown_account', "Unknown account #{id}", nil,
78
+ @sourceFileInfo[0])
77
79
  end
78
80
  account
79
81
  })
@@ -107,7 +109,7 @@ EOT
107
109
  level = @project.alertLevelIndex(@val[0])
108
110
  unless level
109
111
  error('bad_alert', "Unknown alert level #{@val[1]}. Must be " +
110
- 'green, yellow or red')
112
+ 'green, yellow or red', nil, @sourceFileInfo[0])
111
113
  end
112
114
  level
113
115
  })
@@ -171,7 +173,7 @@ EOT
171
173
  pattern(%w( !limits ), lambda {
172
174
  limits = @property['limits', @scenarioIdx] = @val[0]
173
175
  @allocate.candidates.each do |resource|
174
- limits.limits.each_value do |l|
176
+ limits.limits.each do |l|
175
177
  l.resource = resource if resource.leaf?
176
178
  end
177
179
  end
@@ -257,7 +259,7 @@ EOT
257
259
  # Make sure we have a ShiftAssignment for the allocation.
258
260
  if @allocate.shift.nil?
259
261
  @allocate.shift = ShiftAssignments.new
260
- @allocate.shift.setProject(@project)
262
+ @allocate.shift.project = @project
261
263
  end
262
264
 
263
265
  if @val[1].nil?
@@ -270,7 +272,7 @@ EOT
270
272
  addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
271
273
  interval))
272
274
  error('shift_assignment_overlap',
273
- 'Shifts may not overlap each other.')
275
+ 'Shifts may not overlap each other.', nil, @sourceFileInfo[0])
274
276
  end
275
277
  end
276
278
  })
@@ -313,16 +315,18 @@ EOT
313
315
  pattern(%w( _balance !accountId !accountId ), lambda {
314
316
  if @val[1].parent
315
317
  error('cost_acct_no_top',
316
- "The cost account #{@val[1].fullId} is not a top-level account.")
318
+ "The cost account #{@val[1].fullId} is not a top-level account.",
319
+ nil, @sourceFileInfo[1])
317
320
  end
318
321
  if @val[2].parent
319
322
  error('rev_acct_no_top',
320
323
  "The revenue account #{@val[2].fullId} is not a top-level " +
321
- "account.")
324
+ "account.", nil, @sourceFileInfo[2])
322
325
  end
323
326
  if @val[1] == @val[2]
324
327
  error('cost_rev_same',
325
- 'The cost and revenue accounts may not be the same.')
328
+ 'The cost and revenue accounts may not be the same.', nil,
329
+ @sourceFileInfo[1])
326
330
  end
327
331
  [ @val[1], @val[2] ]
328
332
  })
@@ -347,7 +351,8 @@ EOT
347
351
  pattern(%w( _overtime $INTEGER ), lambda {
348
352
  if @val[1] < 0 || @val[1] > 2
349
353
  error('overtime_range',
350
- "Overtime value #{@val[1]} out of range (0 - 2).", @property)
354
+ "Overtime value #{@val[1]} out of range (0 - 2).", @property,
355
+ @sourceFileInfo[1])
351
356
  end
352
357
  @booking.overtime = @val[1]
353
358
  })
@@ -368,7 +373,8 @@ EOT
368
373
  pattern(%w( _sloppy $INTEGER ), lambda {
369
374
  if @val[1] < 0 || @val[1] > 2
370
375
  error('sloppy_range',
371
- "Sloppyness value #{@val[1]} out of range (0 - 2).", @property)
376
+ "Sloppyness value #{@val[1]} out of range (0 - 2).", @property,
377
+ @sourceFileInfo[1])
372
378
  end
373
379
  @booking.sloppy = @val[1]
374
380
  })
@@ -422,7 +428,7 @@ EOT
422
428
  end
423
429
  chargeSet.complete
424
430
  rescue TjException
425
- error('chargeset', $!.message)
431
+ error('chargeset', $!.message, @property, @sourceFileInfo[0])
426
432
  end
427
433
  masterAccounts = []
428
434
  @property['chargeset', @scenarioIdx].each do |set|
@@ -431,7 +437,7 @@ EOT
431
437
  if masterAccounts.include?(chargeSet.master)
432
438
  error('chargeset_master',
433
439
  "All charge sets for this task must have different top-level " +
434
- "accounts.")
440
+ "accounts.", @property, @sourceFileInfo[0])
435
441
  end
436
442
  @property['chargeset', @scenarioIdx] =
437
443
  @property['chargeset', @scenarioIdx] + [ chargeSet ]
@@ -499,7 +505,8 @@ EOT
499
505
  col = @val[0]
500
506
  unless /#[0-9A-Fa-f]{3}/ =~ col || /#[0-9A-Fa-f]{3}/ =~ col
501
507
  error('bad_color',
502
- "Color values must be specified as '#RGB' or '#RRGGBB' values")
508
+ "Color values must be specified as '#RGB' or '#RRGGBB' values",
509
+ nil, @sourceFileInfo[0])
503
510
  end
504
511
  col
505
512
  })
@@ -586,6 +593,18 @@ Specifies an alternative font color for the cells of this column. The
586
593
  logical expression specifies for which cells the color should be used. If
587
594
  multiple fontcolor patterns are provided for a column, the first
588
595
  matching one is used for each cell.
596
+ EOT
597
+ )
598
+
599
+ pattern(%w( _halign !logicalExpression !hAlignment ), lambda {
600
+ @column.hAlign.addPattern(
601
+ CellSettingPattern.new(@val[2], @val[1]))
602
+ })
603
+ doc('halign.column', <<'EOT'
604
+ Specifies the horizontal alignment of the cell content. The logical expression
605
+ specifies for which cells the alignment setting should be used. If multiple
606
+ halign patterns are provided for a column, the first matching one is used for
607
+ each cell.
589
608
  EOT
590
609
  )
591
610
 
@@ -666,7 +685,8 @@ EOT
666
685
  if @val[0] % resolution != 0
667
686
  error('misaligned_date',
668
687
  "The date must be aligned to the timing resolution (" +
669
- "#{resolution / 60} min) of the project.")
688
+ "#{resolution / 60} min) of the project.", nil,
689
+ @sourceFileInfo[0])
670
690
  end
671
691
  @val[0]
672
692
  })
@@ -712,11 +732,12 @@ EOT
712
732
 
713
733
  rtTokenSetMore =
714
734
  %w( LINEBREAK SPACE WORD BOLD ITALIC CODE BOLDITALIC PRE HREF HREFEND
715
- REF REFEND HLINE TITLE2 TITLE3 TITLE2END TITLE3END BULLET1 BULLET2
716
- BULLET3 NUMBER1 NUMBER2 NUMBER3 )
735
+ REF REFEND HLINE TITLE2 TITLE3 TITLE4 TITLE2END TITLE3END TITLE4END
736
+ BULLET1 BULLET2 BULLET3 BULLET4 NUMBER1 NUMBER2 NUMBER3 NUMBER4 )
717
737
  if @val[1] == "Some more details\n"
718
738
  error('ts_default_details',
719
- "'Some more details' is not a valid value")
739
+ "'Some more details' is not a valid value", nil,
740
+ @sourceFileInfo[1])
720
741
  end
721
742
  @journalEntry.details = newRichText(@val[1], rtTokenSetMore)
722
743
  })
@@ -773,23 +794,19 @@ EOT
773
794
  @property = nil
774
795
  })
775
796
  doc('export', <<'EOT'
776
- The export report looks like a regular TaskJuggler file but contains fixed
777
- start and end dates for all tasks. The tasks only have start and end times,
778
- their description and their project id listed. No other attributes are
779
- exported unless they are requested using the taskattributes attribute. The
780
- contents also depends on the extension of the file name. If the file name ends
781
- with .tjp a complete project with header, resource and shift definitions is
782
- generated. In case it ends with .tji only the tasks and resource allocations
783
- are exported.
784
-
785
- If specified the resource usage for the tasks is reported as well. But only
786
- those allocations are listed that belong to tasks listed in the same export
787
- report.
797
+ The export report looks like a regular TaskJuggler file with the provided
798
+ input data complemented by the results of the scheduling process. The content
799
+ of the report can be controlled with the [[definitions]] attribute. In case
800
+ the file contains the project header, a ''''.tjp'''' extension is added to the
801
+ file name. Otherwise, a ''''.tji'''' extension is used.
802
+
803
+ The [[resourceattributes]] and [[taskattributes]] attributes provide even more
804
+ control over the content of the file.
788
805
 
789
806
  The export report can be used to share certain tasks or milestones with other
790
807
  projects or to save past resource allocations as immutable part for future
791
808
  scheduling runs. When an export report is included the project IDs of the
792
- included tasks must be declared first with the project id property.`
809
+ included tasks must be declared first with the project id property.
793
810
  EOT
794
811
  )
795
812
  example('Export')
@@ -817,6 +834,8 @@ EOT
817
834
  This attributes controls what definitions will be contained in the report. If
818
835
  the list includes ''project'', the generated file will have a ''''.tjp''''
819
836
  extension. Otherwise it will have a ''''.tji'''' extension.
837
+
838
+ By default, the report contains everything and the generated files has a ''''.tjp'''' extension.
820
839
  EOT
821
840
  )
822
841
  allOrNothingListRule('exportDefinitions',
@@ -946,7 +965,8 @@ EOT
946
965
  pattern(%w( $ID ), lambda {
947
966
  unless (?A..?Z) === @val[0][0]
948
967
  error('extend_id_cap',
949
- "User defined attributes IDs must start with a capital letter")
968
+ "User defined attributes IDs must start with a capital letter",
969
+ nil, @sourceFileInfo[0])
950
970
  end
951
971
  @val[0]
952
972
  })
@@ -1005,7 +1025,7 @@ EOT
1005
1025
  The fail attribute adds a logical expression to the property. The condition
1006
1026
  described by the logical expression is checked after the scheduling and an
1007
1027
  error is raised if the condition evaluates to true. This attribute is
1008
- primarily intended for testing purpuses.
1028
+ primarily intended for testing purposes.
1009
1029
  EOT
1010
1030
  )
1011
1031
  end
@@ -1013,7 +1033,8 @@ EOT
1013
1033
  def rule_flag
1014
1034
  pattern(%w( $ID ), lambda {
1015
1035
  unless @project['flags'].include?(@val[0])
1016
- error('undecl_flag', "Undeclared flag '#{@val[0]}'")
1036
+ error('undecl_flag', "Undeclared flag '#{@val[0]}'", nil,
1037
+ @sourceFileInfo[0])
1017
1038
  end
1018
1039
  @val[0]
1019
1040
  })
@@ -1133,6 +1154,15 @@ EOT
1133
1154
  arg(2, 'Resource ID', 'The ID of a defined resource')
1134
1155
  arg(4, 'Scenario ID', 'A scenario ID')
1135
1156
 
1157
+ pattern(%w( _isfeatureof _( $ID _, $ID _) ))
1158
+ doc('isfeatureof', <<'EOT'
1159
+ If the provided task or any of its sub-tasks depend on this task or any of its
1160
+ sub-tasks, we call this task a feature of the provided task.
1161
+ EOT
1162
+ )
1163
+ arg(2, 'Task ID', 'The ID of a defined task')
1164
+ arg(4, 'Scenario ID', 'A scenario ID')
1165
+
1136
1166
  pattern(['_isleaf', '_(', '_)' ])
1137
1167
  doc('isleaf', 'The result is true if the property is not a container.')
1138
1168
 
@@ -1158,6 +1188,23 @@ EOT
1158
1188
  )
1159
1189
  end
1160
1190
 
1191
+ def rule_hAlignment
1192
+ pattern(%w( _center ), lambda {
1193
+ :center
1194
+ })
1195
+ doc('halign.center', 'Center the cell content')
1196
+
1197
+ pattern(%w( _left ), lambda {
1198
+ :left
1199
+ })
1200
+ doc('halign.left', 'Left align the cell content')
1201
+
1202
+ pattern(%w( _right ), lambda {
1203
+ :right
1204
+ })
1205
+ doc('halign.right', 'Right align the cell content')
1206
+ end
1207
+
1161
1208
  def rule_headline
1162
1209
  pattern(%w( _headline $STRING ), lambda {
1163
1210
  @property.set('headline', newRichText(@val[1]))
@@ -1183,6 +1230,7 @@ report is sorted in tree mode (default) then enclosing resources are listed
1183
1230
  even if the expression matches the resource.
1184
1231
  EOT
1185
1232
  )
1233
+ also(%w( sortresources ))
1186
1234
  end
1187
1235
 
1188
1236
  def rule_hidetask
@@ -1195,6 +1243,7 @@ report is sorted in tree mode (default) then enclosing tasks are listed even
1195
1243
  if the expression matches the task.
1196
1244
  EOT
1197
1245
  )
1246
+ also(%w( sorttasks ))
1198
1247
  end
1199
1248
 
1200
1249
  def rule_idOrAbsoluteId
@@ -1256,7 +1305,7 @@ EOT
1256
1305
 
1257
1306
  def rule_includeFile
1258
1307
  pattern(%w( !includeFileName ), lambda {
1259
- @scanner.include(@val[0])
1308
+ @scanner.include(@val[0], @sourceFileInfo[0])
1260
1309
  })
1261
1310
  end
1262
1311
 
@@ -1264,7 +1313,8 @@ EOT
1264
1313
  pattern(%w( $STRING ), lambda {
1265
1314
  unless @val[0][-4, 4] == '.tji'
1266
1315
  error('bad_include_suffix', "Included files must have a '.tji'" +
1267
- "extension: '#{@val[0]}'")
1316
+ "extension: '#{@val[0]}'",
1317
+ nil, @sourceFileInfo[0])
1268
1318
  end
1269
1319
  @val[0]
1270
1320
  })
@@ -1279,7 +1329,7 @@ EOT
1279
1329
  def rule_includeProperties
1280
1330
  pattern(%w( !includeFileName !includeAttributes ), lambda {
1281
1331
  pushFileStack
1282
- @scanner.include(@val[0])
1332
+ @scanner.include(@val[0], @sourceFileInfo[0])
1283
1333
  })
1284
1334
  end
1285
1335
 
@@ -1291,7 +1341,7 @@ EOT
1291
1341
  if mode == 0
1292
1342
  unless @val[0] < endSpec
1293
1343
  error('start_before_end', "The end date (#{endSpec}) must be " +
1294
- "after the start date (#{@val[0]}).")
1344
+ "after the start date (#{@val[0]}).", nil, @sourceFileInfo[0])
1295
1345
  end
1296
1346
  Interval.new(@val[0], endSpec)
1297
1347
  else
@@ -1322,7 +1372,7 @@ EOT
1322
1372
  if mode == 0
1323
1373
  unless @val[0] < endSpec
1324
1374
  error('start_before_end', "The end date (#{endSpec}) must be after " +
1325
- "the start date (#{@val[0]}).")
1375
+ "the start date (#{@val[0]}).", nil, @sourceFileInfo[0])
1326
1376
  end
1327
1377
  Interval.new(@val[0], endSpec)
1328
1378
  else
@@ -1352,7 +1402,8 @@ EOT
1352
1402
  60 * 60 * 24 * 365 # years
1353
1403
  ]
1354
1404
  if @val[0] == 0.0
1355
- error('zero_duration', "The interval duration may not be 0.")
1405
+ error('zero_duration', "The interval duration may not be 0.", nil,
1406
+ @sourceFileInfo[1])
1356
1407
  end
1357
1408
  duration = @val[0] * convFactors[@val[1]]
1358
1409
  resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
@@ -1363,7 +1414,7 @@ EOT
1363
1414
  end
1364
1415
 
1365
1416
  def rule_intervalEnd
1366
- pattern([ '_ - ', '!date' ], lambda {
1417
+ pattern([ '_-', '!date' ], lambda {
1367
1418
  [ 0, @val[1] ]
1368
1419
  })
1369
1420
 
@@ -1374,7 +1425,7 @@ EOT
1374
1425
 
1375
1426
  def rule_intervalOptionalEnd
1376
1427
  optional
1377
- pattern([ '_ - ', '!date' ], lambda {
1428
+ pattern([ '_-', '!date' ], lambda {
1378
1429
  [ 0, @val[1] ]
1379
1430
  })
1380
1431
 
@@ -1421,7 +1472,7 @@ EOT
1421
1472
  level = @project.alertLevelIndex(@val[1])
1422
1473
  unless level
1423
1474
  error('bad_alert', "Unknown alert level #{@val[1]}. Must be " +
1424
- 'green, yellow or red')
1475
+ 'green, yellow or red', nil, @sourceFileInfo[0])
1425
1476
  end
1426
1477
  @journalEntry.alertLevel = level
1427
1478
  })
@@ -1451,7 +1502,7 @@ EOT
1451
1502
  def rule_journalEntryHeader
1452
1503
  pattern(%w( _journalentry !valDate $STRING ), lambda {
1453
1504
  @journalEntry = JournalEntry.new(@project['journal'], @val[1], @val[2],
1454
- @property, @scanner.sourceFileInfo)
1505
+ @property, @sourceFileInfo[0])
1455
1506
  })
1456
1507
  arg(2, 'headline', <<'EOT'
1457
1508
  The headline of the journal entry. It will be interpreted as
@@ -1464,7 +1515,7 @@ EOT
1464
1515
  resource = @val[0]
1465
1516
  unless resource.leaf?
1466
1517
  error('leaf_resource_id_expected',
1467
- "#{resource.id} is not a leaf resource.")
1518
+ "#{resource.id} is not a leaf resource.", nil, @sourceFileInfo[0])
1468
1519
  end
1469
1520
  resource
1470
1521
  })
@@ -1711,7 +1762,7 @@ EOT
1711
1762
  if @scanner.macroDefined?(@val[1])
1712
1763
  warning('marco_redefinition', "Redefining macro #{@val[1]}")
1713
1764
  end
1714
- @scanner.addMacro(Macro.new(@val[1], @val[2], @scanner.sourceFileInfo))
1765
+ @scanner.addMacro(Macro.new(@val[1], @val[2], @sourceFileInfo[0]))
1715
1766
  })
1716
1767
  doc('macro', <<'EOT'
1717
1768
  Defines a text fragment that can later be inserted by using the specified ID.
@@ -1730,14 +1781,17 @@ numbers as names. The number specifies the index of the argument.
1730
1781
  macro FOO [ This ${1} text ]
1731
1782
 
1732
1783
  will expand to ''''This stupid text'''' if called as ''''${FOO "stupid"}''''.
1733
- Macros may call other macros.
1784
+ Macros may call other macros. All macro arguments must be enclosed by double
1785
+ quotes. In case the argument contains a double quote, it must be escaped by a
1786
+ slash (''''/'''').
1734
1787
 
1735
1788
  User defined macro IDs must have at least one uppercase letter as all
1736
1789
  lowercase letter IDs are reserved for built-in macros.
1737
1790
 
1738
- Macro definitions may contain ''''<nowiki>]</nowiki>'''' as long as each
1739
- ''''<nowiki>]</nowiki>'''' is preceeded by a corresponding
1740
- ''''<nowiki>[</nowiki>''''.
1791
+ To terminate the macro definition, the ''''<nowiki>]</nowiki>'''' must be the
1792
+ last character in the line. If there are any other characters trailing it
1793
+ (even spaces or comments) the ''''<nowiki>]</nowiki>'''' will not be
1794
+ considered the end of the macro definition.
1741
1795
 
1742
1796
  In macro calls the macro names can be prefixed by a question mark. In this
1743
1797
  case the macro will expand to nothing if the macro is not defined. Otherwise
@@ -1840,7 +1894,8 @@ EOT
1840
1894
  pattern(%w( _navigator $ID ), lambda {
1841
1895
  if @project['navigators'][@val[1]]
1842
1896
  error('navigator_exists',
1843
- "The navigator #{@val[1]} has already been defined.")
1897
+ "The navigator #{@val[1]} has already been defined.", nil,
1898
+ @sourceFileInfo[0])
1844
1899
  end
1845
1900
  @navigator = Navigator.new(@val[1], @project)
1846
1901
  })
@@ -1893,6 +1948,49 @@ EOT
1893
1948
  example('Niku')
1894
1949
  end
1895
1950
 
1951
+ def rule_nodeId
1952
+ pattern(%w( !idOrAbsoluteId !subNodeId ), lambda {
1953
+ case @property.typeSpec
1954
+ when :taskreport
1955
+ if (p1 = @project.task(@val[0])).nil?
1956
+ error('unknown_main_node',
1957
+ "Unknown task ID #{@val[0]}", nil, @sourceFileInfo[0])
1958
+ end
1959
+ if @val[1]
1960
+ if (p2 = @project.resource(@val[1])).nil?
1961
+ error('unknown_sub_node',
1962
+ "Unknown resource ID #{@val[0]}", nil, @sourceFileInfo[0])
1963
+ end
1964
+ return [ p2, p1 ]
1965
+ end
1966
+ return [ p1, nil ]
1967
+ when :resourcereport
1968
+ if (p1 = @project.task(@val[0])).nil?
1969
+ error('unknown_main_node',
1970
+ "Unknown task ID #{@val[0]}", nil, @sourceFileInfo[0])
1971
+ end
1972
+ if @val[1]
1973
+ if (p2 = @project.resource(@val[1])).nil?
1974
+ error('unknown_sub_node',
1975
+ "Unknown resource ID #{@val[0]}", nil, @sourceFileInfo[0])
1976
+ end
1977
+ return [ p2, p1 ]
1978
+ end
1979
+ return [ p1, nil ]
1980
+ end
1981
+
1982
+ raise "Node list is not supported for this report type: " +
1983
+ "#{@property.typeSpec}"
1984
+ })
1985
+ end
1986
+
1987
+ def rule_nodeIdList
1988
+ listRule('moreNodeIdList', '!nodeId')
1989
+ pattern([ '_-' ], lambda {
1990
+ []
1991
+ })
1992
+ end
1993
+
1896
1994
  def rule_number
1897
1995
  singlePattern('$INTEGER')
1898
1996
  singlePattern('$FLOAT')
@@ -1911,12 +2009,13 @@ EOT
1911
2009
  pattern(%w( $ABSOLUTE_ID ), lambda {
1912
2010
  if @val[0].count('.') > 1
1913
2011
  error('operand_attribute',
1914
- 'Attributes must be specified as <scenarioID>.<attribute>')
2012
+ 'Attributes must be specified as <scenarioID>.<attribute>', nil,
2013
+ @sourceFileInfo[0])
1915
2014
  end
1916
2015
  scenario, attribute = @val[0].split('.')
1917
2016
  if (scenarioIdx = @project.scenarioIdx(scenario)).nil?
1918
- error('operand_unkn_scen',
1919
- "Unknown scenario ID #{scenario}")
2017
+ error('operand_unkn_scen', "Unknown scenario ID #{scenario}", nil,
2018
+ @sourceFileInfo[0])
1920
2019
  end
1921
2020
  LogicalAttribute.new(attribute, scenarioIdx)
1922
2021
  })
@@ -1926,7 +2025,8 @@ EOT
1926
2025
  pattern(%w( $ID !argumentList ), lambda {
1927
2026
  if @val[1].nil?
1928
2027
  unless @project['flags'].include?(@val[0])
1929
- error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'")
2028
+ error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'",
2029
+ nil, @sourceFileInfo[0])
1930
2030
  end
1931
2031
  LogicalFlag.new(@val[0])
1932
2032
  else
@@ -1966,10 +2066,10 @@ EOT
1966
2066
  arg(0, 'operand', <<'EOT'
1967
2067
  An operand can consist of a date, a text string, a [[functions|function]], a
1968
2068
  property attribute or a numerical value. It can also be the name of a declared
1969
- flag. Use the scenario.attribute notation to use an attribute of the currently
1970
- evaluated property. The scenario ID always has to be specified, also for
1971
- non-scenario specific attributes. This is necessary to distinguish them from
1972
- flags.
2069
+ flag. Use the ''''scenario_id.attribute'''' notation to use an attribute of the
2070
+ currently evaluated property. The scenario ID always has to be specified, also
2071
+ for non-scenario specific attributes. This is necessary to distinguish them
2072
+ from flags.
1973
2073
 
1974
2074
  An operand can be a negated operand by prefixing a ~ charater or it can be
1975
2075
  another logical expression enclosed in braces.
@@ -2087,11 +2187,11 @@ EOT
2087
2187
 
2088
2188
  def rule_plusOrMinus
2089
2189
  singlePattern('_+')
2090
- singlePattern('_ - ')
2190
+ singlePattern('_-')
2091
2191
  end
2092
2192
 
2093
2193
  def rule_project
2094
- pattern(%w( !projectProlog !projectDeclaration !properties ), lambda {
2194
+ pattern(%w( !projectProlog !projectDeclaration !properties . ), lambda {
2095
2195
  @val[1]
2096
2196
  })
2097
2197
  end
@@ -2132,8 +2232,9 @@ EOT
2132
2232
  Set the average number of working hours per day. This is used as
2133
2233
  the base to convert working hours into working days. This affects
2134
2234
  for example the length task attribute. The default value is 8 hours
2135
- and should work for most Western countries. The value you specify
2136
- should match the settings you specified for workinghours.
2235
+ and should work for most Western countries. The value you specify should match
2236
+ the settings you specified as your default [[workinghours.project|working
2237
+ hours]].
2137
2238
  EOT
2138
2239
  )
2139
2240
  example('Project')
@@ -2161,9 +2262,9 @@ EOT
2161
2262
  pattern(%w( _now !date ), lambda {
2162
2263
  @project['now'] = @val[1]
2163
2264
  @scanner.addMacro(Macro.new('now', @val[1].to_s,
2164
- @scanner.sourceFileInfo))
2265
+ @sourceFileInfo[0]))
2165
2266
  @scanner.addMacro(Macro.new('today', @val[1].to_s(@project['timeFormat']),
2166
- @scanner.sourceFileInfo))
2267
+ @sourceFileInfo[0]))
2167
2268
  })
2168
2269
  doc('now', <<'EOT'
2169
2270
  Specify the date that TaskJuggler uses for calculation as current
@@ -2208,12 +2309,14 @@ EOT
2208
2309
  goodValues = [ 5, 10, 15, 20, 30, 60 ]
2209
2310
  unless goodValues.include?(@val[1])
2210
2311
  error('bad_timing_res',
2211
- "Timing resolution must be one of #{goodValues.join(', ')} min.")
2312
+ "Timing resolution must be one of #{goodValues.join(', ')} min.",
2313
+ nil, @sourceFileInfo[1])
2212
2314
  end
2213
2315
  if @val[1] > (Project.maxScheduleGranularity / 60)
2214
2316
  error('too_large_timing_res',
2215
2317
  'The maximum allowed timing resolution for the timezone is ' +
2216
- "#{Project.maxScheduleGranularity / 60} minutes.")
2318
+ "#{Project.maxScheduleGranularity / 60} minutes.", nil,
2319
+ @sourceFileInfo[1])
2217
2320
  end
2218
2321
  @project['scheduleGranularity'] = @val[1] * 60
2219
2322
  })
@@ -2283,6 +2386,7 @@ EOT
2283
2386
  @messageHandler)
2284
2387
  @project['start'] = @val[4].start
2285
2388
  @project['end'] = @val[4].end
2389
+ @projectId = @val[1]
2286
2390
  setGlobalMacros
2287
2391
  @property = nil
2288
2392
  @reportCounter = 0
@@ -2381,10 +2485,12 @@ EOT
2381
2485
 
2382
2486
  def rule_properties
2383
2487
  pattern(%w( !propertiesBody . ))
2488
+ lastSyntaxToken(1)
2384
2489
  end
2385
2490
 
2386
2491
  def rule_propertiesBody
2387
2492
  repeatable
2493
+ optional
2388
2494
 
2389
2495
  pattern(%w( !account ))
2390
2496
 
@@ -2435,7 +2541,7 @@ EOT
2435
2541
  pattern(%w( _projectid $ID ), lambda {
2436
2542
  @project['projectids'] << @val[1]
2437
2543
  @project['projectids'].uniq!
2438
- @project['projectid'] = @val[1]
2544
+ @project['projectid'] = @projectId = @val[1]
2439
2545
  })
2440
2546
  doc('projectid', <<'EOT'
2441
2547
  This declares a new project id and activates it. All subsequent
@@ -2511,7 +2617,6 @@ EOT
2511
2617
  pattern(%w( _include !includeProperties !properties ), lambda {
2512
2618
  popFileStack
2513
2619
  })
2514
- lastSyntaxToken(1)
2515
2620
  doc('include.properties', <<'EOT'
2516
2621
  Includes the specified file name as if its contents would be written
2517
2622
  instead of the include property. The only exception is the include
@@ -2532,7 +2637,8 @@ EOT
2532
2637
  pattern(%w( _purge $ID ), lambda {
2533
2638
  if (attributeDefinition = @property.attributeDefinition(@val[1])).nil?
2534
2639
  error('purge_unknown_id',
2535
- "#{@val[1]} is not a known attribute for this property")
2640
+ "#{@val[1]} is not a known attribute for this property", nil,
2641
+ @sourceFileInfo[1])
2536
2642
  end
2537
2643
  if attributeDefinition.scenarioSpecific
2538
2644
  attr = @property[@val[1], 0]
@@ -2541,7 +2647,8 @@ EOT
2541
2647
  end
2542
2648
  unless attr.is_a?(Array)
2543
2649
  error('purge_no_list',
2544
- "#{@val[1]} is not a list attribute. Only those can be purged.")
2650
+ "#{@val[1]} is not a list attribute. Only those can be purged.",
2651
+ nil, @sourceFileInfo[1])
2545
2652
  end
2546
2653
  if attributeDefinition.scenarioSpecific
2547
2654
  @property[@val[1], @scenarioIdx] = attributeDefinition.default.dup
@@ -2620,17 +2727,19 @@ properties.
2620
2727
  EOT
2621
2728
  )
2622
2729
 
2623
- singlePattern('_alertmessage')
2730
+ singlePattern('_alertmessages')
2624
2731
  descr(<<'EOT'
2625
2732
  The headlines, the summary and the details of the message from the journal
2626
- entries that caused the current alert level for this task.
2733
+ entries that caused the current alert level to be larger than the defaul level
2734
+ for this task or any of its sub tasks.
2627
2735
  EOT
2628
2736
  )
2629
2737
 
2630
- singlePattern('_alertsummary')
2738
+ singlePattern('_alertsummaries')
2631
2739
  descr(<<'EOT'
2632
2740
  The headlines and the summary message from the journal entries that caused the
2633
- current alert level for this task.
2741
+ current alert level to be larger than the default for this task or any of its
2742
+ sub tasks.
2634
2743
  EOT
2635
2744
  )
2636
2745
 
@@ -2754,6 +2863,20 @@ EOT
2754
2863
  singlePattern('_journal')
2755
2864
  descr(<<'EOT'
2756
2865
  The journal entries for the task or resource for the reported interval.
2866
+ EOT
2867
+ )
2868
+
2869
+ singlePattern('_journalmessages')
2870
+ descr(<<'EOT'
2871
+ The headlines, the summary and the details of the message from the journal
2872
+ entries that caused the current alert level for this task.
2873
+ EOT
2874
+ )
2875
+
2876
+ singlePattern('_journalsummaries')
2877
+ descr(<<'EOT'
2878
+ The headlines and the summary message from the journal entries that caused the
2879
+ current alert level for this task.
2757
2880
  EOT
2758
2881
  )
2759
2882
 
@@ -2788,7 +2911,7 @@ EOT
2788
2911
  descr('The criticalness of the task with respect to all the paths that ' +
2789
2912
  'it is a part of.')
2790
2913
 
2791
- singlePattern('_precursor')
2914
+ singlePattern('_precursors')
2792
2915
  descr(<<EOT
2793
2916
  A list of tasks the current task depends on. The list contains the names, the
2794
2917
  IDs, the date and the type of dependency. For the type the following symbols
@@ -2979,6 +3102,11 @@ EOT
2979
3102
  )
2980
3103
  also(%w( epilog footer header ))
2981
3104
 
3105
+ pattern(%w( _opennodes !nodeIdList ), lambda {
3106
+ @property.set('openNodes', @val[1])
3107
+ })
3108
+ doc('opennods', 'For internal use only!')
3109
+
2982
3110
  pattern(%w( !report ))
2983
3111
 
2984
3112
  pattern(%w( _right $STRING ), lambda {
@@ -3046,7 +3174,8 @@ EOT
3046
3174
  pattern(%w( _end !date ), lambda {
3047
3175
  if @val[1] < @property.get('start')
3048
3176
  error('report_end',
3049
- "End date must be before start date #{@property.get('start')}")
3177
+ "End date must be before start date #{@property.get('start')}",
3178
+ nil, @sourceFileInfo[1])
3050
3179
  end
3051
3180
  @property.set('end', @val[1])
3052
3181
  })
@@ -3067,7 +3196,8 @@ EOT
3067
3196
  end
3068
3197
  # In case we have a nested supplement, we need to prepend the parent ID.
3069
3198
  if (report = @project.report(id)).nil?
3070
- error('report_id_expected', "#{id} is not a defined report.")
3199
+ error('report_id_expected', "#{id} is not a defined report.", nil,
3200
+ @sourceFileInfo[0])
3071
3201
  end
3072
3202
  report
3073
3203
  })
@@ -3095,7 +3225,8 @@ EOT
3095
3225
  pattern(%w( _start !date ), lambda {
3096
3226
  if @val[1] > @property.get('end')
3097
3227
  error('report_start',
3098
- "Start date must be before end date #{@property.get('end')}")
3228
+ "Start date must be before end date #{@property.get('end')}",
3229
+ nil, @sourceFileInfo[1])
3099
3230
  end
3100
3231
  @property.set('start', @val[1])
3101
3232
  })
@@ -3118,11 +3249,12 @@ EOT
3118
3249
  if @val[1]
3119
3250
  id = (@property ? @property.fullId + '.' : '') + @val[1]
3120
3251
  if @project.report(id)
3121
- error('report_exists', "report #{id} has already been defined.")
3252
+ error('report_exists', "report #{id} has already been defined.",
3253
+ @property, @sourceFileInfo[1])
3122
3254
  end
3123
3255
  end
3124
3256
  @property = Report.new(@project, @val[1], @val[2], @property)
3125
- @property.sourceFileInfo = @scanner.sourceFileInfo
3257
+ @property.sourceFileInfo = @sourceFileInfo[0]
3126
3258
  @property.inheritAttributes
3127
3259
  case @val[0]
3128
3260
  when 'taskreport'
@@ -3303,7 +3435,7 @@ EOT
3303
3435
  pattern(%w( !taskId !valIntervals ), lambda {
3304
3436
  checkBooking(@val[0], @property)
3305
3437
  @booking = Booking.new(@property, @val[0], @val[1])
3306
- @booking.sourceFileInfo = @scanner.sourceFileInfo
3438
+ @booking.sourceFileInfo = @sourceFileInfo[0]
3307
3439
  @booking
3308
3440
  })
3309
3441
  arg(0, 'id', 'Absolute ID of a defined task')
@@ -3313,7 +3445,8 @@ EOT
3313
3445
  pattern(%w( $ID ), lambda {
3314
3446
  id = (@resourceprefix.empty? ? '' : @resourceprefix + '.') + @val[0]
3315
3447
  if (resource = @project.resource(id)).nil?
3316
- error('resource_id_expected', "#{id} is not a defined resource.")
3448
+ error('resource_id_expected', "#{id} is not a defined resource.",
3449
+ nil, @sourceFileInfo[0])
3317
3450
  end
3318
3451
  resource
3319
3452
  })
@@ -3326,10 +3459,12 @@ EOT
3326
3459
  @property = @project.resource(@resourceprefix)
3327
3460
  end
3328
3461
  if @val[1] && @project.resource(@val[1])
3329
- error('resource_exists', "Resource #{@val[1]} has already been defined.")
3462
+ error('resource_exists',
3463
+ "Resource #{@val[1]} has already been defined.", @property,
3464
+ @sourceFileInfo[1])
3330
3465
  end
3331
3466
  @property = Resource.new(@project, @val[1], @val[2], @property)
3332
- @property.sourceFileInfo = @scanner.sourceFileInfo
3467
+ @property.sourceFileInfo = @sourceFileInfo[0]
3333
3468
  @property.inheritAttributes
3334
3469
  @scenarioIdx = 0
3335
3470
  })
@@ -3443,8 +3578,8 @@ EOT
3443
3578
  doc('shifts.resource', <<'EOT'
3444
3579
  Limits the working time of a resource to a defined shift during the specified
3445
3580
  interval. Multiple shifts can be defined, but shift intervals may not overlap.
3446
- Outside of the defined shift intervals the resource uses its normal working
3447
- hours and vacations.
3581
+ In case a shift is defined for a certain interval, the shift working hours
3582
+ replace the standard resource working hours for this interval.
3448
3583
  EOT
3449
3584
  )
3450
3585
 
@@ -3555,7 +3690,9 @@ EOT
3555
3690
  # first.
3556
3691
  @project.scenarios.clearProperties if @property.nil?
3557
3692
  if @project.scenario(@val[1])
3558
- error('scenario_exists', "Scenario #{@val[1]} has already been defined.")
3693
+ error('scenario_exists',
3694
+ "Scenario #{@val[1]} has already been defined.", nil,
3695
+ @sourceFileInfo[1])
3559
3696
  end
3560
3697
  @property = Scenario.new(@project, @val[1], @val[2], @property)
3561
3698
  @property.inheritAttributes
@@ -3567,7 +3704,8 @@ EOT
3567
3704
  def rule_scenarioId
3568
3705
  pattern(%w( $ID ), lambda {
3569
3706
  if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
3570
- error('unknown_scenario_id', "Unknown scenario: #{@val[0]}")
3707
+ error('unknown_scenario_id', "Unknown scenario: #{@val[0]}", nil,
3708
+ @sourceFileInfo[0])
3571
3709
  end
3572
3710
  @scenarioIdx
3573
3711
  })
@@ -3577,7 +3715,8 @@ EOT
3577
3715
  def rule_scenarioIdCol
3578
3716
  pattern(%w( $ID_WITH_COLON ), lambda {
3579
3717
  if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
3580
- error('unknown_scenario_id', "Unknown scenario: @val[0]")
3718
+ error('unknown_scenario_id', "Unknown scenario: @val[0]", nil,
3719
+ @sourceFileInfo[0])
3581
3720
  end
3582
3721
  })
3583
3722
  end
@@ -3589,7 +3728,8 @@ EOT
3589
3728
  def rule_scenarioIdx
3590
3729
  pattern(%w( $ID ), lambda {
3591
3730
  if (scenarioIdx = @project.scenarioIdx(@val[0])).nil?
3592
- error('unknown_scenario_idx', "Unknown scenario #{@val[0]}")
3731
+ error('unknown_scenario_idx', "Unknown scenario #{@val[0]}", nil,
3732
+ @sourceFileInfo[0])
3593
3733
  end
3594
3734
  scenarioIdx
3595
3735
  })
@@ -3613,6 +3753,7 @@ Shifts have a global name space. All IDs must be unique within the shifts of
3613
3753
  the project.
3614
3754
  EOT
3615
3755
  )
3756
+ also(%w( shifts.task shifts.resource ))
3616
3757
  end
3617
3758
 
3618
3759
  def rule_shiftAssignment
@@ -3620,7 +3761,7 @@ EOT
3620
3761
  # Make sure we have a ShiftAssignment for the property.
3621
3762
  if @property['shifts', @scenarioIdx].nil?
3622
3763
  @property['shifts', @scenarioIdx] = ShiftAssignments.new
3623
- @property['shifts', @scenarioIdx].setProject(@project)
3764
+ @property['shifts', @scenarioIdx].project = @project
3624
3765
  end
3625
3766
 
3626
3767
  if @val[1].nil?
@@ -3633,7 +3774,8 @@ EOT
3633
3774
  addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
3634
3775
  interval))
3635
3776
  error('shift_assignment_overlap',
3636
- 'Shifts may not overlap each other.')
3777
+ 'Shifts may not overlap each other.', @property,
3778
+ @sourceFileInfo[0])
3637
3779
  end
3638
3780
  end
3639
3781
  # Set same value again to set the 'provided' state for the attribute.
@@ -3663,10 +3805,11 @@ EOT
3663
3805
  def rule_shiftHeader
3664
3806
  pattern(%w( _shift !optionalID $STRING ), lambda {
3665
3807
  if @val[1] && @project.shift(@val[1])
3666
- error('shift_exists', "Shift #{@val[1]} has already been defined.")
3808
+ error('shift_exists', "Shift #{@val[1]} has already been defined.",
3809
+ nil, @sourceFileInfo[1])
3667
3810
  end
3668
3811
  @property = Shift.new(@project, @val[1], @val[2], @property)
3669
- @property.sourceFileInfo = @scanner.sourceFileInfo
3812
+ @property.sourceFileInfo = @sourceFileInfo[0]
3670
3813
  @property.inheritAttributes
3671
3814
  @scenarioIdx = 0
3672
3815
  })
@@ -3676,7 +3819,8 @@ EOT
3676
3819
  def rule_shiftId
3677
3820
  pattern(%w( $ID ), lambda {
3678
3821
  if (shift = @project.shift(@val[0])).nil?
3679
- error('shift_id_expected', "#{@val[0]} is not a defined shift.")
3822
+ error('shift_id_expected', "#{@val[0]} is not a defined shift.", nil,
3823
+ @sourceFileInfo[0])
3680
3824
  end
3681
3825
  shift
3682
3826
  })
@@ -3746,33 +3890,38 @@ EOT
3746
3890
  args = @val[0].split('.')
3747
3891
  case args.length
3748
3892
  when 2
3893
+ # <attribute>.<up|down>
3749
3894
  scenario = -1
3750
3895
  direction = args[1] == 'up'
3751
3896
  attribute = args[0]
3752
3897
  when 3
3898
+ # <scenario>.<attribute>.<up|down>
3753
3899
  if (scenario = @project.scenarioIdx(args[0])).nil?
3754
3900
  error('sort_unknown_scen',
3755
- "Unknown scenario #{args[0]} in sorting criterium")
3901
+ "Unknown scenario #{args[0]} in sorting criterium", nil,
3902
+ @sourceFileInfo[0])
3756
3903
  end
3757
3904
  attribute = args[1]
3758
3905
  if args[2] != 'up' && args[2] != 'down'
3759
- error('sort_direction', "Sorting direction must be 'up' or 'down'")
3906
+ error('sort_direction', "Sorting direction must be 'up' or 'down'",
3907
+ nil, @sourceFileInfo[0])
3760
3908
  end
3761
3909
  direction = args[2] == 'up'
3762
3910
  else
3763
3911
  error('sorting_crit_exptd1',
3764
3912
  "Sorting criterium expected (e.g. tree, start.up or " +
3765
- "plan.end.down).")
3913
+ "plan.end.down).", nil, @sourceFileInfo[0])
3766
3914
  end
3767
3915
  if attribute == 'wbs'
3768
3916
  error('sorting_wbs',
3769
3917
  "Sorting by wbs is not supported. Please use 'tree' " +
3770
- '(without appended .up or .down) instead.')
3918
+ '(without appended .up or .down) instead.', nil,
3919
+ @sourceFileInfo[0])
3771
3920
  end
3772
3921
  [ attribute, direction, scenario ]
3773
3922
  })
3774
3923
  arg(0, 'criteria', <<'EOT'
3775
- The soring criteria must consist of a property attribute ID. See [[columnid]]
3924
+ The sorting criteria must consist of a property attribute ID. See [[columnid]]
3776
3925
  for a complete list of available attributes. The ID must be suffixed by '.up'
3777
3926
  or '.down' to determine the sorting direction. Optionally the ID may be
3778
3927
  prefixed with a scenario ID and a dot to determine the scenario that should be
@@ -3812,7 +3961,7 @@ EOT
3812
3961
  if @val[0] != 'tree'
3813
3962
  error('sorting_crit_exptd2',
3814
3963
  "Sorting criterium expected (e.g. tree, start.up or " +
3815
- "plan.end.down).")
3964
+ "plan.end.down).", nil, @sourceFileInfo[0])
3816
3965
  end
3817
3966
  [ 'tree', true, -1 ]
3818
3967
  })
@@ -3825,7 +3974,7 @@ EOT
3825
3974
  if @project.reports[fileName]
3826
3975
  error('report_redefinition',
3827
3976
  "A report with the name '#{fileName}' has already been " +
3828
- "defined.")
3977
+ "defined.", nil, @sourceFileInfo[2])
3829
3978
  end
3830
3979
  else
3831
3980
  fileName = "statusSheet#{@project.reports.length + 1}"
@@ -3883,7 +4032,7 @@ EOT
3883
4032
  pattern(%w( _status !alertLevel $STRING ), lambda {
3884
4033
  @journalEntry = JournalEntry.new(@project['journal'], @sheetEnd,
3885
4034
  @val[2], @property,
3886
- @scanner.sourceFileInfo)
4035
+ @sourceFileInfo[0])
3887
4036
  @journalEntry.alertLevel = @val[1]
3888
4037
  @journalEntry.author = @sheetAuthor
3889
4038
 
@@ -3924,6 +4073,14 @@ EOT
3924
4073
  optionsRule('statusSheetAttributes')
3925
4074
  end
3926
4075
 
4076
+ def rule_statusSheetFile
4077
+ pattern(%w( !statusSheet . ), lambda {
4078
+ @val[0]
4079
+ })
4080
+ lastSyntaxToken(1)
4081
+ end
4082
+
4083
+
3927
4084
  def rule_statusSheetHeader
3928
4085
  pattern(%w( _statussheet !resourceId !valIntervalOrDate ), lambda {
3929
4086
  @sheetAuthor = @val[1]
@@ -3985,6 +4142,14 @@ EOT
3985
4142
  @property = @val[1]
3986
4143
  })
3987
4144
  end
4145
+
4146
+ def rule_subNodeId
4147
+ optional
4148
+ pattern(%w( _: !idOrAbsoluteId ), lambda {
4149
+ @val[1]
4150
+ })
4151
+ end
4152
+
3988
4153
  def rule_summary
3989
4154
  pattern(%w( _summary $STRING ), lambda {
3990
4155
  return if @val[1].empty?
@@ -3992,11 +4157,13 @@ EOT
3992
4157
  if @val[1].length > 480
3993
4158
  error('ts_summary_too_long',
3994
4159
  "The summary text must be 480 characters long or shorter. " +
3995
- "This text has #{@val[1].length} characters.")
4160
+ "This text has #{@val[1].length} characters.",
4161
+ nil, @sourceFileInfo[1])
3996
4162
  end
3997
4163
  if @val[1] == "A summary text\n"
3998
4164
  error('ts_default_summary',
3999
- "'A summary text' is not a valid summary")
4165
+ "'A summary text' is not a valid summary", nil,
4166
+ @sourceFileInfo[1])
4000
4167
  end
4001
4168
  rtTokenSetIntro =
4002
4169
  %w( LINEBREAK SPACE WORD BOLD ITALIC CODE BOLDITALIC HREF HREFEND )
@@ -4130,7 +4297,7 @@ EOT
4130
4297
  pattern(%w( !resourceId !valIntervals ), lambda {
4131
4298
  checkBooking(@property, @val[0])
4132
4299
  @booking = Booking.new(@val[0], @property, @val[1])
4133
- @booking.sourceFileInfo = @scanner.sourceFileInfo
4300
+ @booking.sourceFileInfo = @sourceFileInfo[0]
4134
4301
  @booking
4135
4302
  })
4136
4303
  end
@@ -4215,7 +4382,7 @@ EOT
4215
4382
  end
4216
4383
  error('too_many_bangs',
4217
4384
  "Too many '!' for relative task in this context.",
4218
- @property) if id[0] == ?!
4385
+ @property, @sourceFileInfo[0]) if id[0] == ?!
4219
4386
  if task
4220
4387
  task.fullId + '.' + id
4221
4388
  else
@@ -4245,11 +4412,13 @@ EOT
4245
4412
  if @val[1]
4246
4413
  id = (@property ? @property.fullId + '.' : '') + @val[1]
4247
4414
  if @project.task(id)
4248
- error('task_exists', "Task #{id} has already been defined.")
4415
+ error('task_exists', "Task #{id} has already been defined.", nil,
4416
+ @sourceFileInfo[1])
4249
4417
  end
4250
4418
  end
4251
4419
  @property = Task.new(@project, @val[1], @val[2], @property)
4252
- @property.sourceFileInfo = @scanner.sourceFileInfo
4420
+ @property['projectid', 0] = @projectId
4421
+ @property.sourceFileInfo = @sourceFileInfo[0]
4253
4422
  @property.inheritAttributes
4254
4423
  @scenarioIdx = 0
4255
4424
  })
@@ -4266,7 +4435,7 @@ EOT
4266
4435
  id = @taskprefix + '.' + id unless @taskprefix.empty?
4267
4436
  end
4268
4437
  if (task = @project.task(id)).nil?
4269
- error('unknown_task', "Unknown task #{id}")
4438
+ error('unknown_task', "Unknown task #{id}", nil, @sourceFileInfo[0])
4270
4439
  end
4271
4440
  task
4272
4441
  })
@@ -4331,7 +4500,8 @@ EOT
4331
4500
 
4332
4501
  if @property['chargeset', @scenarioIdx].empty?
4333
4502
  error('task_without_chargeset',
4334
- 'The task does not have a chargeset defined.')
4503
+ 'The task does not have a chargeset defined.', @property,
4504
+ @sourceFileInfo[0])
4335
4505
  end
4336
4506
  case @val[2]
4337
4507
  when 'onstart'
@@ -4368,7 +4538,7 @@ EOT
4368
4538
  pattern(%w( _complete !number), lambda {
4369
4539
  if @val[1] < 0.0 || @val[1] > 100.0
4370
4540
  error('task_complete', "Complete value must be between 0 and 100",
4371
- @property)
4541
+ @property, @sourceFileInfo[1])
4372
4542
  end
4373
4543
  @property['complete', @scenarioIdx] = @val[1]
4374
4544
  })
@@ -4418,7 +4588,8 @@ EOT
4418
4588
  pattern(%w( _effort !workingDuration ), lambda {
4419
4589
  checkContainer('effort')
4420
4590
  if @val[1] <= 0.0
4421
- error('effort_zero', "Effort value must be larger than 0", @property)
4591
+ error('effort_zero', "Effort value must be larger than 0", @property,
4592
+ @sourceFileInfo[1])
4422
4593
  end
4423
4594
  @property['effort', @scenarioIdx] = @val[1]
4424
4595
  })
@@ -4595,7 +4766,7 @@ EOT
4595
4766
  pattern(%w( _priority $INTEGER ), lambda {
4596
4767
  if @val[1] < 0 || @val[1] > 1000
4597
4768
  error('task_priority', "Priority must have a value between 0 and 1000",
4598
- @property)
4769
+ @property, @sourceFileInfo[1])
4599
4770
  end
4600
4771
  @property['priority', @scenarioIdx] = @val[1]
4601
4772
  })
@@ -4620,7 +4791,8 @@ EOT
4620
4791
 
4621
4792
  pattern(%w( _projectid $ID ), lambda {
4622
4793
  unless @project['projectids'].include?(@val[1])
4623
- error('unknown_projectid', "Unknown project ID #{@val[1]}")
4794
+ error('unknown_projectid', "Unknown project ID #{@val[1]}", nil,
4795
+ @sourceFileInfo[1])
4624
4796
  end
4625
4797
  @property['projectid', @scenarioIdx] = @val[1]
4626
4798
  })
@@ -4642,6 +4814,17 @@ EOT
4642
4814
  )
4643
4815
 
4644
4816
  pattern(%w( _scheduled ), lambda {
4817
+ if (@property['milestone', @scenarioIdx] &&
4818
+ @property['start', @scenarioIdx].nil? &&
4819
+ @property['end', @scenarioIdx].nil?) ||
4820
+ (!@property['milestone', @scenarioIdx] &&
4821
+ (@property['start', @scenarioIdx].nil? ||
4822
+ @property['end', @scenarioIdx].nil?))
4823
+ error('not_scheduled',
4824
+ "Task #{@property.fullId} is marked as scheduled but does not " +
4825
+ 'have a fixed start and end date.', @property,
4826
+ @sourceFileInfo[0])
4827
+ end
4645
4828
  @property['scheduled', @scenarioIdx] = true
4646
4829
  })
4647
4830
  doc('scheduled', <<'EOT'
@@ -4875,10 +5058,11 @@ EOT
4875
5058
  end
4876
5059
 
4877
5060
  def rule_timeInterval
4878
- pattern([ '$TIME', '_ - ', '$TIME' ], lambda {
5061
+ pattern([ '$TIME', '_-', '$TIME' ], lambda {
4879
5062
  if @val[0] >= @val[2]
4880
5063
  error('time_interval',
4881
- "End time of interval must be larger than start time")
5064
+ "End time of interval must be larger than start time", nil,
5065
+ @sourceFileInfo[0])
4882
5066
  end
4883
5067
  [ @val[0], @val[2] ]
4884
5068
  })
@@ -4931,7 +5115,10 @@ EOT
4931
5115
  optional
4932
5116
  repeatable
4933
5117
 
4934
- pattern(%w( !tsNewTaskHeader !tsTaskBody ))
5118
+ pattern(%w( !tsNewTaskHeader !tsTaskBody ), lambda {
5119
+ @property = nil
5120
+ @timeSheetRecord = nil
5121
+ })
4935
5122
  doc('newtask', <<'EOT'
4936
5123
  The keyword can be used add a new task to the project. If the task ID requires
4937
5124
  further parent task that don't exist yet, these tasks will be created as well.
@@ -4942,7 +5129,7 @@ EOT
4942
5129
  example('TimeSheet1', '3')
4943
5130
 
4944
5131
  pattern(%w( _shift !shiftId ), lambda {
4945
-
5132
+ #TODO
4946
5133
  })
4947
5134
  doc('shift.timesheet', <<'EOT'
4948
5135
  Specifies an alternative [[shift]] for the time sheet period. This shift will
@@ -4968,6 +5155,13 @@ EOT
4968
5155
  example('TimeSheet1', '4')
4969
5156
  end
4970
5157
 
5158
+ def rule_timeSheetFile
5159
+ pattern(%w( !timeSheet . ), lambda {
5160
+ @val[0]
5161
+ })
5162
+ lastSyntaxToken(1)
5163
+ end
5164
+
4971
5165
  def rule_timeSheetBody
4972
5166
  pattern(%w( _{ !timeSheetAttributes _} ), lambda {
4973
5167
 
@@ -4976,16 +5170,17 @@ EOT
4976
5170
 
4977
5171
  def rule_timeSheetHeader
4978
5172
  pattern(%w( _timesheet !resourceId !valIntervalOrDate ), lambda {
4979
- sheetAuthor = @val[1]
5173
+ @sheetAuthor = @val[1]
4980
5174
  @property = nil
4981
- unless sheetAuthor.leaf?
5175
+ unless @sheetAuthor.leaf?
4982
5176
  error('ts_group_author',
4983
- 'A resource group cannot file a time sheet')
5177
+ 'A resource group cannot file a time sheet', nil,
5178
+ @sourceFileInfo[1])
4984
5179
  end
4985
5180
  # Currently time sheets are hardcoded for scenario 0.
4986
- @timeSheet = TimeSheet.new(sheetAuthor, @val[2],
5181
+ @timeSheet = TimeSheet.new(@sheetAuthor, @val[2],
4987
5182
  @project['trackingScenarioIdx'])
4988
- @timeSheet.sourceFileInfo = @scanner.sourceFileInfo
5183
+ @timeSheet.sourceFileInfo = @sourceFileInfo[0]
4989
5184
  @project.timeSheets << @timeSheet
4990
5185
  })
4991
5186
  end
@@ -5039,7 +5234,7 @@ EOT
5039
5234
  pattern(%w( _newtask !taskIdUnverifd $STRING ), lambda {
5040
5235
  @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @val[1])
5041
5236
  @timeSheetRecord.name = @val[2]
5042
- @timeSheetRecord.sourceFileInfo = @scanner.sourceFileInfo
5237
+ @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
5043
5238
  })
5044
5239
  arg(1, 'task', 'ID of the new task')
5045
5240
  end
@@ -5095,20 +5290,21 @@ EOT
5095
5290
  if @val[2].length > 120
5096
5291
  error('ts_headline_too_long',
5097
5292
  "The headline must be 120 or less characters long. This one " +
5098
- "has #{@val[2].length} characters.")
5293
+ "has #{@val[2].length} characters.", nil, @sourceFileInfo[2])
5099
5294
  end
5100
5295
  if @val[2] == 'Your headline here!'
5101
5296
  error('ts_no_headline',
5102
- "'Your headline here!' is not a valid headline")
5297
+ "'Your headline here!' is not a valid headline", nil,
5298
+ @sourceFileInfo[2])
5103
5299
  end
5104
5300
  @journalEntry = JournalEntry.new(@project['journal'],
5105
5301
  @timeSheet.interval.end,
5106
5302
  @val[2],
5107
5303
  @property || @timeSheet.resource,
5108
- @scanner.sourceFileInfo)
5304
+ @sourceFileInfo[0])
5109
5305
  @journalEntry.alertLevel = @val[1]
5110
5306
  @journalEntry.timeSheetRecord = @timeSheetRecord
5111
- @journalEntry.author = @timeSheet.resource
5307
+ @journalEntry.author = @sheetAuthor
5112
5308
  @timeSheetRecord.status = @journalEntry if @timeSheetRecord
5113
5309
  })
5114
5310
  end
@@ -5135,7 +5331,7 @@ EOT
5135
5331
  if @val[1] < @timeSheet.interval.start
5136
5332
  error('ts_end_too_early',
5137
5333
  "The expected task end date must be after the start date of " +
5138
- "this time sheet report.")
5334
+ "this time sheet report.", nil, @sourceFileInfo[1])
5139
5335
  end
5140
5336
  @timeSheetRecord.expectedEnd = @val[1]
5141
5337
  })
@@ -5150,7 +5346,8 @@ EOT
5150
5346
  priority = @val[1]
5151
5347
  if priority < 1 || priority > 1000
5152
5348
  error('ts_bad_priority',
5153
- "Priority value #{priority} must be between 1 and 1000.")
5349
+ "Priority value #{priority} must be between 1 and 1000.", nil,
5350
+ @sourceFileInfo[1])
5154
5351
  end
5155
5352
  @timeSheetRecord.priority = priority
5156
5353
  })
@@ -5213,14 +5410,15 @@ EOT
5213
5410
  @property = @val[1]
5214
5411
  unless @property.leaf?
5215
5412
  error('ts_task_not_leaf',
5216
- 'You cannot specify a task that has sub tasks here.')
5413
+ 'You cannot specify a task that has sub tasks here.',
5414
+ @property, @sourceFileInfo[1])
5217
5415
  end
5218
5416
  scenarioIdx = @timeSheet.scenarioIdx
5219
5417
  taskStart = @property['start', scenarioIdx] || @project['start']
5220
5418
  taskEnd = @property['end', scenarioIdx] || @project['end']
5221
5419
 
5222
5420
  @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @property)
5223
- @timeSheetRecord.sourceFileInfo = @scanner.sourceFileInfo
5421
+ @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
5224
5422
  })
5225
5423
  arg(1, 'task', 'ID of an already existing task')
5226
5424
  end
@@ -5235,7 +5433,8 @@ EOT
5235
5433
  pattern(%w( !date ), lambda {
5236
5434
  if @val[0] < @project['start'] || @val[0] > @project['end']
5237
5435
  error('date_in_range', "Date must be within the project time frame " +
5238
- "#{@project['start']} + - #{@project['end']}")
5436
+ "#{@project['start']} - #{@project['end']}", nil,
5437
+ @sourceFileInfo[0])
5239
5438
  end
5240
5439
  @val[0]
5241
5440
  })
@@ -5244,7 +5443,8 @@ EOT
5244
5443
  def rule_validTimeZone
5245
5444
  pattern(%w( $STRING ), lambda {
5246
5445
  unless TjTime.checkTimeZone(@val[0])
5247
- error('bad_time_zone', "#{@val[0]} is not a known time zone")
5446
+ error('bad_time_zone', "#{@val[0]} is not a known time zone", nil,
5447
+ @sourceFileInfo[0])
5248
5448
  end
5249
5449
  @val[0]
5250
5450
  })
@@ -5258,7 +5458,8 @@ EOT
5258
5458
  if mode == 0
5259
5459
  unless @val[0] < endSpec
5260
5460
  error('start_before_end', "The end date (#{endSpec}) must be " +
5261
- "after the start date (#{@val[0]}).")
5461
+ "after the start date (#{@val[0]}).", nil,
5462
+ @sourceFileInfo[1])
5262
5463
  end
5263
5464
  iv = Interval.new(@val[0], endSpec)
5264
5465
  else
@@ -5294,7 +5495,7 @@ EOT
5294
5495
  if mode == 0
5295
5496
  unless @val[0] < endSpec
5296
5497
  error('start_before_end', "The end date (#{endSpec}) must be after " +
5297
- "the start date (#{@val[0]}).")
5498
+ "the start date (#{@val[0]}).", nil, @sourceFileInfo[1])
5298
5499
  end
5299
5500
  iv = Interval.new(@val[0], endSpec)
5300
5501
  else
@@ -5330,7 +5531,7 @@ EOT
5330
5531
  The warn attribute adds a logical expression to the property. The condition
5331
5532
  described by the logical expression is checked after the scheduling and an
5332
5533
  warning is generated if the condition evaluates to true. This attribute is
5333
- primarily intended for testing purpuses.
5534
+ primarily intended for testing purposes.
5334
5535
  EOT
5335
5536
  )
5336
5537
  end
@@ -5367,7 +5568,7 @@ EOT
5367
5568
 
5368
5569
  def rule_weekDayIntervalEnd
5369
5570
  optional
5370
- pattern([ '_ - ', '!weekday' ], lambda {
5571
+ pattern([ '_-', '!weekday' ], lambda {
5371
5572
  @val[1]
5372
5573
  })
5373
5574
  arg(1, 'end weekday',
@@ -5409,7 +5610,8 @@ EOT
5409
5610
  # 1.0.
5410
5611
  if @val[0] < 0.0 || @val[0] > 100.0
5411
5612
  error('illegal_percentage',
5412
- "Percentage values must be between 0 and 100%.")
5613
+ "Percentage values must be between 0 and 100%.", nil,
5614
+ @sourceFileInfo[1])
5413
5615
  end
5414
5616
  @val[0] / 100.0
5415
5617
  end
@@ -5441,8 +5643,12 @@ EOT
5441
5643
  Set the default working hours for all subsequent resource definitions.
5442
5644
  The working hours specification limits the availability of resources to
5443
5645
  certain time slots of week days.
5646
+
5647
+ These default working hours can be replaced with other working hours for
5648
+ individual resources.
5444
5649
  EOT
5445
5650
  )
5651
+ also(%w( dailyworkinghours workinghours.resource workinghours.shift ))
5446
5652
  end
5447
5653
 
5448
5654
  def rule_workinghoursResource
@@ -5452,16 +5658,26 @@ Set the working hours for a specific resource. The working hours specification
5452
5658
  limits the availability of resources to certain time slots of week days.
5453
5659
  EOT
5454
5660
  )
5661
+ also(%w( workinghours.project workinghours.shift ))
5455
5662
  end
5456
5663
 
5457
5664
  def rule_workinghoursShift
5458
5665
  pattern(%w( !workinghours ))
5459
5666
  doc('workinghours.shift', <<'EOT'
5460
- Set the default working hours for the shift. The working hours specification
5461
- limits the availability of resources or the activity on a task to certain time
5667
+ Set the working hours for the shift. The working hours specification limits
5668
+ the availability of resources or the activity on a task to certain time
5462
5669
  slots of week days.
5670
+
5671
+ The shift working hours will replace the default or resource working hours for
5672
+ the specified time frame when assigning the shift to a resource.
5673
+
5674
+ In case the shift is used for a task, resources are only assigned during the
5675
+ working hours of this shift and during the working hours of the allocated
5676
+ resource. Allocations only happen when both the task shift and the resource
5677
+ work hours allow work to happen.
5463
5678
  EOT
5464
5679
  )
5680
+ also(%w( workinghours.project workinghours.resource ))
5465
5681
  end
5466
5682
 
5467
5683
  def rule_yesNo