taskjuggler 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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