taskjuggler 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (563) hide show
  1. data/CHANGELOG +37 -5
  2. data/README.rdoc +4 -2
  3. data/benchmarks/UTF-8-Strings.rb +58 -0
  4. data/benchmarks/css/tjmanual.css +0 -1
  5. data/benchmarks/htmltaskreport-1.html +47702 -0
  6. data/benchmarks/htmltaskreport-2.html +23345 -0
  7. data/benchmarks/htmltaskreport-3.html +23265 -0
  8. data/benchmarks/htmltaskreport-4.html +22135 -0
  9. data/benchmarks/profile.clt +36082 -0
  10. data/benchmarks/tj3.profile +0 -0
  11. data/benchmarks/tj3.profile.grind +6185 -0
  12. data/benchmarks/tj3.profile.symbols +432 -0
  13. data/benchmarks/tj3.profile.txt +448 -0
  14. data/data/tjp.vim +689 -0
  15. data/doc/AppConfig.html +26 -2
  16. data/doc/CHANGELOG.html +60 -8
  17. data/doc/COPYING.html +26 -2
  18. data/doc/Diff/Hunk.html +26 -2
  19. data/doc/Diff.html +26 -2
  20. data/doc/Diffable.html +26 -2
  21. data/doc/DiffableString.html +26 -2
  22. data/doc/Object.html +26 -104
  23. data/doc/README_rdoc.html +39 -7
  24. data/doc/RuntimeConfig.html +26 -2
  25. data/doc/String.html +26 -2
  26. data/doc/TaskJuggler/Account.html +27 -3
  27. data/doc/TaskJuggler/AccountAttribute.html +30 -6
  28. data/doc/TaskJuggler/AccountScenario.html +28 -4
  29. data/doc/TaskJuggler/Allocation.html +33 -9
  30. data/doc/TaskJuggler/AllocationAttribute.html +31 -7
  31. data/doc/TaskJuggler/AttributeBase.html +162 -111
  32. data/doc/TaskJuggler/AttributeDefinition.html +26 -2
  33. data/doc/TaskJuggler/AttributeOverwrite.html +26 -2
  34. data/doc/TaskJuggler/BatchProcessor.html +26 -2
  35. data/doc/TaskJuggler/Booking.html +29 -5
  36. data/doc/TaskJuggler/BookingListAttribute.html +29 -5
  37. data/doc/TaskJuggler/BooleanAttribute.html +30 -6
  38. data/doc/TaskJuggler/CSVFile.html +26 -2
  39. data/doc/TaskJuggler/CellSettingPattern.html +26 -2
  40. data/doc/TaskJuggler/CellSettingPatternList.html +26 -2
  41. data/doc/TaskJuggler/Charge.html +30 -6
  42. data/doc/TaskJuggler/ChargeListAttribute.html +29 -5
  43. data/doc/TaskJuggler/ChargeSet.html +26 -2
  44. data/doc/TaskJuggler/ChargeSetListAttribute.html +30 -6
  45. data/doc/TaskJuggler/CollisionDetector.html +26 -2
  46. data/doc/TaskJuggler/ColumnListAttribute.html +28 -4
  47. data/doc/TaskJuggler/ColumnTable.html +26 -2
  48. data/doc/TaskJuggler/Daemon.html +26 -2
  49. data/doc/TaskJuggler/DataCache.html +26 -2
  50. data/doc/TaskJuggler/DataCacheEntry.html +26 -2
  51. data/doc/TaskJuggler/DateAttribute.html +30 -6
  52. data/doc/TaskJuggler/DefinitionListAttribute.html +28 -4
  53. data/doc/TaskJuggler/DependencyListAttribute.html +30 -6
  54. data/doc/TaskJuggler/DurationAttribute.html +31 -7
  55. data/doc/TaskJuggler/FileList.html +26 -2
  56. data/doc/TaskJuggler/FileRecord.html +26 -2
  57. data/doc/TaskJuggler/FixnumAttribute.html +28 -4
  58. data/doc/TaskJuggler/FlagListAttribute.html +30 -6
  59. data/doc/TaskJuggler/FloatAttribute.html +29 -5
  60. data/doc/TaskJuggler/FormatListAttribute.html +29 -5
  61. data/doc/TaskJuggler/GanttChart.html +26 -2
  62. data/doc/TaskJuggler/GanttContainer.html +26 -2
  63. data/doc/TaskJuggler/GanttHeader.html +26 -2
  64. data/doc/TaskJuggler/GanttHeaderScaleItem.html +26 -2
  65. data/doc/TaskJuggler/GanttLine.html +27 -3
  66. data/doc/TaskJuggler/GanttLoadStack.html +26 -2
  67. data/doc/TaskJuggler/GanttMilestone.html +26 -2
  68. data/doc/TaskJuggler/GanttRouter.html +26 -2
  69. data/doc/TaskJuggler/GanttTaskBar.html +26 -2
  70. data/doc/TaskJuggler/HTMLDocument.html +26 -2
  71. data/doc/TaskJuggler/HTMLElements.html +623 -0
  72. data/doc/TaskJuggler/HTMLGraphics.html +26 -2
  73. data/doc/TaskJuggler/ICalReport.html +864 -0
  74. data/doc/TaskJuggler/ICalendar/Component.html +969 -0
  75. data/doc/TaskJuggler/ICalendar/Event.html +742 -0
  76. data/doc/TaskJuggler/ICalendar/Journal.html +722 -0
  77. data/doc/TaskJuggler/ICalendar/Person.html +633 -0
  78. data/doc/TaskJuggler/ICalendar/Todo.html +789 -0
  79. data/doc/TaskJuggler/ICalendar.html +1035 -0
  80. data/doc/TaskJuggler/Interval.html +99 -172
  81. data/doc/TaskJuggler/IntervalList.html +31 -7
  82. data/doc/TaskJuggler/JobInfo.html +26 -2
  83. data/doc/TaskJuggler/Journal.html +26 -2
  84. data/doc/TaskJuggler/JournalEntry.html +26 -2
  85. data/doc/TaskJuggler/JournalEntryList.html +26 -2
  86. data/doc/TaskJuggler/KeywordArray.html +26 -2
  87. data/doc/TaskJuggler/KeywordDocumentation.html +26 -2
  88. data/doc/TaskJuggler/Limits/Limit.html +124 -49
  89. data/doc/TaskJuggler/Limits.html +139 -156
  90. data/doc/TaskJuggler/LimitsAttribute.html +39 -14
  91. data/doc/TaskJuggler/ListAttributeBase.html +35 -11
  92. data/doc/TaskJuggler/Log.html +26 -2
  93. data/doc/TaskJuggler/LogFile.html +26 -2
  94. data/doc/TaskJuggler/LogicalAttribute.html +26 -2
  95. data/doc/TaskJuggler/LogicalExpression.html +26 -2
  96. data/doc/TaskJuggler/LogicalExpressionAttribute.html +35 -11
  97. data/doc/TaskJuggler/LogicalExpressionListAttribute.html +35 -11
  98. data/doc/TaskJuggler/LogicalFlag.html +26 -2
  99. data/doc/TaskJuggler/LogicalFunction.html +28 -4
  100. data/doc/TaskJuggler/LogicalOperation.html +26 -2
  101. data/doc/TaskJuggler/ManagerResponsibilities.html +26 -2
  102. data/doc/TaskJuggler/ManagerStatusRecord.html +26 -2
  103. data/doc/TaskJuggler/Message.html +26 -2
  104. data/doc/TaskJuggler/MessageHandler.html +108 -62
  105. data/doc/TaskJuggler/Navigator.html +26 -2
  106. data/doc/TaskJuggler/NavigatorElement.html +26 -2
  107. data/doc/TaskJuggler/NikuProject.html +26 -2
  108. data/doc/TaskJuggler/NikuReport.html +27 -3
  109. data/doc/TaskJuggler/NikuResource.html +26 -2
  110. data/doc/TaskJuggler/NodeListAttribute.html +31 -7
  111. data/doc/TaskJuggler/PlaceHolderCell.html +26 -2
  112. data/doc/TaskJuggler/ProcessIntercom.html +26 -2
  113. data/doc/TaskJuggler/ProcessIntercomIface.html +26 -2
  114. data/doc/TaskJuggler/Project.html +1236 -973
  115. data/doc/TaskJuggler/ProjectBroker.html +26 -2
  116. data/doc/TaskJuggler/ProjectBrokerIface.html +26 -2
  117. data/doc/TaskJuggler/ProjectFileParser.html +29 -4
  118. data/doc/TaskJuggler/ProjectFileScanner.html +56 -31
  119. data/doc/TaskJuggler/ProjectRecord.html +26 -2
  120. data/doc/TaskJuggler/ProjectServer.html +26 -2
  121. data/doc/TaskJuggler/ProjectServerIface.html +26 -2
  122. data/doc/TaskJuggler/PropertyAttribute.html +35 -11
  123. data/doc/TaskJuggler/PropertyList.html +26 -2
  124. data/doc/TaskJuggler/PropertySet.html +126 -106
  125. data/doc/TaskJuggler/PropertyTreeNode.html +595 -551
  126. data/doc/TaskJuggler/Query.html +127 -100
  127. data/doc/TaskJuggler/RTFHandlers.html +26 -2
  128. data/doc/TaskJuggler/RTFNavigator.html +26 -2
  129. data/doc/TaskJuggler/RTFQuery.html +28 -4
  130. data/doc/TaskJuggler/RTFReport.html +26 -2
  131. data/doc/TaskJuggler/RTFReportLink.html +26 -2
  132. data/doc/TaskJuggler/RTFWithQuerySupport.html +26 -2
  133. data/doc/TaskJuggler/RealFormat.html +26 -2
  134. data/doc/TaskJuggler/RealFormatAttribute.html +31 -7
  135. data/doc/TaskJuggler/ReferenceAttribute.html +58 -34
  136. data/doc/TaskJuggler/Report.html +427 -284
  137. data/doc/TaskJuggler/ReportBase.html +28 -102
  138. data/doc/TaskJuggler/ReportContext.html +26 -2
  139. data/doc/TaskJuggler/ReportScenario.html +633 -0
  140. data/doc/TaskJuggler/ReportServer.html +26 -2
  141. data/doc/TaskJuggler/ReportServerIface.html +26 -2
  142. data/doc/TaskJuggler/ReportServerRecord.html +26 -2
  143. data/doc/TaskJuggler/ReportServlet.html +26 -2
  144. data/doc/TaskJuggler/ReportTable.html +26 -2
  145. data/doc/TaskJuggler/ReportTableCell.html +26 -2
  146. data/doc/TaskJuggler/ReportTableColumn.html +26 -2
  147. data/doc/TaskJuggler/ReportTableLegend.html +26 -2
  148. data/doc/TaskJuggler/ReportTableLine.html +26 -2
  149. data/doc/TaskJuggler/Resource.html +225 -163
  150. data/doc/TaskJuggler/ResourceListAttribute.html +71 -47
  151. data/doc/TaskJuggler/ResourceListRE.html +26 -2
  152. data/doc/TaskJuggler/ResourceScenario.html +645 -603
  153. data/doc/TaskJuggler/RichText.html +26 -2
  154. data/doc/TaskJuggler/RichTextAttribute.html +53 -29
  155. data/doc/TaskJuggler/RichTextDocument.html +26 -2
  156. data/doc/TaskJuggler/RichTextElement.html +26 -2
  157. data/doc/TaskJuggler/RichTextFunctionExample.html +26 -2
  158. data/doc/TaskJuggler/RichTextFunctionHandler.html +26 -2
  159. data/doc/TaskJuggler/RichTextImage.html +26 -2
  160. data/doc/TaskJuggler/RichTextIntermediate.html +29 -5
  161. data/doc/TaskJuggler/RichTextParser.html +26 -2
  162. data/doc/TaskJuggler/RichTextScanner.html +26 -2
  163. data/doc/TaskJuggler/RichTextSnip.html +26 -2
  164. data/doc/TaskJuggler/RichTextSyntaxRules.html +26 -2
  165. data/doc/TaskJuggler/Scenario.html +26 -2
  166. data/doc/TaskJuggler/ScenarioData.html +95 -28
  167. data/doc/TaskJuggler/ScenarioListAttribute.html +39 -15
  168. data/doc/TaskJuggler/Scoreboard.html +137 -73
  169. data/doc/TaskJuggler/ScoreboardInterval.html +1116 -0
  170. data/doc/TaskJuggler/SheetHandlerBase.html +26 -2
  171. data/doc/TaskJuggler/SheetReceiver.html +26 -2
  172. data/doc/TaskJuggler/SheetSender.html +26 -2
  173. data/doc/TaskJuggler/Shift.html +27 -3
  174. data/doc/TaskJuggler/ShiftAssignment.html +27 -3
  175. data/doc/TaskJuggler/ShiftAssignments.html +174 -149
  176. data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +41 -16
  177. data/doc/TaskJuggler/ShiftScenario.html +26 -2
  178. data/doc/TaskJuggler/SimpleQueryExpander.html +26 -2
  179. data/doc/TaskJuggler/SortListAttribute.html +35 -11
  180. data/doc/TaskJuggler/StatusSheetReceiver.html +26 -2
  181. data/doc/TaskJuggler/StatusSheetReport.html +26 -2
  182. data/doc/TaskJuggler/StatusSheetSender.html +26 -2
  183. data/doc/TaskJuggler/StdIoWrapper.html +26 -2
  184. data/doc/TaskJuggler/StringAttribute.html +39 -15
  185. data/doc/TaskJuggler/SymbolAttribute.html +35 -11
  186. data/doc/TaskJuggler/SyntaxReference.html +26 -2
  187. data/doc/TaskJuggler/TOCEntry.html +26 -2
  188. data/doc/TaskJuggler/TSResourceRecord.html +26 -2
  189. data/doc/TaskJuggler/TSTaskRecord.html +26 -2
  190. data/doc/TaskJuggler/TableColumnDefinition.html +26 -2
  191. data/doc/TaskJuggler/TableOfContents.html +26 -2
  192. data/doc/TaskJuggler/TableReport.html +239 -214
  193. data/doc/TaskJuggler/TagFile/TagFileEntry.html +841 -0
  194. data/doc/TaskJuggler/TagFile.html +817 -0
  195. data/doc/TaskJuggler/Task.html +27 -3
  196. data/doc/TaskJuggler/TaskDepListAttribute.html +47 -23
  197. data/doc/TaskJuggler/TaskDependency.html +26 -2
  198. data/doc/TaskJuggler/TaskListAttribute.html +47 -23
  199. data/doc/TaskJuggler/TaskListRE.html +26 -2
  200. data/doc/TaskJuggler/TaskScenario.html +2235 -2178
  201. data/doc/TaskJuggler/TernarySearchTree.html +26 -2
  202. data/doc/TaskJuggler/TextFormatter.html +26 -2
  203. data/doc/TaskJuggler/TextParser/Macro.html +26 -2
  204. data/doc/TaskJuggler/TextParser/MacroTable.html +26 -2
  205. data/doc/TaskJuggler/TextParser/Pattern.html +26 -2
  206. data/doc/TaskJuggler/TextParser/Rule.html +26 -2
  207. data/doc/TaskJuggler/TextParser/Scanner/BufferStreamHandle.html +32 -8
  208. data/doc/TaskJuggler/TextParser/Scanner/FileStreamHandle.html +39 -15
  209. data/doc/TaskJuggler/TextParser/Scanner/MacroStackEntry.html +26 -2
  210. data/doc/TaskJuggler/TextParser/Scanner/StreamHandle.html +119 -86
  211. data/doc/TaskJuggler/TextParser/Scanner.html +317 -291
  212. data/doc/TaskJuggler/TextParser/SourceFileInfo.html +26 -2
  213. data/doc/TaskJuggler/TextParser/StackElement.html +26 -2
  214. data/doc/TaskJuggler/TextParser/State.html +26 -2
  215. data/doc/TaskJuggler/TextParser/StateTransition.html +26 -2
  216. data/doc/TaskJuggler/TextParser/TextParserResultArray.html +26 -2
  217. data/doc/TaskJuggler/TextParser/TokenDoc.html +26 -2
  218. data/doc/TaskJuggler/TextParser.html +85 -61
  219. data/doc/TaskJuggler/TextReport.html +26 -2
  220. data/doc/TaskJuggler/TimeInterval.html +841 -0
  221. data/doc/TaskJuggler/{IntervalListAttribute.html → TimeIntervalListAttribute.html} +33 -9
  222. data/doc/TaskJuggler/TimeSheet.html +26 -2
  223. data/doc/TaskJuggler/TimeSheetReceiver.html +26 -2
  224. data/doc/TaskJuggler/TimeSheetRecord.html +27 -3
  225. data/doc/TaskJuggler/TimeSheetReport.html +29 -5
  226. data/doc/TaskJuggler/TimeSheetSender.html +26 -2
  227. data/doc/TaskJuggler/TimeSheetSummary.html +26 -2
  228. data/doc/TaskJuggler/TimeSheets.html +26 -2
  229. data/doc/TaskJuggler/Tj3.html +150 -111
  230. data/doc/TaskJuggler/Tj3AppBase.html +26 -2
  231. data/doc/TaskJuggler/Tj3Client.html +26 -2
  232. data/doc/TaskJuggler/Tj3Daemon.html +26 -2
  233. data/doc/TaskJuggler/Tj3Man.html +26 -2
  234. data/doc/TaskJuggler/Tj3SheetAppBase.html +26 -2
  235. data/doc/TaskJuggler/Tj3SsReceiver.html +26 -2
  236. data/doc/TaskJuggler/Tj3SsSender.html +26 -2
  237. data/doc/TaskJuggler/Tj3TsReceiver.html +26 -2
  238. data/doc/TaskJuggler/Tj3TsSender.html +26 -2
  239. data/doc/TaskJuggler/Tj3TsSummary.html +26 -2
  240. data/doc/TaskJuggler/TjException.html +26 -2
  241. data/doc/TaskJuggler/TjRuntimeError.html +26 -2
  242. data/doc/TaskJuggler/TjTime.html +539 -477
  243. data/doc/TaskJuggler/TjpExample.html +26 -2
  244. data/doc/TaskJuggler/TjpExportRE.html +240 -161
  245. data/doc/TaskJuggler/TjpSyntaxRules.html +4236 -3844
  246. data/doc/TaskJuggler/URLParameter.html +26 -2
  247. data/doc/TaskJuggler/UserManual.html +26 -2
  248. data/doc/TaskJuggler/VimSyntax.html +31 -7
  249. data/doc/TaskJuggler/WebServer.html +26 -2
  250. data/doc/TaskJuggler/WelcomePage.html +26 -2
  251. data/doc/TaskJuggler/WorkingHours.html +227 -152
  252. data/doc/TaskJuggler/WorkingHoursAttribute.html +62 -38
  253. data/doc/TaskJuggler/XMLBlob.html +26 -2
  254. data/doc/TaskJuggler/XMLComment.html +26 -2
  255. data/doc/TaskJuggler/XMLDocument.html +26 -2
  256. data/doc/TaskJuggler/XMLElement.html +26 -2
  257. data/doc/TaskJuggler/XMLNamedText.html +26 -2
  258. data/doc/TaskJuggler/XMLText.html +26 -2
  259. data/doc/TaskJuggler.html +486 -427
  260. data/doc/index.html +801 -659
  261. data/doc/lib/taskjuggler/AccountScenario_rb.html +1 -1
  262. data/doc/lib/taskjuggler/Account_rb.html +1 -1
  263. data/doc/lib/taskjuggler/AlgorithmDiff_rb.html +1 -1
  264. data/doc/lib/taskjuggler/Allocation_rb.html +1 -1
  265. data/doc/lib/taskjuggler/AppConfig_rb.html +1 -1
  266. data/doc/lib/taskjuggler/AttributeBase_rb.html +1 -1
  267. data/doc/lib/taskjuggler/AttributeDefinition_rb.html +1 -1
  268. data/doc/lib/taskjuggler/Attributes_rb.html +1 -1
  269. data/doc/lib/taskjuggler/BatchProcessor_rb.html +1 -1
  270. data/doc/lib/taskjuggler/Booking_rb.html +1 -1
  271. data/doc/lib/taskjuggler/ChargeSet_rb.html +1 -1
  272. data/doc/lib/taskjuggler/Charge_rb.html +1 -1
  273. data/doc/lib/taskjuggler/DataCache_rb.html +1 -1
  274. data/doc/lib/taskjuggler/FileList_rb.html +1 -1
  275. data/doc/lib/taskjuggler/HTMLDocument_rb.html +1 -1
  276. data/doc/lib/{ruby-signal-bug_rb.html → taskjuggler/HTMLElements_rb.html} +9 -9
  277. data/doc/lib/{exchangebug_rb.html → taskjuggler/ICalendar_rb.html} +9 -9
  278. data/doc/lib/taskjuggler/IntervalList_rb.html +1 -1
  279. data/doc/lib/taskjuggler/Interval_rb.html +1 -1
  280. data/doc/lib/taskjuggler/Journal_rb.html +1 -1
  281. data/doc/lib/taskjuggler/KeywordArray_rb.html +1 -1
  282. data/doc/lib/taskjuggler/KeywordDocumentation_rb.html +1 -1
  283. data/doc/lib/taskjuggler/Limits_rb.html +1 -1
  284. data/doc/lib/taskjuggler/LogFile_rb.html +1 -1
  285. data/doc/lib/taskjuggler/Log_rb.html +1 -1
  286. data/doc/lib/taskjuggler/LogicalExpression_rb.html +1 -1
  287. data/doc/lib/taskjuggler/LogicalFunction_rb.html +1 -1
  288. data/doc/lib/taskjuggler/LogicalOperation_rb.html +1 -1
  289. data/doc/lib/taskjuggler/MessageHandler_rb.html +1 -1
  290. data/doc/lib/taskjuggler/ProjectFileParser_rb.html +1 -1
  291. data/doc/lib/taskjuggler/ProjectFileScanner_rb.html +1 -1
  292. data/doc/lib/taskjuggler/Project_rb.html +1 -1
  293. data/doc/lib/taskjuggler/PropertyList_rb.html +1 -1
  294. data/doc/lib/taskjuggler/PropertySet_rb.html +1 -1
  295. data/doc/lib/taskjuggler/PropertyTreeNode_rb.html +1 -1
  296. data/doc/lib/taskjuggler/Query_rb.html +1 -1
  297. data/doc/lib/taskjuggler/RealFormat_rb.html +1 -1
  298. data/doc/lib/taskjuggler/ResourceScenario_rb.html +1 -1
  299. data/doc/lib/taskjuggler/Resource_rb.html +1 -1
  300. data/doc/lib/taskjuggler/RichText/Document_rb.html +1 -1
  301. data/doc/lib/taskjuggler/RichText/Element_rb.html +1 -1
  302. data/doc/lib/taskjuggler/RichText/FunctionExample_rb.html +1 -1
  303. data/doc/lib/taskjuggler/RichText/FunctionHandler_rb.html +1 -1
  304. data/doc/lib/taskjuggler/RichText/Parser_rb.html +1 -1
  305. data/doc/lib/taskjuggler/RichText/RTFHandlers_rb.html +1 -1
  306. data/doc/lib/taskjuggler/RichText/RTFNavigator_rb.html +1 -1
  307. data/doc/lib/taskjuggler/RichText/RTFQuery_rb.html +1 -1
  308. data/doc/lib/taskjuggler/RichText/RTFReportLink_rb.html +1 -1
  309. data/doc/lib/taskjuggler/RichText/RTFReport_rb.html +1 -1
  310. data/doc/lib/taskjuggler/RichText/RTFWithQuerySupport_rb.html +1 -1
  311. data/doc/lib/taskjuggler/RichText/Scanner_rb.html +1 -1
  312. data/doc/lib/taskjuggler/RichText/Snip_rb.html +1 -1
  313. data/doc/lib/taskjuggler/RichText/SyntaxRules_rb.html +1 -1
  314. data/doc/lib/taskjuggler/RichText/TOCEntry_rb.html +1 -1
  315. data/doc/lib/taskjuggler/RichText/TableOfContents_rb.html +1 -1
  316. data/doc/lib/taskjuggler/RichText_rb.html +1 -1
  317. data/doc/lib/taskjuggler/RuntimeConfig_rb.html +1 -1
  318. data/doc/lib/taskjuggler/ScenarioData_rb.html +1 -1
  319. data/doc/lib/taskjuggler/Scenario_rb.html +1 -1
  320. data/doc/lib/taskjuggler/Scoreboard_rb.html +1 -1
  321. data/doc/lib/taskjuggler/SheetHandlerBase_rb.html +1 -1
  322. data/doc/lib/taskjuggler/SheetReceiver_rb.html +1 -1
  323. data/doc/lib/taskjuggler/SheetSender_rb.html +1 -1
  324. data/doc/lib/taskjuggler/ShiftAssignments_rb.html +1 -1
  325. data/doc/lib/taskjuggler/ShiftScenario_rb.html +1 -1
  326. data/doc/lib/taskjuggler/Shift_rb.html +1 -1
  327. data/doc/lib/taskjuggler/SimpleQueryExpander_rb.html +1 -1
  328. data/doc/lib/taskjuggler/StatusSheetReceiver_rb.html +1 -1
  329. data/doc/lib/taskjuggler/StatusSheetSender_rb.html +1 -1
  330. data/doc/lib/taskjuggler/StdIoWrapper_rb.html +1 -1
  331. data/doc/lib/taskjuggler/SyntaxReference_rb.html +1 -1
  332. data/doc/lib/taskjuggler/TableColumnDefinition_rb.html +1 -1
  333. data/doc/lib/taskjuggler/TaskDependency_rb.html +1 -1
  334. data/doc/lib/taskjuggler/TaskJuggler_rb.html +1 -1
  335. data/doc/lib/taskjuggler/TaskScenario_rb.html +1 -1
  336. data/doc/lib/taskjuggler/Task_rb.html +1 -1
  337. data/doc/lib/taskjuggler/TernarySearchTree_rb.html +1 -1
  338. data/doc/lib/taskjuggler/TextFormatter_rb.html +1 -1
  339. data/doc/lib/taskjuggler/TextParser/MacroTable_rb.html +1 -1
  340. data/doc/lib/taskjuggler/TextParser/Pattern_rb.html +1 -1
  341. data/doc/lib/taskjuggler/TextParser/Rule_rb.html +1 -1
  342. data/doc/lib/taskjuggler/TextParser/Scanner_rb.html +1 -1
  343. data/doc/lib/taskjuggler/TextParser/SourceFileInfo_rb.html +1 -1
  344. data/doc/lib/taskjuggler/TextParser/StackElement_rb.html +1 -1
  345. data/doc/lib/taskjuggler/TextParser/State_rb.html +1 -1
  346. data/doc/lib/taskjuggler/TextParser/TokenDoc_rb.html +1 -1
  347. data/doc/lib/taskjuggler/TextParser_rb.html +1 -1
  348. data/doc/lib/taskjuggler/TimeSheetReceiver_rb.html +1 -1
  349. data/doc/lib/taskjuggler/TimeSheetSender_rb.html +1 -1
  350. data/doc/lib/taskjuggler/TimeSheetSummary_rb.html +1 -1
  351. data/doc/lib/taskjuggler/TimeSheets_rb.html +1 -1
  352. data/doc/lib/taskjuggler/Tj3AppBase_rb.html +1 -1
  353. data/doc/lib/taskjuggler/Tj3Config_rb.html +1 -1
  354. data/doc/lib/taskjuggler/Tj3SheetAppBase_rb.html +1 -1
  355. data/doc/lib/taskjuggler/TjException_rb.html +1 -1
  356. data/doc/lib/taskjuggler/TjTime_rb.html +1 -1
  357. data/doc/lib/taskjuggler/TjpExample_rb.html +1 -1
  358. data/doc/lib/taskjuggler/TjpSyntaxRules_rb.html +1 -1
  359. data/doc/lib/taskjuggler/URLParameter_rb.html +1 -1
  360. data/doc/lib/taskjuggler/UTF8String_rb.html +1 -1
  361. data/doc/lib/taskjuggler/UserManual_rb.html +1 -1
  362. data/doc/lib/taskjuggler/VimSyntax_rb.html +1 -1
  363. data/doc/lib/taskjuggler/WorkingHours_rb.html +1 -1
  364. data/doc/lib/taskjuggler/XMLDocument_rb.html +1 -1
  365. data/doc/lib/taskjuggler/XMLElement_rb.html +1 -1
  366. data/doc/lib/taskjuggler/apps/Tj3Client_rb.html +1 -1
  367. data/doc/lib/taskjuggler/apps/Tj3Daemon_rb.html +1 -1
  368. data/doc/lib/taskjuggler/apps/Tj3Man_rb.html +1 -1
  369. data/doc/lib/taskjuggler/apps/Tj3SsReceiver_rb.html +1 -1
  370. data/doc/lib/taskjuggler/apps/Tj3SsSender_rb.html +1 -1
  371. data/doc/lib/taskjuggler/apps/Tj3TsReceiver_rb.html +1 -1
  372. data/doc/lib/taskjuggler/apps/Tj3TsSender_rb.html +1 -1
  373. data/doc/lib/taskjuggler/apps/Tj3TsSummary_rb.html +1 -1
  374. data/doc/lib/taskjuggler/apps/Tj3_rb.html +1 -1
  375. data/doc/lib/taskjuggler/daemon/Daemon_rb.html +1 -1
  376. data/doc/lib/taskjuggler/daemon/ProcessIntercom_rb.html +1 -1
  377. data/doc/lib/taskjuggler/daemon/ProjectBroker_rb.html +1 -1
  378. data/doc/lib/taskjuggler/daemon/ProjectServer_rb.html +1 -1
  379. data/doc/lib/taskjuggler/daemon/ReportServer_rb.html +1 -1
  380. data/doc/lib/taskjuggler/daemon/ReportServlet_rb.html +1 -1
  381. data/doc/lib/taskjuggler/daemon/WebServer_rb.html +1 -1
  382. data/doc/lib/taskjuggler/daemon/WelcomePage_rb.html +1 -1
  383. data/doc/lib/taskjuggler/deep_copy_rb.html +1 -1
  384. data/doc/lib/taskjuggler/reports/CSVFile_rb.html +1 -1
  385. data/doc/lib/taskjuggler/reports/CollisionDetector_rb.html +1 -1
  386. data/doc/lib/taskjuggler/reports/ColumnTable_rb.html +1 -1
  387. data/doc/lib/taskjuggler/reports/GanttChart_rb.html +1 -1
  388. data/doc/lib/taskjuggler/reports/GanttContainer_rb.html +1 -1
  389. data/doc/lib/taskjuggler/reports/GanttHeaderScaleItem_rb.html +1 -1
  390. data/doc/lib/taskjuggler/reports/GanttHeader_rb.html +1 -1
  391. data/doc/lib/taskjuggler/reports/GanttLine_rb.html +1 -1
  392. data/doc/lib/taskjuggler/reports/GanttLoadStack_rb.html +1 -1
  393. data/doc/lib/taskjuggler/reports/GanttMilestone_rb.html +1 -1
  394. data/doc/lib/taskjuggler/reports/GanttRouter_rb.html +1 -1
  395. data/doc/lib/taskjuggler/reports/GanttTaskBar_rb.html +1 -1
  396. data/doc/lib/taskjuggler/reports/HTMLGraphics_rb.html +1 -1
  397. data/doc/lib/taskjuggler/reports/ICalReport_rb.html +71 -0
  398. data/doc/lib/taskjuggler/reports/Navigator_rb.html +1 -1
  399. data/doc/lib/taskjuggler/reports/NikuReport_rb.html +1 -1
  400. data/doc/lib/taskjuggler/reports/ReportBase_rb.html +1 -1
  401. data/doc/lib/taskjuggler/reports/ReportContext_rb.html +1 -1
  402. data/doc/lib/taskjuggler/reports/ReportTableCell_rb.html +1 -1
  403. data/doc/lib/taskjuggler/reports/ReportTableColumn_rb.html +1 -1
  404. data/doc/lib/taskjuggler/reports/ReportTableLegend_rb.html +1 -1
  405. data/doc/lib/taskjuggler/reports/ReportTableLine_rb.html +1 -1
  406. data/doc/lib/taskjuggler/reports/ReportTable_rb.html +1 -1
  407. data/doc/lib/taskjuggler/reports/Report_rb.html +5 -1
  408. data/doc/lib/taskjuggler/reports/ResourceListRE_rb.html +1 -1
  409. data/doc/lib/taskjuggler/reports/StatusSheetReport_rb.html +1 -1
  410. data/doc/lib/taskjuggler/reports/TableReport_rb.html +1 -1
  411. data/doc/lib/taskjuggler/reports/TagFile_rb.html +71 -0
  412. data/doc/lib/taskjuggler/reports/TaskListRE_rb.html +1 -1
  413. data/doc/lib/taskjuggler/reports/TextReport_rb.html +1 -1
  414. data/doc/lib/taskjuggler/reports/TimeSheetReport_rb.html +1 -1
  415. data/doc/lib/taskjuggler/reports/TjpExportRE_rb.html +1 -1
  416. data/doc/lib/tj3_rb.html +1 -1
  417. data/doc/lib/tj3client_rb.html +1 -1
  418. data/doc/lib/tj3d_rb.html +1 -1
  419. data/doc/lib/tj3man_rb.html +1 -1
  420. data/doc/lib/tj3ss_receiver_rb.html +1 -1
  421. data/doc/lib/tj3ss_sender_rb.html +1 -1
  422. data/doc/lib/tj3ts_receiver_rb.html +1 -1
  423. data/doc/lib/tj3ts_sender_rb.html +1 -1
  424. data/doc/lib/tj3ts_summary_rb.html +1 -1
  425. data/lib/taskjuggler/Account.rb +1 -1
  426. data/lib/taskjuggler/AccountScenario.rb +1 -1
  427. data/lib/taskjuggler/Allocation.rb +5 -5
  428. data/lib/taskjuggler/AttributeBase.rb +30 -22
  429. data/lib/taskjuggler/Attributes.rb +80 -78
  430. data/lib/taskjuggler/Booking.rb +2 -2
  431. data/lib/taskjuggler/Charge.rb +3 -3
  432. data/lib/taskjuggler/ICalendar.rb +251 -0
  433. data/lib/taskjuggler/Interval.rb +215 -53
  434. data/lib/taskjuggler/IntervalList.rb +5 -5
  435. data/lib/taskjuggler/Limits.rb +79 -69
  436. data/lib/taskjuggler/LogicalFunction.rb +2 -2
  437. data/lib/taskjuggler/MessageHandler.rb +11 -6
  438. data/lib/taskjuggler/Project.rb +208 -95
  439. data/lib/taskjuggler/ProjectFileParser.rb +2 -2
  440. data/lib/taskjuggler/ProjectFileScanner.rb +7 -6
  441. data/lib/taskjuggler/PropertySet.rb +1 -5
  442. data/lib/taskjuggler/PropertyTreeNode.rb +21 -16
  443. data/lib/taskjuggler/Query.rb +10 -7
  444. data/lib/taskjuggler/Resource.rb +6 -1
  445. data/lib/taskjuggler/ResourceScenario.rb +85 -69
  446. data/lib/taskjuggler/RichText/RTFQuery.rb +2 -2
  447. data/lib/taskjuggler/ScenarioData.rb +11 -1
  448. data/lib/taskjuggler/Scoreboard.rb +8 -1
  449. data/lib/taskjuggler/Shift.rb +1 -1
  450. data/lib/taskjuggler/ShiftAssignments.rb +22 -20
  451. data/lib/taskjuggler/Task.rb +1 -1
  452. data/lib/taskjuggler/TaskJuggler.rb +65 -51
  453. data/lib/taskjuggler/TaskScenario.rb +486 -419
  454. data/lib/taskjuggler/TextParser/Scanner.rb +22 -11
  455. data/lib/taskjuggler/TimeSheets.rb +1 -1
  456. data/lib/taskjuggler/Tj3Config.rb +1 -1
  457. data/lib/taskjuggler/TjTime.rb +7 -3
  458. data/lib/taskjuggler/TjpSyntaxRules.rb +157 -23
  459. data/lib/taskjuggler/VimSyntax.rb +18 -0
  460. data/lib/taskjuggler/WorkingHours.rb +20 -4
  461. data/lib/taskjuggler/apps/Tj3.rb +16 -1
  462. data/lib/taskjuggler/reports/GanttLine.rb +1 -1
  463. data/lib/taskjuggler/reports/ICalReport.rb +136 -0
  464. data/lib/taskjuggler/reports/NikuReport.rb +1 -1
  465. data/lib/taskjuggler/reports/Report.rb +59 -0
  466. data/lib/taskjuggler/reports/ReportBase.rb +2 -67
  467. data/lib/taskjuggler/reports/TableReport.rb +9 -8
  468. data/lib/taskjuggler/reports/TagFile.rb +120 -0
  469. data/lib/taskjuggler/reports/TimeSheetReport.rb +3 -3
  470. data/lib/taskjuggler/reports/TjpExportRE.rb +33 -9
  471. data/manual/Installation +126 -0
  472. data/spec/ICalendar_spec.rb +45 -0
  473. data/spec/IntervalList_spec.rb +11 -11
  474. data/tasks/changelog.rake +150 -60
  475. data/tasks/gem.rake +1 -0
  476. data/tasks/vim.rake +2 -2
  477. data/test/TestSuite/Export-Reports/refs/Booking.tjp +1 -1
  478. data/test/TestSuite/Export-Reports/refs/CompletedWork.tji.tjp +40 -0
  479. data/test/TestSuite/Export-Reports/refs/Macro-2.tjp +10 -1
  480. data/test/TestSuite/Export-Reports/refs/TaskPrefix.tjp +1 -1
  481. data/test/TestSuite/HTML-Reports/Alerts.html +160 -412
  482. data/test/TestSuite/HTML-Reports/CellText.html +758 -0
  483. data/test/TestSuite/HTML-Reports/ColumnPeriods.html +156 -0
  484. data/test/TestSuite/HTML-Reports/IsOngoing.html +172 -0
  485. data/test/TestSuite/HTML-Reports/LogicalFunctions.html +245 -0
  486. data/test/TestSuite/HTML-Reports/Query.html +31 -0
  487. data/test/TestSuite/HTML-Reports/css/tjmanual.css +0 -20
  488. data/test/TestSuite/HTML-Reports/css/tjreport.css +6 -7
  489. data/test/TestSuite/HTML-Reports/depArrows.html +851 -0
  490. data/test/TestSuite/HTML-Reports/profile.html +37581 -0
  491. data/test/TestSuite/{Scheduler/Correct → HTML-Reports/scripts}/scripts/wz_tooltip.js +20 -20
  492. data/test/TestSuite/Scheduler/Correct/Booking.tjp +3 -3
  493. data/test/TestSuite/Scheduler/Correct/Duration.tjp +3 -3
  494. data/test/TestSuite/Scheduler/Errors/R.html +113 -0
  495. data/test/TestSuite/Scheduler/Errors/allocate_no_assigned.tjp +15 -0
  496. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/css/tjmanual.css +0 -1
  497. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/css/tjreport.css +0 -0
  498. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/details.png +0 -0
  499. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/flag-green.png +0 -0
  500. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/flag-red.png +0 -0
  501. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/flag-yellow.png +0 -0
  502. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/resource.png +0 -0
  503. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/resourcegroup.png +0 -0
  504. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/task.png +0 -0
  505. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/taskgroup.png +0 -0
  506. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/trend-down.png +0 -0
  507. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/trend-flat.png +0 -0
  508. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/icons/trend-up.png +0 -0
  509. data/test/TestSuite/Scheduler/Errors/overbooked_duration.tjp +11 -0
  510. data/test/TestSuite/Scheduler/Errors/overbooked_effort.tjp +11 -0
  511. data/test/TestSuite/Scheduler/Errors/overbooked_length.tjp +13 -0
  512. data/test/TestSuite/{ReportGenerator/Correct → Scheduler/Errors}/scripts/wz_tooltip.js +0 -0
  513. data/test/TestSuite/StatusSheets/dev2.tji +22 -0
  514. data/test/TestSuite/Syntax/Correct/CompletedWork.tji.tjp +38 -0
  515. data/test/TestSuite/Syntax/Correct/Macro-2.tjp +5 -2
  516. data/test/TestSuite/Syntax/Errors/scenario_after_tracking.tjp +8 -0
  517. data/test/TestSuite/TimeSheets/resrep.tji +7 -0
  518. data/test/TestSuite/TimeSheets/ts.tji +351 -0
  519. data/test/TestSuite/TimeSheets/tsdef.tji +2 -0
  520. data/test/test_Limits.rb +38 -30
  521. data/test/test_Scheduler.rb +2 -2
  522. data/test/test_ShiftAssignments.rb +8 -8
  523. data/test/test_WorkingHours.rb +4 -4
  524. metadata +1015 -1005
  525. data/lib/exchangebug.rb +0 -42
  526. data/lib/ruby-signal-bug.rb +0 -55
  527. data/test/TestSuite/Export-Reports/refs/DST.tjp +0 -60
  528. data/test/TestSuite/Export-Reports/refs/ReleasePlan.tjp +0 -80
  529. data/test/TestSuite/HTML-Reports/TimeSheet.html +0 -79
  530. data/test/TestSuite/HTML-Reports/reference.html +0 -51
  531. data/test/TestSuite/ReportGenerator/Correct/Alerts-1.csv +0 -412
  532. data/test/TestSuite/ReportGenerator/Correct/Alerts-1.html +0 -680
  533. data/test/TestSuite/ReportGenerator/Correct/DependencyList.csv +0 -4
  534. data/test/TestSuite/ReportGenerator/Correct/DependencyList.tjp +0 -25
  535. data/test/TestSuite/ReportGenerator/Correct/Journal-1.csv +0 -8
  536. data/test/TestSuite/ReportGenerator/Correct/Journal-2.csv +0 -8
  537. data/test/TestSuite/ReportGenerator/Correct/Journal-3.html +0 -28
  538. data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.csv +0 -3
  539. data/test/TestSuite/ReportGenerator/Correct/opennodes-1.csv +0 -2
  540. data/test/TestSuite/ReportGenerator/Correct/opennodes.csv +0 -2
  541. data/test/TestSuite/ReportGenerator/Correct/opennodes.tjp +0 -26
  542. data/test/TestSuite/ReportGenerator/Correct/refs/opennodes-1.csv +0 -2
  543. data/test/TestSuite/Scheduler/' +0 -23
  544. data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +0 -86
  545. data/test/TestSuite/Scheduler/Correct/css/tjreport.css +0 -413
  546. data/test/TestSuite/Scheduler/Correct/icons/details.png +0 -0
  547. data/test/TestSuite/Scheduler/Correct/icons/flag-green.png +0 -0
  548. data/test/TestSuite/Scheduler/Correct/icons/flag-red.png +0 -0
  549. data/test/TestSuite/Scheduler/Correct/icons/flag-yellow.png +0 -0
  550. data/test/TestSuite/Scheduler/Correct/icons/resource.png +0 -0
  551. data/test/TestSuite/Scheduler/Correct/icons/resourcegroup.png +0 -0
  552. data/test/TestSuite/Scheduler/Correct/icons/task.png +0 -0
  553. data/test/TestSuite/Scheduler/Correct/icons/taskgroup.png +0 -0
  554. data/test/TestSuite/Scheduler/Correct/icons/trend-down.png +0 -0
  555. data/test/TestSuite/Scheduler/Correct/icons/trend-flat.png +0 -0
  556. data/test/TestSuite/Scheduler/Correct/icons/trend-up.png +0 -0
  557. data/test/TestSuite/StatusSheetTemplates/project.tji +0 -35
  558. data/test/TestSuite/StatusSheetTemplates/project.tjp +0 -56
  559. data/test/TestSuite/StatusSheets/TimeSheets/2002-03-01/resource1_2002-03-01.tji +0 -0
  560. data/test/TestSuite/Syntax/Correct/DST.tjp +0 -11
  561. data/test/TestSuite/Syntax/Correct/ReleasePlan.tjp +0 -32
  562. data/test/TestSuite/TimeSheets/receiver.log.mod +0 -1056
  563. data/test/TestSuite/TimeSheets/uu.txt +0 -29
@@ -23,6 +23,15 @@ class TaskJuggler
23
23
  # Create a new TaskScenario object.
24
24
  def initialize(task, scenarioIdx, attributes)
25
25
  super
26
+ # Attributed are only really created when they are accessed the first
27
+ # time. So make sure some needed attributes really exist so we don't
28
+ # have to check for existance each time we access them.
29
+ %w( allocate assignedresources booking charge chargeset complete
30
+ criticalness depends duration effort end forward length
31
+ maxend maxstart minend minstart milestone pathcriticalness
32
+ precedes scheduled shifts start status ).each do |attr|
33
+ @property[attr, @scenarioIdx]
34
+ end
26
35
 
27
36
  # A list of all allocated leaf resources.
28
37
  @candidates = []
@@ -33,59 +42,79 @@ class TaskJuggler
33
42
  # scheduling.
34
43
  def prepareScheduling
35
44
  @property['startpreds', @scenarioIdx] = []
36
- @property['startsuccs', @scenarioIdx] =[]
45
+ @property['startsuccs', @scenarioIdx] = []
37
46
  @property['endpreds', @scenarioIdx] = []
38
47
  @property['endsuccs', @scenarioIdx] = []
39
48
 
40
49
  @isRunAway = false
41
50
 
42
- # The following variables are only used during scheduling
43
- @lastSlot = nil
51
+ # And as global scoreboard index
52
+ @currentSlotIdx = nil
44
53
  # The 'done' variables count scheduled values in number of time slots.
45
54
  @doneDuration = 0
46
55
  @doneLength = 0
47
56
  # Due to the 'efficiency' factor the effort slots must be a float.
48
57
  @doneEffort = 0.0
49
58
 
59
+ @projectionMode = @project.scenario(@scenarioIdx).get('projection')
60
+
50
61
  @startIsDetermed = nil
51
62
  @endIsDetermed = nil
52
- @tentativeStart = @tentativeEnd = nil
53
63
 
54
64
  # To avoid multiple calls to propagateDate() we use these flags to know
55
65
  # when we've done it already.
56
66
  @startPropagated = false
57
67
  @endPropagated = false
58
68
 
69
+ markMilestone
59
70
  # Milestones may only have start or end date even when the 'scheduled'
60
71
  # attribute is set. For further processing, we need to add the missing
61
72
  # date.
62
- if a('milestone') && a('scheduled')
63
- @property['end', @scenarioIdx] = a('start') if a('start') && !a('end')
64
- @property['start', @scenarioIdx] = a('end') if !a('start') && a('end')
65
- Log << "Milestone #{@property.fullId}: #{a('start')} -> #{a('end')}"
73
+ if @milestone
74
+ @end = @start if @start && !@end
75
+ @start = @end if !@start && @end
76
+ end
77
+
78
+ # For start-end-tasks without allocation, we don't have to do
79
+ # anything but to set the 'scheduled' flag.
80
+ if @start && @end && @effort == 0 && @length == 0 && @duration == 0 &&
81
+ @allocate.empty?
82
+ @scheduled = true
83
+ Log << "Task #{@property.fullId}: #{@start} -> #{@end}"
66
84
  end
67
85
 
68
86
  # Collect the limits of this task and all parent tasks into a single
69
87
  # Array.
70
- @limits = []
88
+ @allLimits = []
71
89
  task = @property
72
90
  # Reset the counters of all limits of this task.
73
91
  task['limits', @scenarioIdx].reset if task['limits', @scenarioIdx]
74
92
  until task.nil?
75
93
  if task['limits', @scenarioIdx]
76
- @limits << task['limits', @scenarioIdx]
94
+ @allLimits << task['limits', @scenarioIdx]
77
95
  end
78
96
  task = task.parent
79
97
  end
80
98
 
81
99
  # Collect the mandatory allocations.
82
100
  @mandatories = []
83
- a('allocate').each do |allocation|
101
+ @allocate.each do |allocation|
84
102
  @mandatories << allocation if allocation.mandatory
103
+ allocation.lockedResource = nil
85
104
  end
86
105
 
87
106
  bookBookings
88
- markMilestone
107
+
108
+ @durationType =
109
+ if @effort > 0
110
+ :effortTask
111
+ elsif @length > 0
112
+ :lengthTask
113
+ elsif @duration > 0
114
+ :durationTask
115
+ else
116
+ :startEndTask
117
+ end
89
118
  end
90
119
 
91
120
  # The parser only stores the full task IDs for each of the dependencies.
@@ -100,16 +129,16 @@ class TaskJuggler
100
129
  # points to the dependent task and the boolean specifies whether the
101
130
  # dependency originates from the end of the task or not.
102
131
  def Xref
103
- @property['depends', @scenarioIdx].each do |dependency|
132
+ @depends.each do |dependency|
104
133
  depTask = checkDependency(dependency, 'depends')
105
- a('startpreds').push([ depTask, dependency.onEnd ])
134
+ @startpreds.push([ depTask, dependency.onEnd ])
106
135
  depTask[dependency.onEnd ? 'endsuccs' : 'startsuccs', @scenarioIdx].
107
136
  push([ @property, false ])
108
137
  end
109
138
 
110
- @property['precedes', @scenarioIdx].each do |dependency|
139
+ @precedes.each do |dependency|
111
140
  predTask = checkDependency(dependency, 'precedes')
112
- a('endsuccs').push([ predTask, dependency.onEnd ])
141
+ @endsuccs.push([ predTask, dependency.onEnd ])
113
142
  predTask[dependency.onEnd ? 'endpreds' : 'startpreds', @scenarioIdx].
114
143
  push([@property, true ])
115
144
  end
@@ -123,8 +152,8 @@ class TaskJuggler
123
152
 
124
153
  def propagateInitialValues
125
154
  unless @startPropagated
126
- if a('start')
127
- propagateDate(a('start'), false)
155
+ if @start
156
+ propagateDate(@start, false)
128
157
  elsif @property.parent.nil? &&
129
158
  @property.canInheritDate?(@scenarioIdx, false)
130
159
  propagateDate(@project['start'], false)
@@ -132,8 +161,8 @@ class TaskJuggler
132
161
  end
133
162
 
134
163
  unless @endPropagated
135
- if a('end')
136
- propagateDate(a('end'), true)
164
+ if @end
165
+ propagateDate(@end, true)
137
166
  elsif @property.parent.nil? &&
138
167
  @property.canInheritDate?(@scenarioIdx, true)
139
168
  propagateDate(@project['end'], true)
@@ -146,7 +175,7 @@ class TaskJuggler
146
175
  def preScheduleCheck
147
176
  # Accounts can have sub accounts added after being used in a chargetset.
148
177
  # So we need to re-test here.
149
- a('chargeset').each do |chargeset|
178
+ @chargeset.each do |chargeset|
150
179
  chargeset.each do |account, share|
151
180
  unless account.leaf?
152
181
  error('account_no_leaf',
@@ -157,36 +186,36 @@ class TaskJuggler
157
186
 
158
187
  # Leaf tasks can be turned into containers after bookings have been added.
159
188
  # We need to check for this.
160
- unless @property.leaf? || a('booking').empty?
189
+ unless @property.leaf? || @booking.empty?
161
190
  error('container_booking',
162
191
  "Container task #{@property.fullId} may not have bookings.")
163
192
  end
164
193
 
165
194
  # Milestones may not have bookings.
166
- if a('milestone') && !a('booking').empty?
195
+ if @milestone && !@booking.empty?
167
196
  error('milestone_booking',
168
197
  "Milestone #{@property.fullId} may not have bookings.")
169
198
  end
170
199
 
171
200
  # All 'scheduled' tasks must have a fixed start and end date.
172
- if a('scheduled') && (a('start').nil? || a('end').nil?)
201
+ if @scheduled && (@start.nil? || @end.nil?)
173
202
  error('not_scheduled',
174
203
  "Task #{@property.fullId} is marked as scheduled but does not " +
175
204
  'have a fixed start and end date.')
176
205
  end
177
206
 
178
207
  # If an effort has been specified resources must be allocated as well.
179
- if a('effort') > 0 && a('allocate').empty?
208
+ if @effort > 0 && @allocate.empty?
180
209
  error('effort_no_allocations',
181
210
  "Task #{@property.fullId} has an effort but no resource " +
182
211
  "allocations.")
183
212
  end
184
213
 
185
214
  durationSpecs = 0
186
- durationSpecs += 1 if a('effort') > 0
187
- durationSpecs += 1 if a('length') > 0
188
- durationSpecs += 1 if a('duration') > 0
189
- durationSpecs += 1 if a('milestone')
215
+ durationSpecs += 1 if @effort > 0
216
+ durationSpecs += 1 if @length > 0
217
+ durationSpecs += 1 if @duration > 0
218
+ durationSpecs += 1 if @milestone
190
219
 
191
220
  # The rest of this function performs a number of plausibility tests with
192
221
  # regards to task start and end critiria. To explain the various cases,
@@ -207,7 +236,7 @@ class TaskJuggler
207
236
  "Container task #{@property.fullId} may not have a duration " +
208
237
  "or be marked as milestones.")
209
238
  end
210
- elsif a('milestone')
239
+ elsif @milestone
211
240
  if durationSpecs > 1
212
241
  error('milestone_duration',
213
242
  "Milestone task #{@property.fullId} may not have a duration.")
@@ -223,9 +252,9 @@ class TaskJuggler
223
252
  # already handled by 'start_undetermed' or 'end_undetermed'
224
253
 
225
254
  # err2: differnt start and end dates
226
- if a('start') && a('end') && a('start') != a('end')
255
+ if @start && @end && @start != @end
227
256
  error('milestone_start_end',
228
- "Start (#{a('start')}) and end (#{a('end')}) dates of " +
257
+ "Start (#{@start}) and end (#{@end}) dates of " +
229
258
  "milestone task #{@property.fullId} must be identical.")
230
259
  end
231
260
  else
@@ -268,8 +297,8 @@ class TaskJuggler
268
297
  # - <-- -D
269
298
  # - <-- |D
270
299
  if durationSpecs == 0 &&
271
- ((a('forward') && a('end').nil? && !hasDependencies(true)) ||
272
- (!a('forward') && a('start').nil? && !hasDependencies(false)))
300
+ ((@forward && @end.nil? && !hasDependencies(true)) ||
301
+ (!@forward && @start.nil? && !hasDependencies(false)))
273
302
  error('task_underspecified',
274
303
  "Task #{@property.fullId} has too few specifations to be " +
275
304
  "scheduled.")
@@ -296,8 +325,8 @@ class TaskJuggler
296
325
  startSpeced = @property.provided('start', @scenarioIdx)
297
326
  endSpeced = @property.provided('end', @scenarioIdx)
298
327
  if ((startSpeced && endSpeced) ||
299
- (hasDependencies(false) && a('forward') && endSpeced) ||
300
- (hasDependencies(true) && !a('forward') && startSpeced)) &&
328
+ (hasDependencies(false) && @forward && endSpeced) ||
329
+ (hasDependencies(true) && !@forward && startSpeced)) &&
301
330
  durationSpecs > 0 && !@property.provided('scheduled', @scenarioIdx)
302
331
  error('task_overspecified',
303
332
  "Task #{@property.fullId} has a start, an end and a " +
@@ -305,7 +334,7 @@ class TaskJuggler
305
334
  end
306
335
  end
307
336
 
308
- if !a('booking').empty? && !a('forward') && !a('scheduled')
337
+ if !@booking.empty? && !@forward && !@scheduled
309
338
  error('alap_booking',
310
339
  'A task scheduled in ALAP mode may only have bookings if it ' +
311
340
  'has been marked as fully scheduled. Keep in mind that ' +
@@ -313,14 +342,14 @@ class TaskJuggler
313
342
  'switch the task to ALAP mode.')
314
343
  end
315
344
 
316
- a('startsuccs').each do |task, onEnd|
345
+ @startsuccs.each do |task, onEnd|
317
346
  unless task['forward', @scenarioIdx]
318
347
  task.data[@scenarioIdx].error(
319
348
  'onstart_wrong_direction',
320
349
  'Tasks with on-start dependencies must be ASAP scheduled')
321
350
  end
322
351
  end
323
- a('endpreds').each do |task, onEnd|
352
+ @endpreds.each do |task, onEnd|
324
353
  if task['forward', @scenarioIdx]
325
354
  task.data[@scenarioIdx].error(
326
355
  'onend_wrong_direction',
@@ -340,7 +369,7 @@ class TaskJuggler
340
369
 
341
370
  if (parent = @property.parent)
342
371
  # Add the assigned resources to the parent task list.
343
- a('assignedresources').each do |resource|
372
+ @assignedresources.each do |resource|
344
373
  unless parent['assignedresources', @scenarioIdx].include?(resource)
345
374
  parent['assignedresources', @scenarioIdx] << resource
346
375
  end
@@ -371,65 +400,65 @@ class TaskJuggler
371
400
  end
372
401
 
373
402
  # Make sure the task is marked complete
374
- unless a('scheduled')
403
+ unless @scheduled
375
404
  error('not_scheduled',
376
405
  "Task #{@property.fullId} has not been marked as scheduled.")
377
406
  end
378
407
 
379
408
  # If the task has a follower or predecessor that is a runaway this task
380
409
  # is also incomplete.
381
- (a('startsuccs') + a('endsuccs')).each do |task, onEnd|
410
+ (@startsuccs + @endsuccs).each do |task, onEnd|
382
411
  return false if task.isRunAway(@scenarioIdx)
383
412
  end
384
- (a('startpreds') + a('endpreds')).each do |task, onEnd|
413
+ (@startpreds + @endpreds).each do |task, onEnd|
385
414
  return false if task.isRunAway(@scenarioIdx)
386
415
  end
387
416
 
388
417
  # Check if the start time is ok
389
- if a('start').nil?
418
+ if @start.nil?
390
419
  error('task_start_undef',
391
420
  "Task #{@property.fullId} has undefined start time")
392
421
  end
393
- if a('start') < @project['start'] || a('start') > @project['end']
422
+ if @start < @project['start'] || @start > @project['end']
394
423
  error('task_start_range',
395
- "The start time (#{a('start')}) of task #{@property.fullId} " +
424
+ "The start time (#{@start}) of task #{@property.fullId} " +
396
425
  "is outside the project interval (#{@project['start']} - " +
397
426
  "#{@project['end']})")
398
427
  end
399
- if !a('minstart').nil? && a('start') < a('minstart')
428
+ if !@minstart.nil? && @start < @minstart
400
429
  warning('minstart',
401
- "The start time (#{a('start')}) of task #{@property.fullId} " +
402
- "is too early. Must be after #{a('minstart')}.")
430
+ "The start time (#{@start}) of task #{@property.fullId} " +
431
+ "is too early. Must be after #{@minstart}.")
403
432
  end
404
- if !a('maxstart').nil? && a('start') > a('maxstart')
433
+ if !@maxstart.nil? && @start > @maxstart
405
434
  warning('maxstart',
406
- "The start time (#{a('start')}) of task #{@property.fullId} " +
407
- "is too late. Must be before #{a('maxstart')}.")
435
+ "The start time (#{@start}) of task #{@property.fullId} " +
436
+ "is too late. Must be before #{@maxstart}.")
408
437
  end
409
438
  # Check if the end time is ok
410
439
  error('task_end_undef',
411
- "Task #{@property.fullId} has undefined end time") if a('end').nil?
412
- if a('end') < @project['start'] || a('end') > @project['end']
440
+ "Task #{@property.fullId} has undefined end time") if @end.nil?
441
+ if @end < @project['start'] || @end > @project['end']
413
442
  error('task_end_range',
414
- "The end time (#{a('end')}) of task #{@property.fullId} " +
443
+ "The end time (#{@end}) of task #{@property.fullId} " +
415
444
  "is outside the project interval (#{@project['start']} - " +
416
445
  "#{@project['end']})")
417
446
  end
418
- if !a('minend').nil? && a('end') < a('minend')
447
+ if !@minend.nil? && @end < @minend
419
448
  warning('minend',
420
- "The end time (#{a('end')}) of task #{@property.fullId} " +
421
- "is too early. Must be after #{a('minend')}.")
449
+ "The end time (#{@end}) of task #{@property.fullId} " +
450
+ "is too early. Must be after #{@minend}.")
422
451
  end
423
- if !a('maxend').nil? && a('end') > a('maxend')
452
+ if !@maxend.nil? && @end > @maxend
424
453
  warning('maxend',
425
- "The end time (#{a('end')}) of task #{@property.fullId} " +
426
- "is too late. Must be before #{a('maxend')}.")
454
+ "The end time (#{@end}) of task #{@property.fullId} " +
455
+ "is too late. Must be before #{@maxend}.")
427
456
  end
428
457
  # Make sure the start is before the end
429
- if a('start') > a('end')
458
+ if @start > @end
430
459
  error('start_after_end',
431
- "The start time (#{a('start')}) of task #{@property.fullId} " +
432
- "is after the end time (#{a('end')}).")
460
+ "The start time (#{@start}) of task #{@property.fullId} " +
461
+ "is after the end time (#{@end}).")
433
462
  end
434
463
 
435
464
 
@@ -437,33 +466,33 @@ class TaskJuggler
437
466
  unless (parent = @property.parent).nil? ||
438
467
  parent['start', @scenarioIdx].nil? ||
439
468
  parent['end', @scenarioIdx].nil?
440
- if a('start') < parent['start', @scenarioIdx]
469
+ if @start < parent['start', @scenarioIdx]
441
470
  error('task_start_in_parent',
442
- "The start date (#{a('start')}) of task #{@property.fullId} " +
443
- "is before the start date of the enclosing task " +
444
- "#{parent['start', @scenarioIdx]}. ")
471
+ "The start date (#{@start}) of task #{@property.fullId} " +
472
+ "is before the start date (#{parent['start', @scenarioIdx]}) " +
473
+ "of the enclosing task.")
445
474
  end
446
- if a('end') > parent['end', @scenarioIdx]
475
+ if @end > parent['end', @scenarioIdx]
447
476
  error('task_end_in_parent',
448
- "The end date (#{a('end')}) of task #{@property.fullId} " +
449
- "is after the end date of the enclosing task " +
450
- "#{parent['end', @scenarioIdx]}. ")
477
+ "The end date (#{@end}) of task #{@property.fullId} " +
478
+ "is after the end date (#{parent['end', @scenarioIdx]}) " +
479
+ "of the enclosing task.")
451
480
  end
452
481
  end
453
482
 
454
483
  # Check that all preceding tasks start/end before this task.
455
- @property['depends', @scenarioIdx].each do |dependency|
484
+ @depends.each do |dependency|
456
485
  task = dependency.task
457
486
  limit = task[dependency.onEnd ? 'end' : 'start', @scenarioIdx]
458
487
  next if limit.nil?
459
- if a('start') < limit
488
+ if @start < limit
460
489
  error('task_pred_before',
461
- "Task #{@property.fullId} must start after " +
462
- "#{dependency.onEnd ? 'end' : 'start'} of task " +
490
+ "Task #{@property.fullId} (#{@start}) must start after " +
491
+ "#{dependency.onEnd ? 'end' : 'start'} (#{limit}) of task " +
463
492
  "#{task.fullId}.")
464
493
  end
465
494
  if dependency.gapDuration > 0
466
- if limit + dependency.gapDuration > a('start')
495
+ if limit + dependency.gapDuration > @start
467
496
  error('task_pred_before_gd',
468
497
  "Task #{@property.fullId} must start " +
469
498
  "#{dependency.gapDuration / (60 * 60 * 24)} days after " +
@@ -474,7 +503,7 @@ class TaskJuggler
474
503
  end
475
504
  end
476
505
  if dependency.gapLength > 0
477
- if calcLength(limit, a('start')) < dependency.gapLength
506
+ if calcLength(limit, @start) < dependency.gapLength
478
507
  error('task_pred_before_gl',
479
508
  "Task #{@property.fullId} must start " +
480
509
  "#{@project.slotsToDays(dependency.gapLength)} " +
@@ -488,17 +517,18 @@ class TaskJuggler
488
517
  end
489
518
 
490
519
  # Check that all following tasks end before this task
491
- @property['precedes', @scenarioIdx].each do |dependency|
520
+ @precedes.each do |dependency|
492
521
  task = dependency.task
493
522
  limit = task[dependency.onEnd ? 'end' : 'start', @scenarioIdx]
494
523
  next if limit.nil?
495
- if limit < a('end')
524
+ if limit < @end
496
525
  error('task_succ_after',
497
- "Task #{@property.fullId} must end before " +
498
- "#{dependency.onEnd ? 'end' : 'start'} of task #{task.fullId}.")
526
+ "Task #{@property.fullId} (#{@end}) must end before " +
527
+ "#{dependency.onEnd ? 'end' : 'start'} (#{limit}) of task " +
528
+ "#{task.fullId}.")
499
529
  end
500
530
  if dependency.gapDuration > 0
501
- if limit - dependency.gapDuration < a('end')
531
+ if limit - dependency.gapDuration < @end
502
532
  error('task_succ_after_gd',
503
533
  "Task #{@property.fullId} must end " +
504
534
  "#{dependency.gapDuration / (60 * 60 * 24)} days before " +
@@ -509,7 +539,7 @@ class TaskJuggler
509
539
  end
510
540
  end
511
541
  if dependency.gapLength > 0
512
- if calcLength(a('end'), limit) < dependency.gapLength
542
+ if calcLength(@end, limit) < dependency.gapLength
513
543
  error('task_succ_after_gl',
514
544
  "Task #{@property.fullId} must end " +
515
545
  "#{@project.slotsToDays(dependency.gapLength)} " +
@@ -522,12 +552,24 @@ class TaskJuggler
522
552
  end
523
553
  end
524
554
 
525
- if a('milestone') && a('start') != a('end')
555
+ if @milestone && @start != @end
526
556
  error('milestone_times_equal',
527
557
  "Milestone #{@property.fullId} must have identical start and " +
528
558
  "end date.")
529
559
  end
530
560
 
561
+ if @effort == 0 && !@milestone && !@allocate.empty? &&
562
+ @assignedresources.empty?
563
+ # The user used an 'allocate' for the task, but did not specify any
564
+ # 'effort'. Actual allocations will only happen when resources are
565
+ # available by chance. If there are no assigned resources, we generate
566
+ # a warning as this is probably not what the user intended.
567
+ warning('allocate_no_assigned',
568
+ "Task #{@property.id} has resource allocation requested, but " +
569
+ "did not get any resources assigned. Either use 'effort' " +
570
+ "to ensure allocations or use a higher 'priority'.")
571
+ end
572
+
531
573
  @errors == 0
532
574
  end
533
575
 
@@ -618,12 +660,12 @@ class TaskJuggler
618
660
  # -->| o---->
619
661
  # +--------
620
662
  #
621
- if (forward && a('forward')) || a('milestone')
663
+ if (forward && @forward) || @milestone
622
664
  checkForLoops(path, true, false, true)
623
665
  end
624
666
  end
625
667
  else
626
- if a('startpreds').empty?
668
+ if @startpreds.empty?
627
669
  #
628
670
  # ^
629
671
  # |
@@ -645,7 +687,7 @@ class TaskJuggler
645
687
  # ^
646
688
  # |
647
689
  #
648
- a('startpreds').each do |task, targetEnd|
690
+ @startpreds.each do |task, targetEnd|
649
691
  task.checkForLoops(@scenarioIdx, path, targetEnd, true, forward)
650
692
  end
651
693
  end
@@ -672,12 +714,12 @@ class TaskJuggler
672
714
  # <----o |<--
673
715
  # --------+
674
716
  #
675
- if (!forward && !a('forward')) || a('milestone')
717
+ if (!forward && !@forward) || @milestone
676
718
  checkForLoops(path, false, false, false)
677
719
  end
678
720
  end
679
721
  else
680
- if a('endsuccs').empty?
722
+ if @endsuccs.empty?
681
723
  #
682
724
  # ^
683
725
  # |
@@ -698,7 +740,7 @@ class TaskJuggler
698
740
  # ^
699
741
  # |
700
742
  #
701
- a('endsuccs').each do |task, targetEnd|
743
+ @endsuccs.each do |task, targetEnd|
702
744
  task.checkForLoops(@scenarioIdx, path, targetEnd, true, forward)
703
745
  end
704
746
  end
@@ -715,7 +757,7 @@ class TaskJuggler
715
757
  # list of leaf resources that are allocated to this task.
716
758
  def candidates
717
759
  @candidates = []
718
- a('allocate').each do |allocation|
760
+ @allocate.each do |allocation|
719
761
  allocation.candidates.each do |candidate|
720
762
  candidate.allLeaves.each do |resource|
721
763
  @candidates << resource unless @candidates.include?(resource)
@@ -730,9 +772,9 @@ class TaskJuggler
730
772
  # stores it in @candidates. It also adds the allocated effort to
731
773
  # the 'alloctdeffort' counter of each resource.
732
774
  def countResourceAllocations
733
- return if @candidates.empty? || a('effort') <= 0
775
+ return if @candidates.empty? || @effort <= 0
734
776
 
735
- avgEffort = a('effort') / @candidates.length
777
+ avgEffort = @effort / @candidates.length
736
778
  @candidates.each do |resource|
737
779
  resource['alloctdeffort', @scenarioIdx] += avgEffort
738
780
  end
@@ -744,20 +786,20 @@ class TaskJuggler
744
786
  # exception are milestones which get an arbitrary value between 0 and 2
745
787
  # based on their priority.
746
788
  def calcCriticalness
747
- @property['criticalness', @scenarioIdx] = 0.0
748
- @property['pathcriticalness', @scenarioIdx] = nil
789
+ @criticalness = 0.0
790
+ @pathcriticalness = nil
749
791
 
750
792
  # Users feel that milestones are somewhat important. So we use an
751
793
  # arbitrary value larger than 0 for them. We make it priority dependent,
752
794
  # so the user has some control over it. Priority 0 is 0, 500 is 1.0 and
753
795
  # 1000 is 2.0. These values are pretty much randomly picked and probably
754
796
  # require some more tuning based on real projects.
755
- if a('milestone')
756
- @property['criticalness', @scenarioIdx] = a('priority') / 500.0
797
+ if @milestone
798
+ @criticalness = @priority / 500.0
757
799
  end
758
800
 
759
801
  # Task without efforts of allocations are not critical.
760
- return if a('effort') <= 0 || @candidates.empty?
802
+ return if @effort <= 0 || @candidates.empty?
761
803
 
762
804
  # Determine the average criticalness of all allocated resources.
763
805
  criticalness = 0.0
@@ -768,7 +810,7 @@ class TaskJuggler
768
810
 
769
811
  # The task criticalness is the product of effort and average resource
770
812
  # criticalness.
771
- @property['criticalness', @scenarioIdx] = a('effort') * criticalness
813
+ @criticalness = @effort * criticalness
772
814
  end
773
815
 
774
816
  # The path criticalness is a measure for the overall criticalness of the
@@ -781,8 +823,8 @@ class TaskJuggler
781
823
  # If we have computed this already, just return the value. If we are only
782
824
  # at the end of the task, we do not include the criticalness of this task
783
825
  # as it is not really part of the path.
784
- if a('pathcriticalness')
785
- return a('pathcriticalness') - (atEnd ? 0 : a('criticalness'))
826
+ if @pathcriticalness
827
+ return @pathcriticalness - (atEnd ? 0 : @criticalness)
786
828
  end
787
829
 
788
830
  maxCriticalness = 0.0
@@ -808,7 +850,7 @@ class TaskJuggler
808
850
  # For leaf tasks, we check all pathes through the start successors and
809
851
  # then the pathes through the end successors of this task and all its
810
852
  # parent tasks.
811
- a('startsuccs').each do |task, onEnd|
853
+ @startsuccs.each do |task, onEnd|
812
854
  if (criticalness = task.calcPathCriticalness(@scenarioIdx, onEnd)) >
813
855
  maxCriticalness
814
856
  maxCriticalness = criticalness
@@ -819,23 +861,23 @@ class TaskJuggler
819
861
  maxCriticalness = criticalness
820
862
  end
821
863
 
822
- maxCriticalness += a('criticalness')
864
+ maxCriticalness += @criticalness
823
865
  end
824
866
  end
825
867
 
826
- @property['pathcriticalness', @scenarioIdx] = maxCriticalness
868
+ @pathcriticalness = maxCriticalness
827
869
  end
828
870
 
829
871
  # Check if the task is ready to be scheduled. For this it needs to have at
830
872
  # least one specified end date and a duration criteria or the other end
831
873
  # date.
832
874
  def readyForScheduling?
833
- return false if a('scheduled') || @isRunAway
875
+ return false if @scheduled || @isRunAway
834
876
 
835
- if a('forward')
836
- return true if a('start') && (hasDurationSpec? || a('end'))
877
+ if @forward
878
+ return true if @start && (hasDurationSpec? || @end)
837
879
  else
838
- return true if a('end') && (hasDurationSpec? || a('start'))
880
+ return true if @end && (hasDurationSpec? || @start)
839
881
  end
840
882
 
841
883
  false
@@ -846,31 +888,39 @@ class TaskJuggler
846
888
  # or end date has been determined and other tasks may be ready for
847
889
  # scheduling now.
848
890
  def schedule
849
- # Is the task scheduled from start to end or vice versa?
850
- forward = a('forward')
851
- # The task may not excede the project interval.
852
- limit = @project[forward ? 'end' : 'start']
853
- # Number of seconds per time slot.
854
- slotDuration = @project['scheduleGranularity']
855
- slot = nextSlot(slotDuration)
891
+ # Compute the date of the next slot this task wants to have scheduled.
892
+ # This must either be the first slot ever or it must be directly
893
+ # adjecent to the previous slot. If this task has not yet been scheduled
894
+ # at all, @currentSlotIdx is still nil. Otherwise it contains the index
895
+ # of the last scheduled slot.
896
+ if @forward
897
+ # On first call, the @currentSlotIdx is not set yet. We set it to the
898
+ # start slot index or the 'now' slot if we are in projection mode and
899
+ # the tasks has allocations.
900
+ if @currentSlotIdx.nil?
901
+ @currentSlotIdx = @project.dateToIdx(
902
+ @projectionMode && (@project['now'] > @start) && !@allocate.empty? ?
903
+ @project['now'] : @start)
904
+ end
905
+ else
906
+ # On first call, the @currentSlotIdx is not set yet. We set it to the
907
+ # slot index of the slot before the end slot.
908
+ if @currentSlotIdx.nil?
909
+ @currentSlotIdx = @project.dateToIdx(@end) - 1
910
+ end
911
+ end
856
912
 
857
913
  # Schedule all time slots from slot in the scheduling direction until
858
914
  # the task is completed or a problem has been found.
859
- while !scheduleSlot(slot, slotDuration)
860
- if forward
861
- # The task is scheduled from start to end.
862
- slot += slotDuration
863
- if slot > limit
864
- markAsRunaway
865
- return false
866
- end
867
- else
868
- # The task is scheduled from end to start.
869
- slot -= slotDuration
870
- if slot < limit
871
- markAsRunaway
872
- return false
873
- end
915
+ # The task may not excede the project interval.
916
+ lowerLimit = @project.dateToIdx(@project['start'])
917
+ upperLimit = @project.dateToIdx(@project['end'])
918
+ delta = @forward ? 1 : -1
919
+ while scheduleSlot
920
+ @currentSlotIdx += delta
921
+ if @currentSlotIdx < lowerLimit || upperLimit < @currentSlotIdx
922
+ markAsRunaway
923
+ return false
874
924
  end
875
925
  end
876
926
 
@@ -896,21 +946,21 @@ class TaskJuggler
896
946
  # For leaf tasks, propagate start may set the date. Container task dates
897
947
  # are only set in scheduleContainer().
898
948
  if @property.leaf?
899
- @property[thisEnd, @scenarioIdx] = date
900
- Log << "Task #{@property.fullId}: #{a('start')} -> #{a('end')}"
949
+ instance_variable_set(('@' + thisEnd).intern, date)
950
+ Log << "Task #{@property.fullId}: #{@start} -> #{@end}"
901
951
  end
902
952
 
903
- if a('milestone')
953
+ if @milestone
904
954
  # Start and end date of a milestone are identical.
905
- @property['scheduled', @scenarioIdx] = true
955
+ @scheduled = true
906
956
  if a(otherEnd).nil?
907
957
  propagateDate(a(thisEnd), !atEnd)
908
958
  end
909
- Log << "Milestone #{@property.fullId}: #{a('start')} -> #{a('end')}"
910
- elsif !a('scheduled') && a('start') && a('end') &&
911
- !(a('length') == 0 && a('duration') == 0 && a('effort') == 0 &&
912
- !a('allocate').empty?)
913
- @property['scheduled', @scenarioIdx] = true
959
+ Log << "Milestone #{@property.fullId}: #{@start} -> #{@end}"
960
+ elsif !@scheduled && @start && @end &&
961
+ !(@length == 0 && @duration == 0 && @effort == 0 &&
962
+ !@allocate.empty?)
963
+ @scheduled = true
914
964
  Log << "Task #{@property.fullId} has been scheduled"
915
965
  end
916
966
 
@@ -920,21 +970,21 @@ class TaskJuggler
920
970
  # allocation. In these cases, bookResource() has to propagate the final
921
971
  # date.
922
972
  if atEnd
923
- if ignoreEffort || a('effort') == 0
924
- a('endpreds').each do |task, onEnd|
973
+ if ignoreEffort || @effort == 0
974
+ @endpreds.each do |task, onEnd|
925
975
  propagateDateToDep(task, onEnd)
926
976
  end
927
977
  end
928
- a('endsuccs').each do |task, onEnd|
978
+ @endsuccs.each do |task, onEnd|
929
979
  propagateDateToDep(task, onEnd)
930
980
  end
931
981
  else
932
- if ignoreEffort || a('effort') == 0
933
- a('startsuccs').each do |task, onEnd|
982
+ if ignoreEffort || @effort == 0
983
+ @startsuccs.each do |task, onEnd|
934
984
  propagateDateToDep(task, onEnd)
935
985
  end
936
986
  end
937
- a('startpreds').each do |task, onEnd|
987
+ @startpreds.each do |task, onEnd|
938
988
  propagateDateToDep(task, onEnd)
939
989
  end
940
990
  end
@@ -988,24 +1038,24 @@ class TaskJuggler
988
1038
 
989
1039
  # Check for tasks that have no start and end spec, no duration spec but
990
1040
  # allocates. They can inherit the start and end date.
991
- return true if hasThatSpec && !hasDurationSpec && !a('allocate').empty?
1041
+ return true if hasThatSpec && !hasDurationSpec && !@allocate.empty?
992
1042
 
993
- if a('forward') ^ atEnd
1043
+ if @forward ^ atEnd
994
1044
  # the scheduling direction is pointing away from this end
995
- return true if hasDurationSpec || !a('booking').empty?
1045
+ return true if hasDurationSpec || !@booking.empty?
996
1046
 
997
1047
  return hasThatSpec
998
1048
  else
999
1049
  # the scheduling direction is pointing towards this end
1000
1050
  return a(thatEnd) && !hasDurationSpec &&
1001
- a('booking').empty? #&& a('allocate').empty?
1051
+ @booking.empty? #&& @allocate.empty?
1002
1052
  end
1003
1053
  end
1004
1054
 
1005
1055
  # Find the smallest possible interval that encloses all child tasks. Abort
1006
1056
  # the operation if any of the child tasks are not yet scheduled.
1007
1057
  def scheduleContainer
1008
- return if a('scheduled') || !@property.container?
1058
+ return if @scheduled || !@property.container?
1009
1059
 
1010
1060
  nStart = nil
1011
1061
  nEnd = nil
@@ -1028,19 +1078,19 @@ class TaskJuggler
1028
1078
 
1029
1079
  startSet = endSet = false
1030
1080
  # Propagate the dates to other dependent tasks.
1031
- if a('start').nil? || a('start') > nStart
1032
- @property['start', @scenarioIdx] = nStart
1081
+ if @start.nil? || @start > nStart
1082
+ @start = nStart
1033
1083
  startSet = true
1034
1084
  end
1035
- if a('end').nil? || a('end') < nEnd
1036
- @property['end', @scenarioIdx] = nEnd
1085
+ if @end.nil? || @end < nEnd
1086
+ @end = nEnd
1037
1087
  endSet = true
1038
1088
  end
1039
- unless a('start') && a('end')
1040
- raise "Start (#{a('start')}) and end (#{a('end')}) must be set"
1089
+ unless @start && @end
1090
+ raise "Start (#{@start}) and end (#{@end}) must be set"
1041
1091
  end
1042
- @property['scheduled', @scenarioIdx] = true
1043
- Log << "Container task #{@property.fullId} completed: #{a('start')} -> #{a('end')}"
1092
+ @scheduled = true
1093
+ Log << "Container task #{@property.fullId} completed: #{@start} -> #{@end}"
1044
1094
 
1045
1095
  # If we have modified the start or end date, we need to communicate this
1046
1096
  # new date to surrounding tasks.
@@ -1050,7 +1100,7 @@ class TaskJuggler
1050
1100
 
1051
1101
  # Return true if the task has a effort, length or duration setting.
1052
1102
  def hasDurationSpec?
1053
- a('length') > 0 || a('duration') > 0 || a('effort') > 0 || a('milestone')
1103
+ @length > 0 || @duration > 0 || @effort > 0 || @milestone
1054
1104
  end
1055
1105
 
1056
1106
  # Find the earliest possible start date for the task. This date must be
@@ -1059,7 +1109,7 @@ class TaskJuggler
1059
1109
  def earliestStart
1060
1110
  # This is the date that we will return.
1061
1111
  startDate = nil
1062
- a('depends').each do |dependency|
1112
+ @depends.each do |dependency|
1063
1113
  potentialStartDate =
1064
1114
  dependency.task[dependency.onEnd ? 'end' : 'start', @scenarioIdx]
1065
1115
  return nil if potentialStartDate.nil?
@@ -1101,7 +1151,7 @@ class TaskJuggler
1101
1151
  # task B depends on A and they are specified this way:
1102
1152
  # task A: | --> D-
1103
1153
  # task B: -D <-- |
1104
- if a('end') && startDate > a('end')
1154
+ if @end && startDate > @end
1105
1155
  error('weak_start_dep',
1106
1156
  "Task #{@property.fullId} has a too weak start dependencies " +
1107
1157
  "to be scheduled properly.")
@@ -1116,7 +1166,7 @@ class TaskJuggler
1116
1166
  def latestEnd
1117
1167
  # This is the date that we will return.
1118
1168
  endDate = nil
1119
- a('precedes').each do |dependency|
1169
+ @precedes.each do |dependency|
1120
1170
  potentialEndDate =
1121
1171
  dependency.task[dependency.onEnd ? 'end' : 'start', @scenarioIdx]
1122
1172
  return nil if potentialEndDate.nil?
@@ -1158,7 +1208,7 @@ class TaskJuggler
1158
1208
  # task A precedes B and they are specified this way:
1159
1209
  # task A: | --> D-
1160
1210
  # task B: -D <-- |
1161
- if a('start') && (endDate.nil? || endDate > a('start'))
1211
+ if @start && (endDate.nil? || endDate > @start)
1162
1212
  error('weak_end_dep',
1163
1213
  "Task #{@property.fullId} has a too weak end dependencies " +
1164
1214
  "to be scheduled properly.")
@@ -1170,14 +1220,14 @@ class TaskJuggler
1170
1220
  def addBooking(booking)
1171
1221
  # This append operation will not trigger a copy to sub-scenarios.
1172
1222
  # Bookings are only valid for the scenario they are defined in.
1173
- @property['booking', @scenarioIdx] << booking
1223
+ @booking << booking
1174
1224
  end
1175
1225
 
1176
1226
  def query_complete(query)
1177
1227
  # If we haven't calculated the value yet, calculate it first.
1178
- unless (complete = a('complete'))
1228
+ unless (complete = @complete)
1179
1229
  calcCompletion
1180
- complete = a('complete')
1230
+ complete = @complete
1181
1231
  end
1182
1232
 
1183
1233
  query.sortable = query.numerical = complete
@@ -1195,7 +1245,7 @@ class TaskJuggler
1195
1245
  query.scopeProperty)
1196
1246
  query.string = query.currencyFormat.format(cost)
1197
1247
  else
1198
- query.string = 'No cost account'
1248
+ query.string = 'No \'balance\' defined!'
1199
1249
  end
1200
1250
  end
1201
1251
 
@@ -1203,7 +1253,7 @@ class TaskJuggler
1203
1253
  # all tasks. Also for those who did not have a 'duration' attribute.
1204
1254
  def query_duration(query)
1205
1255
  query.sortable = query.numerical = duration =
1206
- (a('end') - a('start')) / (60 * 60 * 24)
1256
+ (@end - @start) / (60 * 60 * 24)
1207
1257
  query.string = query.scaleDuration(duration)
1208
1258
  end
1209
1259
 
@@ -1245,7 +1295,7 @@ class TaskJuggler
1245
1295
  list = []
1246
1296
 
1247
1297
  # First gather the task that depend on the start of this task.
1248
- a('startsuccs').each do |task, onEnd|
1298
+ @startsuccs.each do |task, onEnd|
1249
1299
  if onEnd
1250
1300
  date = task['end', query.scenarioIdx].to_s(query.timeFormat)
1251
1301
  dep = "[->]"
@@ -1256,7 +1306,7 @@ class TaskJuggler
1256
1306
  list << generateDepencyListItem(query, task, dep, date)
1257
1307
  end
1258
1308
  # Than add the tasks that depend on the end of this task.
1259
- a('endsuccs').each do |task, onEnd|
1309
+ @endsuccs.each do |task, onEnd|
1260
1310
  if onEnd
1261
1311
  date = task['end', query.scenarioIdx].to_s(query.timeFormat)
1262
1312
  dep = "]->]"
@@ -1274,7 +1324,7 @@ class TaskJuggler
1274
1324
  list = []
1275
1325
 
1276
1326
  # First gather the task that depend on the start of this task.
1277
- a('startpreds').each do |task, onEnd|
1327
+ @startpreds.each do |task, onEnd|
1278
1328
  if onEnd
1279
1329
  date = task['end', query.scenarioIdx].to_s(query.timeFormat)
1280
1330
  dep = "]->["
@@ -1285,7 +1335,7 @@ class TaskJuggler
1285
1335
  list << generateDepencyListItem(query, task, dep, date)
1286
1336
  end
1287
1337
  # Than add the tasks that depend on the end of this task.
1288
- a('endpreds').each do |task, onEnd|
1338
+ @endpreds.each do |task, onEnd|
1289
1339
  if onEnd
1290
1340
  date = task['end', query.scenarioIdx].to_s(query.timeFormat)
1291
1341
  dep = "]->]"
@@ -1305,9 +1355,10 @@ class TaskJuggler
1305
1355
  return '' unless @property.leaf?
1306
1356
 
1307
1357
  list = []
1308
- a('assignedresources').each do |resource|
1358
+ @assignedresources.each do |resource|
1309
1359
  if resource.allocated?(@scenarioIdx,
1310
- Interval.new(query.start, query.end), @property)
1360
+ TimeInterval.new(query.start, query.end),
1361
+ @property)
1311
1362
  if query.listItem
1312
1363
  rti = RichText.new(query.listItem, RTFHandlers.create(@project),
1313
1364
  @project.messageHandler).
@@ -1334,15 +1385,15 @@ class TaskJuggler
1334
1385
  query.scopeProperty)
1335
1386
  query.string = query.currencyFormat.format(revenue)
1336
1387
  else
1337
- query.string = 'No revenue account'
1388
+ query.string = 'No \'balance\' defined!'
1338
1389
  end
1339
1390
  end
1340
1391
 
1341
1392
  def query_status(query)
1342
1393
  # If we haven't calculated the completion yet, calculate it first.
1343
- if (status = a('status')).empty?
1394
+ if (status = @status).empty?
1344
1395
  calcCompletion
1345
- status = a('status')
1396
+ status = @status
1346
1397
  end
1347
1398
 
1348
1399
  query.string = status
@@ -1374,8 +1425,8 @@ class TaskJuggler
1374
1425
  # Compute the total time _resource_ or all resources are allocated during
1375
1426
  # interval specified by _startIdx_ and _endIdx_.
1376
1427
  def getAllocatedTime(startIdx, endIdx, resource = nil)
1377
- return 0.0 if a('milestone') || startIdx >= endIdx ||
1378
- (resource && !a('assignedresources').include?(resource))
1428
+ return 0.0 if @milestone || startIdx >= endIdx ||
1429
+ (resource && !@assignedresources.include?(resource))
1379
1430
 
1380
1431
  key = [ self, :TaskScenarioAllocatedTime, startIdx, endIdx, resource ].hash
1381
1432
  @dCache.cached(key) do
@@ -1391,7 +1442,7 @@ class TaskJuggler
1391
1442
  startIdx, endIdx,
1392
1443
  @property)
1393
1444
  else
1394
- a('assignedresources').each do |r|
1445
+ @assignedresources.each do |r|
1395
1446
  allocatedTime += r.getAllocatedTime(@scenarioIdx, startIdx, endIdx,
1396
1447
  @property)
1397
1448
  end
@@ -1405,8 +1456,8 @@ class TaskJuggler
1405
1456
  # interval specified by _startIdx_ and _endIdx_. The effective work is the
1406
1457
  # actual work multiplied by the efficiency of the resource.
1407
1458
  def getEffectiveWork(startIdx, endIdx, resource = nil)
1408
- return 0.0 if a('milestone') || startIdx >= endIdx ||
1409
- (resource && !a('assignedresources').include?(resource))
1459
+ return 0.0 if @milestone || startIdx >= endIdx ||
1460
+ (resource && !@assignedresources.include?(resource))
1410
1461
 
1411
1462
  key = [ self, :TaskScenarioEffectiveWork, startIdx, endIdx, resource ].hash
1412
1463
  @dCache.cached(key) do
@@ -1421,7 +1472,7 @@ class TaskJuggler
1421
1472
  workLoad += resource.getEffectiveWork(@scenarioIdx, startIdx, endIdx,
1422
1473
  @property)
1423
1474
  else
1424
- a('assignedresources').each do |r|
1475
+ @assignedresources.each do |r|
1425
1476
  workLoad += r.getEffectiveWork(@scenarioIdx, startIdx, endIdx,
1426
1477
  @property)
1427
1478
  end
@@ -1441,9 +1492,9 @@ class TaskJuggler
1441
1492
  @dCache.cached(key) do
1442
1493
  workLoad = @dCache.load(key)
1443
1494
  il = IntervalList.new
1444
- il << Interval.new(@project['start'], @project['end'])
1495
+ il << TimeInterval.new(@project['start'], @project['end'])
1445
1496
  if @property.leaf?
1446
- unless (resources = a('assignedresources')).empty?
1497
+ unless (resources = @assignedresources).empty?
1447
1498
  # The task has assigned resources, so we can use their common time
1448
1499
  # off intervals.
1449
1500
  resources.each do |resource|
@@ -1480,7 +1531,7 @@ class TaskJuggler
1480
1531
  end
1481
1532
 
1482
1533
 
1483
- a('startsuccs').each do |dep|
1534
+ @startsuccs.each do |dep|
1484
1535
  unless dep[1]
1485
1536
  # must be a start->start dependency
1486
1537
  return true if dep[0].isDependencyOf(@scenarioIdx, task, depth)
@@ -1489,7 +1540,7 @@ class TaskJuggler
1489
1540
 
1490
1541
  return false if depth == 1
1491
1542
 
1492
- a('endsuccs').each do |dep|
1543
+ @endsuccs.each do |dep|
1493
1544
  unless dep[1]
1494
1545
  # must be an end->start dependency
1495
1546
  return true if dep[0].isDependencyOf(@scenarioIdx, task, depth - 1)
@@ -1517,7 +1568,7 @@ class TaskJuggler
1517
1568
  # Returns true of the _resource_ is assigned to this task or any of its
1518
1569
  # children.
1519
1570
  def hasResourceAllocated?(interval, resource)
1520
- return false unless a('assignedresources').include?(resource)
1571
+ return false unless @assignedresources.include?(resource)
1521
1572
 
1522
1573
  if @property.leaf?
1523
1574
  return resource.allocated?(@scenarioIdx, interval, @property)
@@ -1531,147 +1582,99 @@ class TaskJuggler
1531
1582
  end
1532
1583
 
1533
1584
  private
1534
- def scheduleSlot(slot, slotDuration)
1535
- # Tasks must always be scheduled in a single contigous fashion. @lastSlot
1536
- # indicates the slot that was used for the previous call. Depending on the
1537
- # scheduling direction the next slot must be scheduled either right before
1538
- # or after this slot. If the current slot is not directly aligned, we'll
1539
- # wait for another call with a proper slot. The function returns true
1540
- # only if a slot could be scheduled.
1541
- if a('forward')
1542
- # On first call, the @lastSlot is not set yet. We set it to the slot
1543
- # before the start slot.
1544
- if @lastSlot.nil?
1545
- @lastSlot = a('start') - slotDuration
1546
- @tentativeEnd = slot + slotDuration
1547
- end
1548
-
1549
- return false unless slot == @lastSlot + slotDuration
1550
- else
1551
- # On first call, the @lastSlot is not set yet. We set it to the slot
1552
- # to the end slot.
1553
- if @lastSlot.nil?
1554
- @lastSlot = a('end')
1555
- @tentativeStart = slot
1556
- end
1557
-
1558
- return false unless slot == @lastSlot - slotDuration
1559
- end
1560
- @lastSlot = slot
1561
1585
 
1562
- if a('length') > 0 || a('duration') > 0
1563
- # The doneDuration counts the number of scheduled slots. It is increased
1564
- # by one with every scheduled slot. The doneLength is only increased for
1565
- # global working time slots.
1566
- bookResources(slot, slotDuration)
1567
- @doneDuration += 1
1568
- if @project.isWorkingTime(slot, slot + slotDuration)
1569
- @doneLength += 1
1586
+ def scheduleSlot
1587
+ # Tasks must always be scheduled in a single contigous fashion.
1588
+ # Depending on the scheduling direction the next slot must be scheduled
1589
+ # either right before or after this slot. If the current slot is not
1590
+ # directly aligned, we'll wait for another call with a proper slot. The
1591
+ # function returns false if the task has been completely scheduled.
1592
+ case @durationType
1593
+ when :effortTask
1594
+ bookResources if @doneEffort < @effort
1595
+ if @doneEffort >= @effort
1596
+ # The specified effort has been reached. The task has been fully
1597
+ # scheduled now.
1598
+ if @forward
1599
+ propagateDate(@project.idxToDate(@currentSlotIdx + 1), true, true)
1600
+ else
1601
+ propagateDate(@project.idxToDate(@currentSlotIdx), false, true)
1602
+ end
1603
+ return false
1570
1604
  end
1605
+ when :lengthTask
1606
+ bookResources
1607
+ # The doneLength is only increased for global working time slots.
1608
+ @doneLength += 1 if @project.isWorkingTime(@currentSlotIdx)
1571
1609
 
1572
1610
  # If we have reached the specified duration or lengths, we set the end
1573
1611
  # or start date and propagate the value to neighbouring tasks.
1574
- if (a('length') > 0 && @doneLength >= a('length')) ||
1575
- (a('duration') > 0 && @doneDuration >= a('duration'))
1576
- if a('forward')
1577
- propagateDate(slot + slotDuration, true)
1612
+ if @doneLength >= @length
1613
+ if @forward
1614
+ propagateDate(@project.idxToDate(@currentSlotIdx + 1), true)
1578
1615
  else
1579
- propagateDate(slot, false)
1616
+ propagateDate(@project.idxToDate(@currentSlotIdx), false)
1580
1617
  end
1581
- return true
1618
+ return false
1582
1619
  end
1583
- elsif a('effort') > 0
1584
- bookResources(slot, slotDuration) if @doneEffort < a('effort')
1585
- if @doneEffort >= a('effort')
1586
- # The specified effort has been reached. The task has been fully
1587
- # scheduled now.
1588
- if a('forward')
1589
- propagateDate(@tentativeEnd, true, true)
1620
+ when :durationTask
1621
+ # The doneDuration counts the number of scheduled slots. It is increased
1622
+ # by one with every scheduled slot.
1623
+ bookResources
1624
+ @doneDuration += 1
1625
+
1626
+ # If we have reached the specified duration or lengths, we set the end
1627
+ # or start date and propagate the value to neighbouring tasks.
1628
+ if @doneDuration >= @duration
1629
+ if @forward
1630
+ propagateDate(@project.idxToDate(@currentSlotIdx + 1), true)
1590
1631
  else
1591
- propagateDate(@tentativeStart, false, true)
1632
+ propagateDate(@project.idxToDate(@currentSlotIdx), false)
1592
1633
  end
1593
- return true
1594
- end
1595
- elsif a('milestone')
1596
- if a('forward')
1597
- propagateDate(a('start'), true)
1598
- else
1599
- propagateDate(a('end'), false)
1634
+ return false
1600
1635
  end
1601
- return true
1602
- elsif a('start') && a('end')
1636
+ when :startEndTask
1603
1637
  # Task with start and end date but no duration criteria
1604
- if a('allocate').empty?
1605
- # For start-end-tasks without allocation, we don't have to do
1606
- # anything but to set the 'scheduled' flag.
1607
- @property['scheduled', @scenarioIdx] = true
1608
- @property.parents.each do |parent|
1609
- parent.scheduleContainer(@scenarioIdx)
1610
- end
1611
- return true
1612
- end
1613
-
1614
- bookResources(slot, slotDuration)
1638
+ bookResources
1615
1639
 
1616
1640
  # Depending on the scheduling direction we can mark the task as
1617
1641
  # scheduled once we have reached the other end.
1618
- if (a('forward') && slot + slotDuration >= a('end')) ||
1619
- (!a('forward') && slot <= a('start'))
1620
- @property['scheduled', @scenarioIdx] = true
1642
+ currentSlot = @project.idxToDate(@currentSlotIdx)
1643
+ if (@forward && currentSlot + @project['scheduleGranularity'] >= @end) ||
1644
+ (!@forward && currentSlot <= @start)
1645
+ @scheduled = true
1621
1646
  @property.parents.each do |parent|
1622
1647
  parent.scheduleContainer(@scenarioIdx)
1623
1648
  end
1624
- return true
1649
+ return false
1625
1650
  end
1651
+ else
1652
+ raise "Unknown task duration type #{@durationType}"
1626
1653
  end
1627
1654
 
1628
- false
1655
+ true
1629
1656
  end
1630
1657
 
1631
- # Return the date of the next slot this task wants to have scheduled. This
1632
- # must either be the first slot ever or it must be directly adjecent to the
1633
- # previous slot. If this task has not yet been scheduled at all, @lastSlot
1634
- # is still nil. Otherwise it contains the date of the last scheduled slot.
1635
- def nextSlot(slotDuration)
1636
- return nil if a('scheduled') || @isRunAway
1658
+ def bookResources
1659
+ # First check if there is any resource at all for this slot.
1660
+ return true unless @project.anyResourceAvailable?(@currentSlotIdx)
1637
1661
 
1638
- if a('forward')
1639
- @lastSlot.nil? ? a('start') : @lastSlot + slotDuration
1640
- else
1641
- @lastSlot.nil? ? a('end') - slotDuration : @lastSlot - slotDuration
1642
- end
1643
- end
1644
-
1645
- def bookResources(date, slotDuration)
1646
- # If there are no allocations defined, we can't do any bookings.
1647
- # In projection mode we do not allow allocations prior to the current
1648
- # date. If the scenario is not scheduled in projection mode, this
1649
- # restriction only applies to tasks with bookings.
1650
- if a('allocate').empty? ||
1651
- ((@project.scenario(@scenarioIdx).get('projection') ||
1652
- !a('booking').empty?) &&
1653
- date < @project['now'])
1654
- return
1655
- end
1662
+ # If the task has resource independent allocation limits we need to make
1663
+ # sure that none of them is already exceeded.
1664
+ return unless limitsOk?(@currentSlotIdx)
1656
1665
 
1657
1666
  # If the task has shifts to limit the allocations, we check that we are
1658
1667
  # within a defined shift interval. If yes, we need to be on shift to
1659
1668
  # continue.
1660
- if (shifts = a('shifts')) && shifts.assigned?(date)
1661
- return if !shifts.onShift?(date)
1669
+ if @shifts && @shifts.assigned?(@currentSlotIdx)
1670
+ return if !@shifts.onShift?(@currentSlotIdx)
1662
1671
  end
1663
1672
 
1664
- # If the task has resource independent allocation limits we need to make
1665
- # sure that none of them is already exceeded.
1666
- return unless limitsOk?(date)
1667
-
1668
- sbIdx = @project.dateToIdx(date, false)
1669
-
1670
1673
  # We first have to make sure that if there are mandatory resources
1671
1674
  # that these are all available for the time slot.
1672
1675
  takenMandatories = []
1673
1676
  @mandatories.each do |allocation|
1674
- return unless allocation.onShift?(date)
1677
+ return unless allocation.onShift?(@currentSlotIdx)
1675
1678
 
1676
1679
  # For mandatory allocations with alternatives at least one of the
1677
1680
  # alternatives must be available.
@@ -1681,8 +1684,8 @@ class TaskJuggler
1681
1684
  # group must be available.
1682
1685
  allAvailable = true
1683
1686
  candidate.allLeaves.each do |resource|
1684
- if !limitsOk?(date, resource) ||
1685
- !resource.available?(@scenarioIdx, sbIdx) ||
1687
+ if !limitsOk?(@currentSlotIdx, resource) ||
1688
+ !resource.available?(@scenarioIdx, @currentSlotIdx) ||
1686
1689
  takenMandatories.include?(resource)
1687
1690
  # We've found a mandatory resource that is not available for
1688
1691
  # the slot.
@@ -1702,19 +1705,19 @@ class TaskJuggler
1702
1705
  return unless found
1703
1706
  end
1704
1707
 
1705
- a('allocate').each do |allocation|
1706
- next unless allocation.onShift?(date)
1708
+ @allocate.each do |allocation|
1709
+ next unless allocation.onShift?(@currentSlotIdx)
1707
1710
 
1708
- # In case we have a persistent allocation we need to check if there is
1709
- # already a locked resource and use it.
1710
- if allocation.persistent && !allocation.lockedResource.nil?
1711
- bookResource(allocation.lockedResource, sbIdx, date)
1711
+ # In case we have a persistent allocation we need to check if there
1712
+ # is already a locked resource and use it.
1713
+ if allocation.lockedResource
1714
+ bookResource(allocation.lockedResource)
1712
1715
  else
1713
1716
  # If not, we create a list of candidates in the proper order and
1714
1717
  # assign the first one available.
1715
1718
  allocation.candidates(@scenarioIdx).each do |candidate|
1716
- if bookResource(candidate, sbIdx, date)
1717
- allocation.lockedResource = candidate
1719
+ if bookResource(candidate)
1720
+ allocation.lockedResource = candidate if allocation.persistent
1718
1721
  break
1719
1722
  end
1720
1723
  end
@@ -1722,49 +1725,46 @@ class TaskJuggler
1722
1725
  end
1723
1726
  end
1724
1727
 
1725
- def bookResource(resource, sbIdx, date)
1728
+ def bookResource(resource)
1726
1729
  booked = false
1727
1730
  resource.allLeaves.each do |r|
1728
1731
  # Prevent overbooking when multiple resources are allocated and
1729
1732
  # available. If the task has allocation limits we need to make sure
1730
1733
  # that none of them is already exceeded.
1731
- break if a('effort') > 0 && @doneEffort >= a('effort') ||
1732
- !limitsOk?(date, resource)
1734
+ break if @effort > 0 && @doneEffort >= @effort ||
1735
+ !limitsOk?(@currentSlotIdx, resource)
1733
1736
 
1734
- if r.book(@scenarioIdx, sbIdx, @property)
1737
+ if r.book(@scenarioIdx, @currentSlotIdx, @property)
1735
1738
  # For effort based task we adjust the the start end (as defined by
1736
1739
  # the scheduling direction) to align with the first booked time
1737
1740
  # slot.
1738
- if a('effort') > 0 && a('assignedresources').empty?
1739
- if a('forward')
1740
- @property['start', @scenarioIdx] = @project.idxToDate(sbIdx)
1741
+ if @effort > 0 && @assignedresources.empty?
1742
+ if @forward
1743
+ @start = @project.idxToDate(@currentSlotIdx)
1741
1744
  Log << "Task #{@property.fullId} first assignment: " +
1742
- "#{a('start')} -> #{a('end')}"
1743
- a('startsuccs').each do |task, onEnd|
1744
- task.propagateDate(@scenarioIdx, a('start'), false, true)
1745
+ "#{@start} -> #{@end}"
1746
+ @startsuccs.each do |task, onEnd|
1747
+ task.propagateDate(@scenarioIdx, @start, false, true)
1745
1748
  end
1746
1749
  else
1747
- @property['end', @scenarioIdx] = @project.idxToDate(sbIdx + 1)
1750
+ @end = @project.idxToDate(@currentSlotIdx + 1)
1748
1751
  Log << "Task #{@property.fullId} last assignment: " +
1749
- "#{a('start')} -> #{a('end')}"
1750
- a('endpreds').each do |task, onEnd|
1751
- task.propagateDate(@scenarioIdx, a('end'), true, true)
1752
+ "#{@start} -> #{@end}"
1753
+ @endpreds.each do |task, onEnd|
1754
+ task.propagateDate(@scenarioIdx, @end, true, true)
1752
1755
  end
1753
1756
  end
1754
1757
  end
1755
1758
 
1756
- @tentativeStart = @project.idxToDate(sbIdx)
1757
- @tentativeEnd = @project.idxToDate(sbIdx + 1)
1758
-
1759
1759
  @doneEffort += r['efficiency', @scenarioIdx]
1760
1760
  # Limits do not take efficiency into account. Limits are usage limits,
1761
1761
  # not effort limits.
1762
- @limits.each do |limit|
1763
- limit.inc(date, resource)
1762
+ @allLimits.each do |limit|
1763
+ limit.inc(@currentSlotIdx, resource)
1764
1764
  end
1765
1765
 
1766
- unless a('assignedresources').include?(r)
1767
- @property['assignedresources', @scenarioIdx] << r
1766
+ unless @assignedresources.include?(r)
1767
+ @assignedresources << r
1768
1768
  end
1769
1769
  booked = true
1770
1770
  end
@@ -1773,13 +1773,13 @@ class TaskJuggler
1773
1773
  booked
1774
1774
  end
1775
1775
 
1776
- # Check if all of the task limits are not exceded at the given _date_. If
1776
+ # Check if all of the task limits are not exceded at the given _sbIdx_. If
1777
1777
  # a _resource_ is provided, the limit for that particular resource is
1778
1778
  # checked. If no resource is provided, only non-resource-specific limits
1779
1779
  # are checked.
1780
- def limitsOk?(date, resource = nil)
1781
- @limits.each do |limit|
1782
- return false if !limit.ok?(date, true, resource)
1780
+ def limitsOk?(sbIdx, resource = nil)
1781
+ @allLimits.each do |limit|
1782
+ return false unless limit.ok?(sbIdx, true, resource)
1783
1783
  end
1784
1784
  true
1785
1785
  end
@@ -1797,67 +1797,137 @@ class TaskJuggler
1797
1797
 
1798
1798
  # Register the user provided bookings with the Resource scoreboards. A
1799
1799
  # booking describes the assignment of a Resource to a certain Task for a
1800
- # specified Interval.
1800
+ # specified TimeInterval.
1801
1801
  def bookBookings
1802
- scheduled = a('scheduled')
1803
- slotDuration = @project['scheduleGranularity']
1802
+ firstSlotIdx = nil
1803
+ lastSlotIdx = nil
1804
1804
  findBookings.each do |booking|
1805
1805
  unless booking.resource.leaf?
1806
1806
  error('booking_resource_not_leaf',
1807
1807
  "Booked resources may not be group resources",
1808
1808
  booking.sourceFileInfo)
1809
1809
  end
1810
- unless a('forward') || scheduled
1810
+ unless @forward || @scheduled
1811
1811
  error('booking_forward_only',
1812
1812
  "Only forward scheduled tasks may have booking statements.")
1813
1813
  end
1814
1814
  booking.intervals.each do |interval|
1815
1815
  startIdx = @project.dateToIdx(interval.start, false)
1816
- date = interval.start
1817
1816
  endIdx = @project.dateToIdx(interval.end, false)
1818
- tEnd = nil
1819
1817
  startIdx.upto(endIdx - 1) do |idx|
1820
- tEnd = date + slotDuration
1821
1818
  if booking.resource.bookBooking(@scenarioIdx, idx, booking)
1822
1819
  # Booking was successful for this time slot.
1823
1820
  @doneEffort += booking.resource['efficiency', @scenarioIdx]
1824
1821
 
1825
- # Set start and lastSlot if appropriate. The task start will be
1826
- # set to the begining of the first booked slot. The lastSlot
1827
- # will be set to the last booked slot
1828
- @lastSlot = date if @lastSlot.nil? || date > @lastSlot
1829
- @tentativeEnd = tEnd if @tentativeEnd.nil? || @tentativeEnd < tEnd
1830
- if !scheduled && (a('start').nil? || date < a('start'))
1831
- @property['start', @scenarioIdx] = date
1832
- Log << "Task #{@property.fullId} first booking: " +
1833
- "#{a('start')} -> #{a('end')}"
1834
- end
1822
+ # Store the indexes of the first slot and the slot after the
1823
+ # last slot.
1824
+ firstSlotIdx = idx if !firstSlotIdx || firstSlotIdx > idx
1825
+ lastSlotIdx = idx if !lastSlotIdx || lastSlotIdx < idx
1835
1826
 
1836
- unless a('assignedresources').include?(booking.resource)
1837
- @property['assignedresources', @scenarioIdx] << booking.resource
1827
+ unless @assignedresources.include?(booking.resource)
1828
+ @assignedresources << booking.resource
1838
1829
  end
1839
1830
  end
1840
- if a('length') > 0 && @project.isWorkingTime(date)
1841
- # For tasks with a 'length' we track the covered work time and
1842
- # set the task to 'scheduled' when we have enough length.
1843
- @doneLength += 1
1844
- if !scheduled && @doneLength >= a('length')
1845
- @property['end', @scenarioIdx] = tEnd
1846
- @property['scheduled', @scenarioIdx] = true
1847
- end
1848
- end
1849
- date = tEnd
1850
1831
  end
1851
- if a('duration') > 0 && @tentativeEnd
1852
- @doneDuration = ((@tentativeEnd - a('start')) /
1853
- @project['scheduleGranularity']).to_i
1854
- if !scheduled && @doneDuration >= a('duration')
1855
- @property['end', @scenarioIdx] = @tentativeEnd
1856
- @property['scheduled', @scenarioIdx] = true
1832
+ end
1833
+ end
1834
+
1835
+ # For effort based tasks, or tasks without a start date, with bookings
1836
+ # that have not yet been marked as scheduled we set the start date to
1837
+ # the date of the first booked slot.
1838
+ if (@start.nil? || (@doneEffort > 0 && @effort > 0)) &&
1839
+ !@scheduled && firstSlotIdx
1840
+ firstSlotDate = @project.idxToDate(firstSlotIdx)
1841
+ if @start.nil? || firstSlotDate > @start
1842
+ @start = firstSlotDate
1843
+ Log << "Task #{@property.fullId} first booking: " +
1844
+ "#{@start} -> #{@end}"
1845
+ end
1846
+ end
1847
+
1848
+ # Check if the the duration criteria has already been reached by the
1849
+ # supplied bookings and set the task end to the last booked slot.
1850
+ # Also the task is marked as scheduled.
1851
+ if lastSlotIdx && !@scheduled
1852
+ tentativeEnd = @project.idxToDate(lastSlotIdx + 1)
1853
+ slotDuration = @project['scheduleGranularity']
1854
+
1855
+ if @effort > 0
1856
+ if @doneEffort >= @effort
1857
+ @end = tentativeEnd
1858
+ @scheduled = true
1859
+ end
1860
+ elsif @length > 0
1861
+ @doneLength = 0
1862
+ startIdx = @project.dateToIdx(date = @start)
1863
+ endIdx = @project.dateToIdx(@project['now'])
1864
+ startIdx.upto(endIdx) do |idx|
1865
+ @doneLength += 1 if @project.isWorkingTime(idx)
1866
+ date += slotDuration
1867
+ # Continue not only until the @length has been reached, but also
1868
+ # the tentativeEnd date. This allows us to detect overbookings.
1869
+ if @doneLength >= @length && date >= tentativeEnd
1870
+ endDate = @project.idxToDate(idx + 1)
1871
+ @end = [ endDate, tentativeEnd ].max
1872
+ @scheduled = true
1873
+ break
1857
1874
  end
1858
1875
  end
1876
+ elsif @duration > 0
1877
+ @doneDuration = ((tentativeEnd - @start) / slotDuration).to_i
1878
+ if @doneDuration >= @duration
1879
+ @end = tentativeEnd
1880
+ @scheduled = true
1881
+ elsif @duration * slotDuration < (@project['now'] - @start)
1882
+ # This handles the case where the bookings don't provide enough
1883
+ # @doneDuration to reach @duration, but the now date would be
1884
+ # after the @start + @duration date.
1885
+ @end = @start + @duration * slotDuration
1886
+ @scheduled = true
1887
+ end
1888
+ end
1889
+ end
1890
+
1891
+ # If the task has bookings, we assume that the bookings describe all
1892
+ # work up to the 'now' date.
1893
+ if @doneEffort > 0
1894
+ @currentSlotIdx = @project.dateToIdx(@project['now'])
1895
+ end
1896
+
1897
+ # Finally, we check if the bookings caused more effort, length or
1898
+ # duration than was requested by the user. This is only flagged as a
1899
+ # warning.
1900
+ if @effort > 0
1901
+ effort = @project.slotsToDays(@doneEffort)
1902
+ effortHours = effort * @project['dailyworkinghours']
1903
+ requestedEffort = @project.slotsToDays(@effort)
1904
+ requestedEffortHours = requestedEffort * @project['dailyworkinghours']
1905
+ if effort > requestedEffort
1906
+ warning('overbooked_effort',
1907
+ "The total effort (#{effort}d or #{effortHours}h) of the " +
1908
+ "provided bookings for task #{@property.fullId} exceeds " +
1909
+ "the specified effort of #{requestedEffort}d or " +
1910
+ "#{requestedEffortHours}h.")
1859
1911
  end
1860
1912
  end
1913
+ if @length > 0 && @doneLength > @length
1914
+ length = @project.slotsToDays(@doneLength)
1915
+ requestedLength = @project.slotsToDays(@length)
1916
+ warning('overbooked_length',
1917
+ "The total length (#{length}d) of the provided bookings " +
1918
+ "for task #{@property.fullId} exceeds the specified length of " +
1919
+ "#{requestedLength}d.")
1920
+ end
1921
+ if @duration > 0 && @doneDuration > @duration
1922
+ duration = @doneDuration * @project['scheduleGranularity'] /
1923
+ (60.0 * 60 * 24)
1924
+ requestedDuration = @duration * @project['scheduleGranularity'] /
1925
+ (60.0 * 60 * 24)
1926
+ warning('overbooked_duration',
1927
+ "The total duration (#{duration}d) of the provided bookings " +
1928
+ "for task #{@property.fullId} exceeds the specified duration " +
1929
+ "of #{requestedDuration}d.")
1930
+ end
1861
1931
  end
1862
1932
 
1863
1933
  # This function checks if the task has a dependency on another task or
@@ -1943,23 +2013,23 @@ class TaskJuggler
1943
2013
  # dependency no matter how it was set.
1944
2014
  unless atEnd
1945
2015
  # Row 1
1946
- a('startpreds').each do |task, onEnd|
2016
+ @startpreds.each do |task, onEnd|
1947
2017
  if (onEnd && (task['forward', @scenarioIdx] ||
1948
2018
  task['end', @scenarioIdx])) || !onEnd
1949
2019
  return true
1950
2020
  end
1951
2021
  end
1952
2022
  # Row 2
1953
- a('startsuccs').each do |task, onEnd|
2023
+ @startsuccs.each do |task, onEnd|
1954
2024
  return true if task[onEnd ? 'end' : 'start', @scenarioIdx]
1955
2025
  end
1956
2026
  else
1957
2027
  # Row 3
1958
- a('endpreds').each do |task, onEnd|
2028
+ @endpreds.each do |task, onEnd|
1959
2029
  return true if task[onEnd ? 'end' : 'start', @scenarioIdx]
1960
2030
  end
1961
2031
  # Row 4
1962
- a('endsuccs').each do |task, onEnd|
2032
+ @endsuccs.each do |task, onEnd|
1963
2033
  if (!onEnd && (!task['forward', @scenarioIdx] ||
1964
2034
  task['start', @scenarioIdx])) || onEnd
1965
2035
  return true
@@ -1977,11 +2047,11 @@ class TaskJuggler
1977
2047
  @isRunAway = true
1978
2048
  end
1979
2049
 
1980
- # This function determines if a task is really a milestones and marks them
2050
+ # This function determines if a task is a milestones and marks it
1981
2051
  # accordingly.
1982
2052
  def markMilestone
1983
2053
  return if @property.container? || hasDurationSpec? ||
1984
- !a('booking').empty? || !a('allocate').empty?
2054
+ !@booking.empty? || !@allocate.empty?
1985
2055
 
1986
2056
  # The following cases qualify for an automatic milestone promotion.
1987
2057
  # - --> -
@@ -1992,19 +2062,19 @@ class TaskJuggler
1992
2062
  # - <-- |
1993
2063
  # - <-- -D
1994
2064
  # - <-- |D
1995
- hasStartSpec = !a('start').nil? || !a('depends').empty?
1996
- hasEndSpec = !a('end').nil? || !a('precedes').empty?
2065
+ hasStartSpec = !@start.nil? || !@depends.empty?
2066
+ hasEndSpec = !@end.nil? || !@precedes.empty?
1997
2067
 
1998
- @property['milestone', @scenarioIdx] =
1999
- (hasStartSpec && a('forward') && !hasEndSpec) ||
2000
- (!hasStartSpec && !a('forward') && hasEndSpec) ||
2001
- (!hasStartSpec && !hasEndSpec)
2068
+ @milestone = (hasStartSpec && @forward && !hasEndSpec) ||
2069
+ (!hasStartSpec && !@forward && hasEndSpec) ||
2070
+ (!hasStartSpec && !hasEndSpec)
2002
2071
  end
2003
2072
 
2004
2073
  def checkDependency(dependency, depType)
2074
+ depList = instance_variable_get(('@' + depType).intern)
2005
2075
  if (depTask = dependency.resolve(@project)).nil?
2006
2076
  # Remove the broken dependency. It could cause trouble later on.
2007
- @property[depType, @scenarioIdx].delete(dependency)
2077
+ depList.delete(dependency)
2008
2078
  error('task_depend_unknown',
2009
2079
  "Task #{@property.fullId} has unknown #{depType} " +
2010
2080
  "#{dependency.taskId}")
@@ -2012,14 +2082,14 @@ class TaskJuggler
2012
2082
 
2013
2083
  if depTask == @property
2014
2084
  # Remove the broken dependency. It could cause trouble later on.
2015
- @property[depType, @scenarioIdx].delete(dependency)
2085
+ depList.delete(dependency)
2016
2086
  error('task_depend_self', "Task #{@property.fullId} cannot " +
2017
2087
  "depend on self")
2018
2088
  end
2019
2089
 
2020
2090
  if depTask.isChildOf?(@property)
2021
2091
  # Remove the broken dependency. It could cause trouble later on.
2022
- @property[depType, @scenarioIdx].delete(dependency)
2092
+ depList.delete(dependency)
2023
2093
  error('task_depend_child',
2024
2094
  "Task #{@property.fullId} cannot depend on child " +
2025
2095
  "#{depTask.fullId}")
@@ -2027,16 +2097,16 @@ class TaskJuggler
2027
2097
 
2028
2098
  if @property.isChildOf?(depTask)
2029
2099
  # Remove the broken dependency. It could cause trouble later on.
2030
- @property[depType, @scenarioIdx].delete(dependency)
2100
+ depList.delete(dependency)
2031
2101
  error('task_depend_parent',
2032
2102
  "Task #{@property.fullId} cannot depend on parent " +
2033
2103
  "#{depTask.fullId}")
2034
2104
  end
2035
2105
 
2036
- @property[depType, @scenarioIdx].each do |dep|
2106
+ depList.each do |dep|
2037
2107
  if dep.task == depTask && !dep.equal?(dependency)
2038
2108
  # Remove the broken dependency. It could cause trouble later on.
2039
- @property[depType, @scenarioIdx].delete(dependency)
2109
+ depList.delete(dependency)
2040
2110
  error('task_depend_multi',
2041
2111
  "No need to specify dependency #{depTask.fullId} multiple " +
2042
2112
  "times for task #{@property.fullId}.")
@@ -2111,23 +2181,21 @@ class TaskJuggler
2111
2181
  # If the user provided a completion degree we are not touching it.
2112
2182
  if @property.provided('complete', @scenarioIdx)
2113
2183
  calcStatus
2114
- return a('complete')
2184
+ return @complete
2115
2185
  end
2116
2186
 
2117
2187
  # We cannot compute a completion degree without a start or end date.
2118
- if a('start').nil? || a('end').nil?
2119
- @property['complete', @scenarioIdx] = 0.0
2120
- @property['status', @scenarioIdx] = 'unknown'
2188
+ if @start.nil? || @end.nil?
2189
+ @complete = 0.0
2190
+ @status = 'unknown'
2121
2191
  return nil
2122
2192
  end
2123
2193
 
2124
2194
  completion = 0.0
2125
- if a('milestone')
2195
+ if @milestone
2126
2196
  # Milestones are either 0% or 100% complete.
2127
- @property['complete', @scenarioIdx] = completion =
2128
- @property['end', @scenarioIdx] <= @project['now'] ? 100.0 : 0.0
2129
- @property['status', @scenarioIdx] =
2130
- a('end') <= @project['now'] ? 'done' : 'not reached'
2197
+ @complete = completion = @end <= @project['now'] ? 100.0 : 0.0
2198
+ @status = @end <= @project['now'] ? 'done' : 'not reached'
2131
2199
  else
2132
2200
  # The task is in progress. Calculate the current completion
2133
2201
  # degree.
@@ -2140,26 +2208,26 @@ class TaskJuggler
2140
2208
  completion += comp
2141
2209
  end
2142
2210
  completion /= @property.children.length
2143
- elsif a('end') <= @project['now']
2211
+ elsif @end <= @project['now']
2144
2212
  # The task has ended already. It's 100% complete.
2145
2213
  completion = 100.0
2146
- elsif @project['now'] <= a('start')
2214
+ elsif @project['now'] <= @start
2147
2215
  # The task has not started yet. Its' 0% complete.
2148
2216
  completion = 0.0
2149
- elsif a('effort') > 0
2217
+ elsif @effort > 0
2150
2218
  # Effort based leaf tasks. The completion degree is the percentage
2151
2219
  # of effort that has been done already.
2152
- done = getEffectiveWork(@project.dateToIdx(a('start'), false),
2220
+ done = getEffectiveWork(@project.dateToIdx(@start, false),
2153
2221
  @project.dateToIdx(@project['now']))
2154
2222
  total = @project.convertToDailyLoad(
2155
- a('effort') * @project['scheduleGranularity'])
2223
+ @effort * @project['scheduleGranularity'])
2156
2224
  completion = done / total * 100.0
2157
2225
  else
2158
2226
  # Length/duration leaf tasks.
2159
- completion = ((@project['now'] - a('start')) /
2160
- (a('end') - a('start'))) * 100.0
2227
+ completion = ((@project['now'] - @start) /
2228
+ (@end - @start)) * 100.0
2161
2229
  end
2162
- @property['complete', @scenarioIdx] = completion
2230
+ @complete = completion
2163
2231
  calcStatus
2164
2232
  end
2165
2233
 
@@ -2168,14 +2236,13 @@ class TaskJuggler
2168
2236
 
2169
2237
  # Calculate the status of the task based on the 'complete' attribute.
2170
2238
  def calcStatus
2171
- @property['status', @scenarioIdx] =
2172
- if a('complete') == 0.0
2173
- 'not started'
2174
- elsif a('complete') >= 100.0
2175
- 'done'
2176
- else
2177
- 'in progress'
2178
- end
2239
+ @status = if @complete == 0.0
2240
+ 'not started'
2241
+ elsif @complete >= 100.0
2242
+ 'done'
2243
+ else
2244
+ 'in progress'
2245
+ end
2179
2246
  end
2180
2247
 
2181
2248
  # Recursively compile a list of Task properties which depend on the
@@ -2187,12 +2254,12 @@ class TaskJuggler
2187
2254
  # A target must be a leaf function that has no direct or indirect
2188
2255
  # (through parent) following tasks. Only milestones are recognized as
2189
2256
  # targets.
2190
- if @property.leaf? && !hasPredecessors && a('milestone')
2257
+ if @property.leaf? && !hasPredecessors && @milestone
2191
2258
  list << @property
2192
2259
  return
2193
2260
  end
2194
2261
 
2195
- a('startpreds').each do |t, onEnd|
2262
+ @startpreds.each do |t, onEnd|
2196
2263
  t.inputs(@scenarioIdx, list, false)
2197
2264
  end
2198
2265
 
@@ -2220,12 +2287,12 @@ class TaskJuggler
2220
2287
  # A target must be a leaf function that has no direct or indirect
2221
2288
  # (through parent) following tasks. Only milestones are recognized as
2222
2289
  # targets.
2223
- if @property.leaf? && !hasSuccessors && a('milestone')
2290
+ if @property.leaf? && !hasSuccessors && @milestone
2224
2291
  list << @property
2225
2292
  return
2226
2293
  end
2227
2294
 
2228
- a('endsuccs').each do |t, onEnd|
2295
+ @endsuccs.each do |t, onEnd|
2229
2296
  t.targets(@scenarioIdx, list, false)
2230
2297
  end
2231
2298
 
@@ -2260,7 +2327,7 @@ class TaskJuggler
2260
2327
 
2261
2328
  # If there are no chargeset defined for this task, we don't need to
2262
2329
  # compute the resource related or other cost.
2263
- unless a('chargeset').empty?
2330
+ unless @chargeset.empty?
2264
2331
  resourceCost = 0.0
2265
2332
  otherCost = 0.0
2266
2333
 
@@ -2270,27 +2337,27 @@ class TaskJuggler
2270
2337
  resourceCost = resource.cost(@scenarioIdx, startIdx, endIdx,
2271
2338
  @property)
2272
2339
  else
2273
- a('assignedresources').each do |r|
2340
+ @assignedresources.each do |r|
2274
2341
  resourceCost += r.cost(@scenarioIdx, startIdx, endIdx, @property)
2275
2342
  end
2276
2343
  end
2277
2344
  end
2278
2345
 
2279
- unless a('charge').empty?
2346
+ unless @charge.empty?
2280
2347
  # Add one-time and periodic charges to the amount.
2281
2348
  startDate = startIdx.is_a?(TjTime) ? startIdx :
2282
2349
  @project.idxToDate(startIdx)
2283
2350
  endDate = endIdx.is_a?(TjTime) ? endIdx :
2284
2351
  @project.idxToDate(endIdx)
2285
- iv = Interval.new(startDate, endDate)
2286
- a('charge').each do |charge|
2352
+ iv = TimeInterval.new(startDate, endDate)
2353
+ @charge.each do |charge|
2287
2354
  otherCost += charge.turnover(iv)
2288
2355
  end
2289
2356
  end
2290
2357
 
2291
2358
  totalCost = resourceCost + otherCost
2292
2359
  # Now weight the total cost by the share of the account
2293
- a('chargeset').each do |set|
2360
+ @chargeset.each do |set|
2294
2361
  set.each do |accnt, share|
2295
2362
  if share > 0.0 && (accnt == account || accnt.isChildOf?(account))
2296
2363
  amount += totalCost * share