taskjuggler 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (410) hide show
  1. data/CHANGELOG +44 -0
  2. data/bin/tj3webd +4 -0
  3. data/data/css/tjreport.css +14 -5
  4. data/data/tjp.vim +22 -7
  5. data/examples/Fedora-20/reports.tji +2 -4
  6. data/examples/Scrum/Product Burndown.csv +26 -0
  7. data/examples/Scrum/Sprint 1 Burndown.csv +26 -0
  8. data/examples/Scrum/Sprint 2 Burndown.csv +26 -0
  9. data/examples/Scrum/Sprint 3 Burndown.csv +26 -0
  10. data/examples/Scrum/scrum.tjp +141 -0
  11. data/examples/Tutorial/tutorial.tjp +13 -7
  12. data/lib/taskjuggler/Attributes.rb +2 -3
  13. data/lib/taskjuggler/HTMLDocument.rb +25 -18
  14. data/lib/taskjuggler/Journal.rb +85 -65
  15. data/lib/taskjuggler/KeywordDocumentation.rb +25 -13
  16. data/lib/taskjuggler/LeaveList.rb +1 -1
  17. data/lib/taskjuggler/Limits.rb +3 -5
  18. data/lib/taskjuggler/MessageHandler.rb +173 -19
  19. data/lib/taskjuggler/Painter.rb +75 -0
  20. data/lib/taskjuggler/Painter/BasicShapes.rb +76 -0
  21. data/lib/taskjuggler/Painter/Color.rb +273 -0
  22. data/lib/taskjuggler/Painter/Element.rb +56 -0
  23. data/lib/taskjuggler/Painter/FontData.rb +221 -0
  24. data/lib/taskjuggler/Painter/FontMetrics.rb +125 -0
  25. data/lib/taskjuggler/Painter/FontMetricsData.rb +151 -0
  26. data/lib/taskjuggler/Painter/Group.rb +77 -0
  27. data/lib/taskjuggler/Painter/Points.rb +47 -0
  28. data/lib/taskjuggler/Painter/Primitives.rb +100 -0
  29. data/lib/taskjuggler/Painter/SVGSupport.rb +36 -0
  30. data/lib/taskjuggler/Painter/Text.rb +36 -0
  31. data/lib/taskjuggler/Project.rb +46 -29
  32. data/lib/taskjuggler/ProjectFileParser.rb +24 -22
  33. data/lib/taskjuggler/ProjectFileScanner.rb +2 -2
  34. data/lib/taskjuggler/PropertyTreeNode.rb +26 -34
  35. data/lib/taskjuggler/Query.rb +8 -5
  36. data/lib/taskjuggler/RealFormat.rb +3 -0
  37. data/lib/taskjuggler/Resource.rb +3 -5
  38. data/lib/taskjuggler/ResourceScenario.rb +19 -7
  39. data/lib/taskjuggler/RichText.rb +4 -6
  40. data/lib/taskjuggler/RichText/FunctionExample.rb +1 -1
  41. data/lib/taskjuggler/RichText/FunctionHandler.rb +5 -6
  42. data/lib/taskjuggler/RichText/Parser.rb +4 -6
  43. data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
  44. data/lib/taskjuggler/RichText/RTFQuery.rb +2 -3
  45. data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
  46. data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -2
  47. data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
  48. data/lib/taskjuggler/RichText/Scanner.rb +6 -6
  49. data/lib/taskjuggler/RichText/Snip.rb +1 -2
  50. data/lib/taskjuggler/RuntimeConfig.rb +9 -6
  51. data/lib/taskjuggler/ScenarioData.rb +4 -3
  52. data/lib/taskjuggler/Scoreboard.rb +6 -0
  53. data/lib/taskjuggler/SheetHandlerBase.rb +25 -8
  54. data/lib/taskjuggler/SimpleQueryExpander.rb +14 -5
  55. data/lib/taskjuggler/SyntaxReference.rb +1 -2
  56. data/lib/taskjuggler/TableColumnSorter.rb +84 -0
  57. data/lib/taskjuggler/Task.rb +3 -5
  58. data/lib/taskjuggler/TaskJuggler.rb +36 -29
  59. data/lib/taskjuggler/TaskScenario.rb +154 -66
  60. data/lib/taskjuggler/TextParser.rb +24 -17
  61. data/lib/taskjuggler/TextParser/Scanner.rb +16 -11
  62. data/lib/taskjuggler/TextParser/SourceFileInfo.rb +20 -15
  63. data/lib/taskjuggler/TimeSheets.rb +6 -12
  64. data/lib/taskjuggler/Tj3AppBase.rb +35 -16
  65. data/lib/taskjuggler/Tj3Config.rb +1 -1
  66. data/lib/taskjuggler/TjpSyntaxRules.rb +239 -49
  67. data/lib/taskjuggler/XMLElement.rb +9 -2
  68. data/lib/taskjuggler/apps/Tj3.rb +43 -37
  69. data/lib/taskjuggler/apps/Tj3Client.rb +62 -112
  70. data/lib/taskjuggler/apps/Tj3Daemon.rb +66 -29
  71. data/lib/taskjuggler/apps/Tj3Man.rb +5 -5
  72. data/lib/taskjuggler/apps/Tj3SsReceiver.rb +10 -13
  73. data/lib/taskjuggler/apps/Tj3SsSender.rb +13 -16
  74. data/lib/taskjuggler/apps/Tj3TsReceiver.rb +10 -13
  75. data/lib/taskjuggler/apps/Tj3TsSender.rb +12 -15
  76. data/lib/taskjuggler/apps/Tj3TsSummary.rb +12 -15
  77. data/lib/taskjuggler/apps/Tj3WebD.rb +99 -0
  78. data/lib/taskjuggler/daemon/Daemon.rb +50 -10
  79. data/lib/taskjuggler/daemon/DaemonConnector.rb +127 -0
  80. data/lib/taskjuggler/daemon/ProcessIntercom.rb +36 -21
  81. data/lib/taskjuggler/daemon/ProjectBroker.rb +122 -112
  82. data/lib/taskjuggler/daemon/ProjectServer.rb +78 -46
  83. data/lib/taskjuggler/daemon/ReportServer.rb +52 -28
  84. data/lib/taskjuggler/daemon/ReportServlet.rb +92 -21
  85. data/lib/taskjuggler/daemon/WebServer.rb +75 -22
  86. data/lib/taskjuggler/daemon/WelcomePage.rb +1 -0
  87. data/lib/taskjuggler/reports/AccountListRE.rb +3 -3
  88. data/lib/taskjuggler/reports/CSVFile.rb +9 -2
  89. data/lib/taskjuggler/reports/ChartPlotter.rb +453 -0
  90. data/lib/taskjuggler/reports/Navigator.rb +1 -0
  91. data/lib/taskjuggler/reports/NikuReport.rb +4 -4
  92. data/lib/taskjuggler/reports/Report.rb +6 -18
  93. data/lib/taskjuggler/reports/ReportBase.rb +9 -9
  94. data/lib/taskjuggler/reports/ReportContext.rb +2 -2
  95. data/lib/taskjuggler/reports/StatusSheetReport.rb +6 -6
  96. data/lib/taskjuggler/reports/TableReport.rb +24 -15
  97. data/lib/taskjuggler/reports/TimeSheetReport.rb +5 -5
  98. data/lib/taskjuggler/reports/TraceReport.rb +251 -0
  99. data/lib/tj3webd.rb +17 -0
  100. data/manual/Day_To_Day_Juggling +10 -3
  101. data/manual/Installation +38 -19
  102. data/manual/Software +25 -19
  103. data/manual/Tutorial +119 -110
  104. data/manual/html/Day_To_Day_Juggling.html +7 -5
  105. data/manual/html/Getting_Started.html +4 -4
  106. data/manual/html/How_To_Contribute.html +4 -4
  107. data/manual/html/Installation.html +19 -11
  108. data/manual/html/Intro.html +4 -4
  109. data/manual/html/Reporting_Bugs.html +4 -4
  110. data/manual/html/Rich_Text_Attributes.html +4 -4
  111. data/manual/html/Software.html +15 -11
  112. data/manual/html/TaskJuggler_2x_Migration.html +4 -4
  113. data/manual/html/TaskJuggler_Internals.html +4 -4
  114. data/manual/html/The_TaskJuggler_Syntax.html +4 -4
  115. data/manual/html/Tutorial.html +41 -32
  116. data/manual/html/account.html +4 -4
  117. data/manual/html/account.task.html +4 -4
  118. data/manual/html/accountprefix.html +4 -4
  119. data/manual/html/accountreport.html +27 -9
  120. data/manual/html/accountroot.html +5 -5
  121. data/manual/html/active.html +4 -4
  122. data/manual/html/adopt.task.html +4 -4
  123. data/manual/html/aggregate.html +4 -4
  124. data/manual/html/alert.html +4 -4
  125. data/manual/html/alertlevels.html +4 -4
  126. data/manual/html/allocate.html +5 -5
  127. data/manual/html/alphabet.html +4 -4
  128. data/manual/html/alternative.html +4 -4
  129. data/manual/html/author.html +4 -4
  130. data/manual/html/balance.html +5 -5
  131. data/manual/html/booking.resource.html +4 -4
  132. data/manual/html/booking.task.html +4 -4
  133. data/manual/html/caption.html +5 -5
  134. data/manual/html/cellcolor.column.html +43 -8
  135. data/manual/html/celltext.column.html +4 -4
  136. data/manual/html/center.html +5 -5
  137. data/manual/html/charge.html +4 -4
  138. data/manual/html/chargeset.html +4 -4
  139. data/manual/html/columnid.html +27 -15
  140. data/manual/html/columns.html +5 -5
  141. data/manual/html/complete.html +4 -4
  142. data/manual/html/copyright.html +4 -4
  143. data/manual/html/credits.html +4 -4
  144. data/manual/html/css/tjreport.css +14 -5
  145. data/manual/html/currency.html +4 -4
  146. data/manual/html/currencyformat.html +5 -5
  147. data/manual/html/dailymax.html +5 -5
  148. data/manual/html/dailymin.html +5 -5
  149. data/manual/html/dailyworkinghours.html +4 -4
  150. data/manual/html/date.extend.html +4 -4
  151. data/manual/html/date.html +5 -5
  152. data/manual/html/definitions.html +4 -4
  153. data/manual/html/depends.html +4 -4
  154. data/manual/html/details.html +4 -4
  155. data/manual/html/disabled.html +4 -4
  156. data/manual/html/duration.html +4 -4
  157. data/manual/html/efficiency.html +4 -4
  158. data/manual/html/effort.html +4 -4
  159. data/manual/html/email.html +4 -4
  160. data/manual/html/enabled.html +4 -4
  161. data/manual/html/end.column.html +4 -4
  162. data/manual/html/end.html +4 -4
  163. data/manual/html/end.limit.html +4 -4
  164. data/manual/html/end.report.html +5 -5
  165. data/manual/html/end.timesheet.html +4 -4
  166. data/manual/html/endcredit.html +4 -4
  167. data/manual/html/epilog.html +5 -5
  168. data/manual/html/export.html +4 -4
  169. data/manual/html/extend.html +4 -4
  170. data/manual/html/fail.html +43 -8
  171. data/manual/html/fdl.html +4 -4
  172. data/manual/html/flags.account.html +4 -4
  173. data/manual/html/flags.html +4 -4
  174. data/manual/html/flags.journalentry.html +4 -4
  175. data/manual/html/flags.report.html +5 -5
  176. data/manual/html/flags.resource.html +4 -4
  177. data/manual/html/flags.statussheet.html +4 -4
  178. data/manual/html/flags.task.html +4 -4
  179. data/manual/html/flags.timesheet.html +4 -4
  180. data/manual/html/fontcolor.column.html +43 -8
  181. data/manual/html/footer.html +5 -5
  182. data/manual/html/formats.html +5 -5
  183. data/manual/html/functions.html +4 -4
  184. data/manual/html/gapduration.html +4 -4
  185. data/manual/html/gaplength.html +4 -4
  186. data/manual/html/halign.center.html +4 -4
  187. data/manual/html/halign.column.html +43 -8
  188. data/manual/html/halign.left.html +4 -4
  189. data/manual/html/halign.right.html +4 -4
  190. data/manual/html/hasalert.html +4 -4
  191. data/manual/html/header.html +5 -5
  192. data/manual/html/headline.html +7 -7
  193. data/manual/html/height.html +72 -0
  194. data/manual/html/hideaccount.html +46 -11
  195. data/manual/html/hidejournalentry.html +5 -5
  196. data/manual/html/hidereport.html +43 -8
  197. data/manual/html/hideresource.html +44 -9
  198. data/manual/html/hidetask.html +44 -9
  199. data/manual/html/icalreport.html +4 -4
  200. data/manual/html/include.macro.html +4 -4
  201. data/manual/html/include.project.html +4 -4
  202. data/manual/html/include.properties.html +4 -4
  203. data/manual/html/index.html +2 -1
  204. data/manual/html/inherit.extend.html +4 -4
  205. data/manual/html/interval1.html +4 -4
  206. data/manual/html/interval2.html +4 -4
  207. data/manual/html/interval3.html +4 -4
  208. data/manual/html/interval4.html +4 -4
  209. data/manual/html/isactive.html +4 -4
  210. data/manual/html/ischildof.html +4 -4
  211. data/manual/html/isdependencyof.html +4 -4
  212. data/manual/html/isdutyof.html +4 -4
  213. data/manual/html/isfeatureof.html +4 -4
  214. data/manual/html/isleaf.html +4 -4
  215. data/manual/html/ismilestone.html +4 -4
  216. data/manual/html/isongoing.html +4 -4
  217. data/manual/html/isresource.html +4 -4
  218. data/manual/html/isresponsibilityof.html +4 -4
  219. data/manual/html/istask.html +4 -4
  220. data/manual/html/journalattributes.html +11 -7
  221. data/manual/html/journalentry.html +4 -4
  222. data/manual/html/journalmode.html +5 -5
  223. data/manual/html/leaveallowance.html +5 -5
  224. data/manual/html/leaves.html +5 -6
  225. data/manual/html/left.html +5 -5
  226. data/manual/html/length.html +4 -4
  227. data/manual/html/limits.allocate.html +4 -4
  228. data/manual/html/limits.html +4 -4
  229. data/manual/html/limits.resource.html +4 -4
  230. data/manual/html/limits.task.html +4 -4
  231. data/manual/html/listitem.column.html +4 -4
  232. data/manual/html/listtype.column.html +4 -4
  233. data/manual/html/loadunit.html +5 -5
  234. data/manual/html/logicalexpression.html +8 -44
  235. data/manual/html/logicalflagexpression.html +4 -4
  236. data/manual/html/macro.html +4 -4
  237. data/manual/html/managers.html +4 -4
  238. data/manual/html/mandatory.html +4 -4
  239. data/manual/html/maxend.html +4 -4
  240. data/manual/html/maximum.html +5 -5
  241. data/manual/html/maxstart.html +4 -4
  242. data/manual/html/milestone.html +4 -4
  243. data/manual/html/minend.html +4 -4
  244. data/manual/html/minimum.html +5 -5
  245. data/manual/html/minstart.html +4 -4
  246. data/manual/html/monthlymax.html +5 -5
  247. data/manual/html/monthlymin.html +5 -5
  248. data/manual/html/navbar.html +10 -4
  249. data/manual/html/navigator.html +4 -4
  250. data/manual/html/newtask.html +4 -4
  251. data/manual/html/nikureport.html +4 -4
  252. data/manual/html/note.task.html +4 -4
  253. data/manual/html/now.html +4 -4
  254. data/manual/html/numberformat.html +5 -5
  255. data/manual/html/onend.html +4 -4
  256. data/manual/html/onstart.html +4 -4
  257. data/manual/html/opennodes.html +5 -5
  258. data/manual/html/overtime.booking.html +4 -4
  259. data/manual/html/period.column.html +4 -4
  260. data/manual/html/period.limit.html +4 -4
  261. data/manual/html/period.report.html +5 -5
  262. data/manual/html/period.task.html +4 -4
  263. data/manual/html/persistent.html +4 -4
  264. data/manual/html/precedes.html +4 -4
  265. data/manual/html/priority.html +4 -4
  266. data/manual/html/priority.timesheet.html +4 -4
  267. data/manual/html/project.html +4 -4
  268. data/manual/html/projectid.html +4 -4
  269. data/manual/html/projectid.task.html +4 -4
  270. data/manual/html/projectids.html +4 -4
  271. data/manual/html/projection.html +5 -7
  272. data/manual/html/prolog.html +5 -5
  273. data/manual/html/properties.html +11 -5
  274. data/manual/html/purge.html +5 -5
  275. data/manual/html/rate.html +4 -4
  276. data/manual/html/rate.resource.html +4 -4
  277. data/manual/html/reference.extend.html +4 -4
  278. data/manual/html/remaining.html +4 -4
  279. data/manual/html/replace.html +4 -4
  280. data/manual/html/reportprefix.html +4 -4
  281. data/manual/html/resource.html +4 -10
  282. data/manual/html/resourceattributes.html +4 -4
  283. data/manual/html/resourceprefix.html +4 -4
  284. data/manual/html/resourcereport.html +28 -10
  285. data/manual/html/resourceroot.html +5 -5
  286. data/manual/html/resources.limit.html +4 -4
  287. data/manual/html/responsible.html +4 -4
  288. data/manual/html/richtext.extend.html +4 -4
  289. data/manual/html/right.html +5 -5
  290. data/manual/html/rollupaccount.html +44 -9
  291. data/manual/html/rollupresource.html +44 -9
  292. data/manual/html/rolluptask.html +44 -9
  293. data/manual/html/scale.column.html +4 -4
  294. data/manual/html/scenario.html +4 -22
  295. data/manual/html/scenario.ical.html +4 -4
  296. data/manual/html/scenarios.export.html +4 -4
  297. data/manual/html/scenarios.html +5 -5
  298. data/manual/html/scenariospecific.extend.html +4 -4
  299. data/manual/html/scheduled.html +4 -4
  300. data/manual/html/scheduling.html +4 -4
  301. data/manual/html/select.html +4 -4
  302. data/manual/html/selfcontained.html +5 -5
  303. data/manual/html/shift.allocate.html +4 -4
  304. data/manual/html/shift.html +4 -4
  305. data/manual/html/shift.resource.html +5 -5
  306. data/manual/html/shift.task.html +4 -4
  307. data/manual/html/shift.timesheet.html +4 -4
  308. data/manual/html/shifts.allocate.html +4 -4
  309. data/manual/html/shifts.resource.html +4 -4
  310. data/manual/html/shifts.task.html +4 -4
  311. data/manual/html/shorttimeformat.html +4 -4
  312. data/manual/html/sloppy.booking.html +4 -4
  313. data/manual/html/sloppy.projection.html +5 -5
  314. data/manual/html/sortaccounts.html +5 -5
  315. data/manual/html/sortjournalentries.html +5 -5
  316. data/manual/html/sortresources.html +5 -5
  317. data/manual/html/sorttasks.html +5 -5
  318. data/manual/html/start.column.html +4 -4
  319. data/manual/html/start.html +4 -4
  320. data/manual/html/start.limit.html +4 -4
  321. data/manual/html/start.report.html +5 -5
  322. data/manual/html/startcredit.html +4 -4
  323. data/manual/html/status.statussheet.html +4 -4
  324. data/manual/html/status.timesheet.html +4 -4
  325. data/manual/html/statussheet.html +4 -4
  326. data/manual/html/statussheetreport.html +4 -4
  327. data/manual/html/strict.projection.html +5 -5
  328. data/manual/html/summary.html +4 -4
  329. data/manual/html/supplement.html +4 -4
  330. data/manual/html/supplement.resource.html +4 -10
  331. data/manual/html/supplement.task.html +4 -28
  332. data/manual/html/tagfile.html +4 -4
  333. data/manual/html/task.html +4 -28
  334. data/manual/html/task.statussheet.html +4 -4
  335. data/manual/html/task.timesheet.html +4 -4
  336. data/manual/html/taskattributes.html +4 -4
  337. data/manual/html/taskprefix.html +4 -4
  338. data/manual/html/taskreport.html +28 -10
  339. data/manual/html/taskroot.html +5 -5
  340. data/manual/html/text.extend.html +4 -4
  341. data/manual/html/textreport.html +27 -9
  342. data/manual/html/timeformat.html +5 -5
  343. data/manual/html/timeoff.nikureport.html +4 -4
  344. data/manual/html/timesheet.html +4 -4
  345. data/manual/html/timesheetreport.html +23 -5
  346. data/manual/html/timezone.export.html +4 -4
  347. data/manual/html/timezone.html +4 -4
  348. data/manual/html/timezone.report.html +5 -5
  349. data/manual/html/timezone.shift.html +4 -4
  350. data/manual/html/timingresolution.html +4 -4
  351. data/manual/html/title.column.html +4 -4
  352. data/manual/html/title.html +5 -5
  353. data/manual/html/toc.html +207 -179
  354. data/manual/html/tooltip.column.html +45 -10
  355. data/manual/html/tracereport.html +405 -0
  356. data/manual/html/trackingscenario.html +6 -6
  357. data/manual/html/treelevel.html +4 -4
  358. data/manual/html/vacation.html +4 -4
  359. data/manual/html/vacation.resource.html +4 -4
  360. data/manual/html/vacation.shift.html +4 -4
  361. data/manual/html/warn.html +43 -8
  362. data/manual/html/weeklymax.html +5 -5
  363. data/manual/html/weeklymin.html +5 -5
  364. data/manual/html/weekstartsmonday.html +4 -4
  365. data/manual/html/weekstartssunday.html +6 -6
  366. data/manual/html/width.column.html +6 -6
  367. data/manual/html/width.html +72 -0
  368. data/manual/html/work.html +4 -4
  369. data/manual/html/workinghours.project.html +4 -4
  370. data/manual/html/workinghours.resource.html +4 -4
  371. data/manual/html/workinghours.shift.html +4 -4
  372. data/manual/html/yearlyworkingdays.html +4 -4
  373. data/spec/Color_spec.rb +60 -0
  374. data/spec/ProjectBroker_spec.rb +3 -2
  375. data/spec/StatusSheets_spec.rb +5 -4
  376. data/spec/TableColumnSorter_spec.rb +78 -0
  377. data/spec/TimeSheets_spec.rb +6 -2
  378. data/spec/Tj3Daemon_spec.rb +2 -2
  379. data/spec/TraceReport_spec.rb +117 -0
  380. data/taskjuggler.gemspec +1 -1
  381. data/test/MessageChecker.rb +3 -1
  382. data/test/ReferenceGenerator.rb +1 -1
  383. data/test/TestSuite/CSV-Reports/Leave.tjp +1 -1
  384. data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +3 -0
  385. data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +9 -0
  386. data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +19 -16
  387. data/test/TestSuite/CSV-Reports/refs/weekly.csv +1 -0
  388. data/test/TestSuite/Export-Reports/refs/LogicalExpression.tjp +14 -2
  389. data/test/TestSuite/Export-Reports/refs/tutorial.tjp +98 -86
  390. data/test/TestSuite/Scheduler/Correct/Leaves.tjp +25 -0
  391. data/test/TestSuite/Syntax/Correct/Leave.tjp +1 -1
  392. data/test/TestSuite/Syntax/Correct/LogicalExpression.tjp +9 -1
  393. data/test/TestSuite/Syntax/Correct/TraceReport.tjp +10 -0
  394. data/test/TestSuite/Syntax/Correct/tutorial.tjp +10 -4
  395. data/test/test_CSV-Reports.rb +3 -3
  396. data/test/test_Export-Reports.rb +91 -86
  397. data/test/test_Journal.rb +15 -12
  398. data/test/test_Limits.rb +3 -3
  399. data/test/test_Project.rb +1 -2
  400. data/test/test_ProjectFileScanner.rb +1 -1
  401. data/test/test_PropertySet.rb +1 -1
  402. data/test/test_Query.rb +5 -6
  403. data/test/test_ReportGenerator.rb +15 -7
  404. data/test/test_RichText.rb +4 -3
  405. data/test/test_Scheduler.rb +19 -7
  406. data/test/test_ShiftAssignments.rb +2 -2
  407. data/test/test_SimpleQueryExpander.rb +29 -2
  408. data/test/test_Syntax.rb +14 -5
  409. metadata +49 -10
  410. data/lib/taskjuggler/LogFile.rb +0 -73
@@ -24,7 +24,7 @@ class TaskJuggler
24
24
 
25
25
  def initialize(project, sourceFileInfo = nil)
26
26
  @project = project
27
- super(project.messageHandler, 'navigator', sourceFileInfo)
27
+ super('navigator', sourceFileInfo)
28
28
  @blockFunction = true
29
29
  end
30
30
 
@@ -23,7 +23,7 @@ class TaskJuggler
23
23
 
24
24
  def initialize(project, sourceFileInfo = nil)
25
25
  @project = project
26
- super(project.messageHandler, 'query', sourceFileInfo)
26
+ super('query', sourceFileInfo)
27
27
  @blockMode = false
28
28
  end
29
29
 
@@ -83,8 +83,7 @@ class TaskJuggler
83
83
  return nil
84
84
  end
85
85
  expandedArgs[arg] =
86
- SimpleQueryExpander.new(value, @query, @messageHandler,
87
- @sourceFileInfo).expand
86
+ SimpleQueryExpander.new(value, @query, @sourceFileInfo).expand
88
87
  end
89
88
 
90
89
  if (expandedArgs['property'] || expandedArgs['scopeproperty']) &&
@@ -22,7 +22,7 @@ class TaskJuggler
22
22
 
23
23
  def initialize(project, sourceFileInfo = nil)
24
24
  @project = project
25
- super(project.messageHandler, 'report', sourceFileInfo)
25
+ super('report', sourceFileInfo)
26
26
  @blockFunction = true
27
27
  end
28
28
 
@@ -24,7 +24,7 @@ class TaskJuggler
24
24
 
25
25
  def initialize(project, sourceFileInfo = nil)
26
26
  @project = project
27
- super(project.messageHandler, 'reportlink', sourceFileInfo)
27
+ super('reportlink', sourceFileInfo)
28
28
  @blockFunction = false
29
29
  @query = nil
30
30
  end
@@ -54,7 +54,6 @@ class TaskJuggler
54
54
 
55
55
  if args['attributes']
56
56
  qEx = SimpleQueryExpander.new(args['attributes'], @query,
57
- @project.messageHandler,
58
57
  @sourceFileInfo)
59
58
  url += ";attributes=" + URLParameter.encode(qEx.expand)
60
59
  end
@@ -17,7 +17,7 @@ class TaskJuggler
17
17
 
18
18
  class RTFWithQuerySupport < RichTextFunctionHandler
19
19
 
20
- def initialize(messageHandler, type, sourceFileInfo = nil)
20
+ def initialize(type, sourceFileInfo = nil)
21
21
  super
22
22
  @query = nil
23
23
  end
@@ -30,7 +30,7 @@ class TaskJuggler
30
30
  # :func : inside of a block <[ .. ]> or inline <- .. -> function
31
31
  class RichTextScanner < TextParser::Scanner
32
32
 
33
- def initialize(masterFile, messageHandler, log)
33
+ def initialize(masterFile, log)
34
34
  tokenPatterns = [
35
35
  # :bol mode rules
36
36
  [ :LINEBREAK, /\s*\n/, :bol, method('linebreak') ],
@@ -49,8 +49,8 @@ class TaskJuggler
49
49
  [ :BLOCKFUNCSTART, /<\[/, [ :bop, :bol ], method('functionStart') ],
50
50
  [ ':TITLE*', /={2,5}/, [ :bop, :bol ], method('titleStart') ],
51
51
  [ 'TITLE*END', /={2,5}/, :inline, method('titleEnd') ],
52
- [ 'BULLET*', /\*{1,4} /, [ :bop, :bol ], method('bullet') ],
53
- [ 'NUMBER*', /\#{1,4} /, [ :bop, :bol ], method('number') ],
52
+ [ 'BULLET*', /\*{1,4}[ \t]+/, [ :bop, :bol ], method('bullet') ],
53
+ [ 'NUMBER*', /\#{1,4}[ \t]+/, [ :bop, :bol ], method('number') ],
54
54
  [ :HLINE, /----/, [ :bop, :bol ], method('inlineMode') ],
55
55
 
56
56
  # :bop, :bol and :inline mode rules
@@ -94,7 +94,7 @@ class TaskJuggler
94
94
  [ nil, /[ \t\n]+/, :func ],
95
95
  [ :LITERAL, /./, :func ]
96
96
  ]
97
- super(masterFile, messageHandler, log, tokenPatterns, :bop)
97
+ super(masterFile, log, tokenPatterns, :bop)
98
98
  end
99
99
 
100
100
  private
@@ -130,12 +130,12 @@ class TaskJuggler
130
130
 
131
131
  def bullet(type, match)
132
132
  self.mode = :inline
133
- [ "BULLET#{match.length - 1}".intern, match ]
133
+ [ "BULLET#{match.count('*')}".intern, match ]
134
134
  end
135
135
 
136
136
  def number(type, match)
137
137
  self.mode = :inline
138
- [ "NUMBER#{match.length - 1}".intern, match ]
138
+ [ "NUMBER#{match.count('#')}".intern, match ]
139
139
  end
140
140
 
141
141
  def fontColorStart(type, match)
@@ -40,8 +40,7 @@ class TaskJuggler
40
40
  File.open(fileName) do |file|
41
41
  file.each_line { |line| text += line }
42
42
  end
43
- rText = RichText.new(text, @document.functionHandlers,
44
- MessageHandler.new(true))
43
+ rText = RichText.new(text, @document.functionHandlers)
45
44
  unless (@richText = rText.generateIntermediateFormat(sectionCounter))
46
45
  exit
47
46
  end
@@ -29,8 +29,7 @@ class RuntimeConfig
29
29
  if configFile
30
30
  # Read user specified config file.
31
31
  unless loadConfigFile(configFile)
32
- $stderr.puts "Config file #{configFile} not found!"
33
- exit 1
32
+ error("Config file #{configFile} not found!")
34
33
  end
35
34
  else
36
35
  # Search config files in certain directories.
@@ -71,14 +70,13 @@ class RuntimeConfig
71
70
 
72
71
  def loadConfigFile(fileName)
73
72
  if File.exist?(fileName)
73
+ debug("Loading #{fileName}")
74
74
  begin
75
- debug("Loading #{fileName}")
76
75
  @config = YAML::load(File.read(fileName))
77
- debug(@config.to_s)
78
76
  rescue
79
- $stderr.puts "Error in config file #{fileName}: #{$!}"
80
- exit 1
77
+ error("Error in config file #{fileName}: #{$!}")
81
78
  end
79
+ debug(@config.to_s)
82
80
  return true
83
81
  end
84
82
  false
@@ -90,5 +88,10 @@ class RuntimeConfig
90
88
  puts message
91
89
  end
92
90
 
91
+ def error(message)
92
+ $stderr.puts message
93
+ exit 1
94
+ end
95
+
93
96
  end
94
97
 
@@ -25,6 +25,7 @@ class TaskJuggler
25
25
  @project = property.project
26
26
  @scenarioIdx = idx
27
27
  @attributes = attributes
28
+ @messageHandler = MessageHandlerInstance.instance
28
29
 
29
30
  # Register the scenario with the Task.
30
31
  @property.data[idx] = self
@@ -42,21 +43,21 @@ class TaskJuggler
42
43
  end
43
44
 
44
45
  def error(id, text, sourceFileInfo = nil, property = nil)
45
- @project.messageHandler.error(
46
+ @messageHandler.error(
46
47
  id, text, sourceFileInfo || @property.sourceFileInfo, nil,
47
48
  property || @property,
48
49
  @project.scenario(@scenarioIdx))
49
50
  end
50
51
 
51
52
  def warning(id, text, sourceFileInfo = nil, property = nil)
52
- @project.messageHandler.warning(
53
+ @messageHandler.warning(
53
54
  id, text, sourceFileInfo || @property.sourceFileInfo, nil,
54
55
  property || @property,
55
56
  @project.scenario(@scenarioIdx))
56
57
  end
57
58
 
58
59
  def info(id, text, sourceFileInfo = nil, property = nil)
59
- @project.messageHandler.info(
60
+ @messageHandler.info(
60
61
  id, text, sourceFileInfo || @property.sourceFileInfo, nil,
61
62
  property || @property,
62
63
  @project.scenario(@scenarioIdx))
@@ -170,6 +170,12 @@ class TaskJuggler
170
170
  intervals
171
171
  end
172
172
 
173
+ def inspect
174
+ 0.upto(@sb.length - 1) do |i|
175
+ puts "#{idxToDate(i)}: #{@sb[i]}"
176
+ end
177
+ end
178
+
173
179
  end
174
180
 
175
181
  end
@@ -25,7 +25,8 @@ class TaskJuggler
25
25
  def initialize(appName)
26
26
  @appName = appName
27
27
  # User specific settings
28
- @smtpServer= nil
28
+ @emailDeliveryMethod = 'smtp'
29
+ @smtpServer = nil
29
30
  @senderEmail = nil
30
31
  @workingDir = nil
31
32
  @scmCommand = nil
@@ -87,7 +88,14 @@ class TaskJuggler
87
88
 
88
89
  def setWorkingDir
89
90
  # Make sure the user has provided a properly setup config file.
90
- error('\'smtpServer\' not configured') unless @smtpServer
91
+ case @emailDeliveryMethod
92
+ when 'smtp'
93
+ error('\'smtpServer\' not configured') unless @smtpServer
94
+ when 'sendmail'
95
+ # nothing to check
96
+ else
97
+ error("Unknown emailDeliveryMethod #{@emailDeliveryMethod}")
98
+ end
91
99
  error('\'senderEmail\' not configured') unless @senderEmail
92
100
 
93
101
  # Change into the specified working directory
@@ -156,11 +164,20 @@ class TaskJuggler
156
164
 
157
165
  def sendEmail(to, subject, message, attachment = nil, from = nil,
158
166
  inReplyTo = nil)
159
- Mail.defaults do
160
- delivery_method :smtp, {
161
- :address => @smtpServer,
162
- :port => 25
163
- }
167
+ case @emailDeliveryMethod
168
+ when 'smtp'
169
+ Mail.defaults do
170
+ delivery_method :smtp, {
171
+ :address => @smtpServer,
172
+ :port => 25
173
+ }
174
+ end
175
+ when 'sendmail'
176
+ Mail.defaults do
177
+ delivery_method :sendmail
178
+ end
179
+ else
180
+ raise "Unknown email delivery method: #{@emailDeliveryMethod}"
164
181
  end
165
182
 
166
183
  begin
@@ -202,7 +219,7 @@ class TaskJuggler
202
219
  puts "-- Email Start #{'-' * 60}\n#{mail.to_s}-- Email End #{'-' * 62}"
203
220
  log('INFO', "Show email '#{subject}' to #{to}")
204
221
  else
205
- # Actually send out the email via SMTP.
222
+ # Actually send out the email.
206
223
  begin
207
224
  mail.deliver
208
225
  rescue
@@ -12,6 +12,7 @@
12
12
  #
13
13
 
14
14
  require 'strscan'
15
+ require 'taskjuggler/MessageHandler'
15
16
 
16
17
  class TaskJuggler
17
18
 
@@ -22,20 +23,29 @@ class TaskJuggler
22
23
  # context of the query.
23
24
  class SimpleQueryExpander
24
25
 
26
+ include MessageHandler
27
+
25
28
  # _inputStr_ is the String with the embedded queries. _query_ is the Query
26
29
  # with that provides the evaluation context. _messageHandle_ is a
27
30
  # MessageHandler that will be used for error reporting. _sourceFileInfo_
28
31
  # is a SourceFileInfo reference used for error reporting.
29
- def initialize(inputStr, query, messageHandler, sourceFileInfo)
32
+ def initialize(inputStr, query, sourceFileInfo)
30
33
  @inputStr = inputStr
31
34
  @query = query.dup
32
- @messageHandler = messageHandler
33
35
  @sourceFileInfo = sourceFileInfo
34
36
  end
35
37
 
36
38
  def expand
37
39
  # Create a copy of the input string since we will modify it.
38
40
  str = @inputStr.dup
41
+
42
+ # The scenario name is not an attribute that can be queried. We need to
43
+ # handle this separately
44
+ if @query.scenarioIdx
45
+ str.gsub!(/<-scenario->/,
46
+ @query.project.scenario(@query.scenarioIdx).id)
47
+ end
48
+
39
49
  # Replace all occurences of <-name->.
40
50
  str.gsub!(/<-[a-zA-Z][_a-zA-Z]*->/) do |match|
41
51
  attribute = match[2..-3]
@@ -45,9 +55,8 @@ class TaskJuggler
45
55
  @query.to_s
46
56
  else
47
57
  # The query failed. We report an error.
48
- @messageHandler.error('sqe_expand_failed',
49
- "Unknown attribute #{attribute}",
50
- @sourceFileInfo)
58
+ error('sqe_expand_failed', "Unknown attribute #{attribute}",
59
+ @sourceFileInfo)
51
60
  end
52
61
  end
53
62
  str
@@ -35,8 +35,7 @@ class TaskJuggler
35
35
  # SyntaxReference.
36
36
  def initialize(manual = nil, ignoreOld = false)
37
37
  @manual = manual
38
- @messageHandler = MessageHandler.new(true)
39
- @parser = ProjectFileParser.new(@messageHandler)
38
+ @parser = ProjectFileParser.new
40
39
  @parser.updateParserTables
41
40
 
42
41
  # This hash stores all documented keywords using the keyword as
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = TableColumnSorter.rb -- The TaskJuggler III Project Management Software
5
+ #
6
+ # Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
7
+ # by Chris Schlaeger <chris@linux.com>
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify
10
+ # it under the terms of version 2 of the GNU General Public License as
11
+ # published by the Free Software Foundation.
12
+ #
13
+
14
+ class TaskJuggler
15
+
16
+ # This class can rearrange the columns of a table according to a new order
17
+ # determined by an Array of table headers. The table is an Array of table
18
+ # lines. Each line is another Array. The first line of the table is an Array
19
+ # of the headers of the columns.
20
+ class TableColumnSorter
21
+
22
+ attr_reader :discontinuedColumns
23
+
24
+ # Register a new table for rearranging.
25
+ def initialize(table)
26
+ @oldTable = table
27
+ @discontinuedColumns = nil
28
+ end
29
+
30
+ # Rearrange the registered table. The old table won't be modified. The
31
+ # method returns a new table (Array of Arrays). _newHeaders_ is an Array
32
+ # that represents the new column headers. The columns that are not in the
33
+ # new header will be the last columns of the new table.
34
+ def sort(newHeaders)
35
+ # Maps old index to new index.
36
+ columnIdxMap = {}
37
+ newHeaderIndex = newHeaders.length
38
+ oldHeaders = @oldTable[0]
39
+ discontinuedHeaders = []
40
+ oldHeaders.length.times do |i|
41
+ if (ni = newHeaders.index(oldHeaders[i]))
42
+ # This old column is still in the new header
43
+ columnIdxMap[i] = ni
44
+ else
45
+ # This old column is no longer contained in the new header. We
46
+ # append it at the end.
47
+ columnIdxMap[i] = newHeaderIndex
48
+ discontinuedHeaders << oldHeaders[i]
49
+ newHeaderIndex += 1
50
+ end
51
+ end
52
+
53
+ # We construct a new table from scratch. All values from the old table
54
+ # are copied over. columns in the new table that were not contained in
55
+ # the old table will be filled with nil.
56
+ newTable = []
57
+ @oldTable.length.times do |lineIdx|
58
+ oldLine = @oldTable[lineIdx]
59
+ if lineIdx == 0
60
+ # Insert the new headers. The discontinued ones will be added below.
61
+ newTable[0] = newHeaders
62
+ else
63
+ # Add a line of nils to the new table.
64
+ newTable[lineIdx] = Array.new(newHeaderIndex, nil)
65
+ end
66
+
67
+ # Copy the old column to the new position.
68
+ columnIdxMap.each do |oldColIdx, newColIdx|
69
+ newTable[lineIdx][newColIdx] = oldLine[oldColIdx]
70
+ end
71
+ end
72
+
73
+ # Now we need to add the new column headers that were not in the old
74
+ # headers.
75
+ #newTable[0] += discontinuedHeaders
76
+
77
+ @discontinuedColumns = discontinuedHeaders.length
78
+ newTable
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
@@ -96,11 +96,9 @@ class TaskJuggler
96
96
 
97
97
  # Now convert the RichText markup String into RichTextIntermediate
98
98
  # format.
99
- unless (rti = RichText.new(rText, RTFHandlers.create(@project),
100
- @project.messageHandler).
101
- generateIntermediateFormat)
102
- @project.messageHandler.warning(
103
- 'task_journal_text', 'Syntax error in journal text')
99
+ unless (rti = RichText.new(rText, RTFHandlers.create(@project)).
100
+ generateIntermediateFormat)
101
+ warning('task_journal_text', 'Syntax error in journal text')
104
102
  return nil
105
103
  end
106
104
 
@@ -23,17 +23,19 @@ require 'taskjuggler/Log'
23
23
  # files, schedule them and generate the reports.
24
24
  class TaskJuggler
25
25
 
26
- attr_reader :project, :messageHandler
27
- attr_accessor :maxCpuCores, :warnTsDeltas
26
+ include MessageHandler
27
+
28
+ attr_reader :project
29
+ attr_accessor :maxCpuCores, :warnTsDeltas, :generateTraces
28
30
 
29
31
  # Create a new TaskJuggler object. _console_ is a boolean that determines
30
32
  # whether or not messsages can be written to $stderr.
31
- def initialize(console)
33
+ def initialize
32
34
  @project = nil
33
35
  @parser = nil
34
- @messageHandler = MessageHandler.new(console)
35
36
  @maxCpuCores = 1
36
37
  @warnTsDeltas = false
38
+ @generateTraces = false
37
39
  TjTime.setTimeZone('UTC')
38
40
  end
39
41
 
@@ -41,18 +43,21 @@ class TaskJuggler
41
43
  # construct a Project object. In case of success true is returned.
42
44
  # Otherwise false.
43
45
  def parse(files, keepParser = false)
46
+ # Reset the MessageHandler to clear all errors.
47
+ MessageHandlerInstance.instance.clear
48
+
44
49
  Log.enter('parser', 'Parsing files ...')
45
50
  master = true
46
51
  @project = nil
47
52
 
48
53
  #RubyProf.start
49
- @parser = ProjectFileParser.new(@messageHandler)
54
+ @parser = ProjectFileParser.new
50
55
  files.each do |file|
51
56
  begin
52
57
  @parser.open(file, master)
53
58
  rescue TjException => msg
54
59
  if msg.message && !msg.message.empty?
55
- @messageHandler.critical('parse', msg.message)
60
+ critical('parse', msg.message)
56
61
  end
57
62
  Log.exit('parser')
58
63
  return false
@@ -91,7 +96,7 @@ class TaskJuggler
91
96
  @parser = nil unless keepParser
92
97
 
93
98
  Log.exit('parser')
94
- @messageHandler.errors == 0
99
+ MessageHandlerInstance.instance.errors == 0
95
100
  end
96
101
 
97
102
  # Parse a file and add the content to the existing project. _fileName_ is
@@ -102,7 +107,7 @@ class TaskJuggler
102
107
  @project.inputFiles << fileName
103
108
  rescue TjException => msg
104
109
  if msg.message && !msg.message.empty?
105
- @messageHandler.critical('parse_file', msg.message)
110
+ critical('parse_file', msg.message)
106
111
  end
107
112
  return nil
108
113
  end
@@ -125,11 +130,13 @@ class TaskJuggler
125
130
  res = @project.schedule
126
131
  rescue TjException => msg
127
132
  if msg.message && !msg.message.empty?
128
- @messageHandler.critical('scheduling_error', msg.message)
133
+ critical('scheduling_error', msg.message)
129
134
  end
130
135
  return false
131
136
  end
132
137
 
138
+ @project.enableTraceReports(@generateTraces)
139
+
133
140
  Log.exit('scheduler')
134
141
  res
135
142
  end
@@ -157,7 +164,7 @@ class TaskJuggler
157
164
  #end
158
165
  rescue TjException => msg
159
166
  if msg.message && !msg.message.empty?
160
- @messageHandler.critical('generate_reports', msg.message)
167
+ critical('generate_reports', msg.message)
161
168
  end
162
169
  return false
163
170
  end
@@ -179,7 +186,7 @@ class TaskJuggler
179
186
  @project.generateReport(reportId, regExpMode, formats, dynamicAttributes)
180
187
  rescue TjException => msg
181
188
  if msg.message && !msg.message.empty?
182
- @messageHandler.critical('generate_report', msg.message)
189
+ critical('generate_report', msg.message)
183
190
  end
184
191
  Log.exit('generateReport')
185
192
  return false
@@ -196,7 +203,7 @@ class TaskJuggler
196
203
  @project.listReports(reportId, regExpMode)
197
204
  rescue TjException => msg
198
205
  if msg.message && !msg.message.empty?
199
- @messageHandler.critical('list_reports', msg.message)
206
+ critical('list_reports', msg.message)
200
207
  end
201
208
  Log.exit('listReports')
202
209
  return false
@@ -210,9 +217,9 @@ class TaskJuggler
210
217
  begin
211
218
  # Check the master file is really a file and not stdin.
212
219
  unless (masterFile = @project.inputFiles.masterFile)
213
- @messageHandler.error('cannot_freeze_stdin',
214
- "The project freeze feature only when the " +
215
- "master file is a real file, not standard input.")
220
+ error('cannot_freeze_stdin',
221
+ "The project freeze feature only when the " +
222
+ "master file is a real file, not standard input.")
216
223
  end
217
224
 
218
225
  # Derive the file names for the header and bookings file from the base
@@ -223,10 +230,10 @@ class TaskJuggler
223
230
  bookingsFile = bookingsFileBase + '.tji'
224
231
 
225
232
  if !File.exists?(bookingsFile) || !File.exists?(headerFile)
226
- @messageHandler.info('incl_freeze_files',
227
- "Please make sure you include #{headerFile} at " +
228
- "the end of the project header and " +
229
- "#{bookingsFile} at the end of #{masterFile}.")
233
+ info('incl_freeze_files',
234
+ "Please make sure you include #{headerFile} at " +
235
+ "the end of the project header and " +
236
+ "#{bookingsFile} at the end of #{masterFile}.")
230
237
  end
231
238
 
232
239
  # Generate the project header include file with the new 'now' date.
@@ -235,9 +242,9 @@ class TaskJuggler
235
242
  f.puts("now #{freezeDate}")
236
243
  end
237
244
  rescue
238
- @messageHandler.error('write_header_incl',
239
- "Cannote write header include file " +
240
- "#{headerFile}")
245
+ error('write_header_incl',
246
+ "Cannote write header include file " +
247
+ "#{headerFile}")
241
248
  end
242
249
 
243
250
  # Generate an export report for the bookings.
@@ -248,8 +255,7 @@ class TaskJuggler
248
255
 
249
256
  # We export only the tracking scenario.
250
257
  unless (trackingScenarioIdx = @project['trackingScenarioIdx'])
251
- @messageHandler.error('no_tracking_scen',
252
- 'No trackingscenario defined')
258
+ error('no_tracking_scen', 'No trackingscenario defined')
253
259
  end
254
260
  report.set('scenarios', [ trackingScenarioIdx ])
255
261
 
@@ -304,8 +310,9 @@ class TaskJuggler
304
310
  'start' => ts.interval.start,
305
311
  'end' => ts.interval.end,
306
312
  'journalMode' => :journal,
307
- 'journalAttributes' => %w( alert property headline flags
308
- timesheet summary details ),
313
+ 'journalAttributes' => %w( alert property propertyid
314
+ headline flags timesheet
315
+ summary details ),
309
316
  'sortJournalEntries' => [ [ :seqno, 1 ] ],
310
317
  'timeFormat' => '%Y-%m-%d',
311
318
  'selfContained' => true }
@@ -313,7 +320,7 @@ class TaskJuggler
313
320
  puts ts.resource.query_journal(query).richText.inputText
314
321
  rescue TjException => msg
315
322
  if msg.message && !msg.message.empty?
316
- @messageHandler.critical('check_time_sheet', msg.message)
323
+ critical('check_time_sheet', msg.message)
317
324
  end
318
325
  Log.exit('checkTimeSheet')
319
326
  return false
@@ -349,7 +356,7 @@ class TaskJuggler
349
356
  puts ss[0].query_dashboard(query).richText.inputText
350
357
  rescue TjException => msg
351
358
  if msg.message && !msg.message.empty?
352
- @messageHandler.critical('check_status_sheet', msg.message)
359
+ critical('check_status_sheet', msg.message)
353
360
  end
354
361
  Log.exit('checkStatusSheet')
355
362
  return false
@@ -372,7 +379,7 @@ class TaskJuggler
372
379
 
373
380
  # Return the number of errors that had been reported during processing.
374
381
  def errors
375
- @project.messageHandler.errors
382
+ MessageHandlerInstance.instance.errors
376
383
  end
377
384
 
378
385
  end