taskjuggler 3.3.0 → 3.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (338) hide show
  1. data/CHANGELOG +35 -0
  2. data/data/tjp.vim +21 -7
  3. data/lib/taskjuggler/Allocation.rb +27 -3
  4. data/lib/taskjuggler/Attributes.rb +3 -2
  5. data/lib/taskjuggler/HTMLDocument.rb +3 -1
  6. data/lib/taskjuggler/KateSyntax.rb +213 -0
  7. data/lib/taskjuggler/Limits.rb +22 -0
  8. data/lib/taskjuggler/Log.rb +1 -1
  9. data/lib/taskjuggler/MessageHandler.rb +20 -10
  10. data/lib/taskjuggler/PTNProxy.rb +6 -1
  11. data/lib/taskjuggler/Project.rb +10 -4
  12. data/lib/taskjuggler/ProjectFileParser.rb +1 -2
  13. data/lib/taskjuggler/ProjectFileScanner.rb +41 -42
  14. data/lib/taskjuggler/ResourceScenario.rb +41 -1
  15. data/lib/taskjuggler/RichText/Element.rb +8 -0
  16. data/lib/taskjuggler/RichText/Parser.rb +1 -1
  17. data/lib/taskjuggler/RichText/RTFReportLink.rb +20 -10
  18. data/lib/taskjuggler/RichText/Scanner.rb +54 -38
  19. data/lib/taskjuggler/RichText/SyntaxRules.rb +12 -0
  20. data/lib/taskjuggler/SheetReceiver.rb +1 -1
  21. data/lib/taskjuggler/TableColumnDefinition.rb +5 -1
  22. data/lib/taskjuggler/TaskJuggler.rb +2 -2
  23. data/lib/taskjuggler/TaskScenario.rb +117 -33
  24. data/lib/taskjuggler/TextParser.rb +2 -4
  25. data/lib/taskjuggler/TextParser/MacroTable.rb +7 -0
  26. data/lib/taskjuggler/TextParser/Scanner.rb +10 -9
  27. data/lib/taskjuggler/Tj3Config.rb +1 -1
  28. data/lib/taskjuggler/TjTime.rb +5 -28
  29. data/lib/taskjuggler/TjpSyntaxRules.rb +85 -13
  30. data/lib/taskjuggler/UTF8String.rb +5 -0
  31. data/lib/taskjuggler/XMLElement.rb +2 -1
  32. data/lib/taskjuggler/apps/Tj3.rb +29 -5
  33. data/lib/taskjuggler/daemon/ProcessIntercom.rb +1 -1
  34. data/lib/taskjuggler/daemon/ProjectServer.rb +5 -2
  35. data/lib/taskjuggler/daemon/ReportServer.rb +7 -4
  36. data/lib/taskjuggler/reports/AccountListRE.rb +2 -0
  37. data/lib/taskjuggler/reports/CSVFile.rb +24 -2
  38. data/lib/taskjuggler/reports/GanttChart.rb +3 -2
  39. data/lib/taskjuggler/reports/GanttHeader.rb +18 -18
  40. data/lib/taskjuggler/reports/GanttLoadStack.rb +1 -1
  41. data/lib/taskjuggler/reports/MspXmlRE.rb +5 -1
  42. data/lib/taskjuggler/reports/Report.rb +29 -18
  43. data/lib/taskjuggler/reports/ReportTable.rb +5 -1
  44. data/lib/taskjuggler/reports/ReportTableCell.rb +16 -10
  45. data/lib/taskjuggler/reports/ResourceListRE.rb +2 -0
  46. data/lib/taskjuggler/reports/TableReport.rb +23 -16
  47. data/lib/taskjuggler/reports/TaskListRE.rb +2 -0
  48. data/lib/taskjuggler/reports/TraceReport.rb +1 -1
  49. data/manual/Installation +5 -1
  50. data/manual/Intro +1 -0
  51. data/manual/Rich_Text_Attributes +5 -0
  52. data/manual/TaskJuggler_Internals +82 -34
  53. data/manual/Tutorial +1 -1
  54. data/manual/html/Day_To_Day_Juggling.html +1 -1
  55. data/manual/html/Getting_Started.html +1 -1
  56. data/manual/html/How_To_Contribute.html +1 -1
  57. data/manual/html/Installation.html +3 -2
  58. data/manual/html/Intro.html +2 -1
  59. data/manual/html/Reporting_Bugs.html +1 -1
  60. data/manual/html/Rich_Text_Attributes.html +2 -1
  61. data/manual/html/Software.html +1 -1
  62. data/manual/html/TaskJuggler_2x_Migration.html +1 -1
  63. data/manual/html/TaskJuggler_Internals.html +15 -13
  64. data/manual/html/The_TaskJuggler_Syntax.html +1 -1
  65. data/manual/html/Tutorial.html +2 -2
  66. data/manual/html/account.html +1 -1
  67. data/manual/html/account.task.html +1 -1
  68. data/manual/html/accountprefix.html +1 -1
  69. data/manual/html/accountreport.html +14 -2
  70. data/manual/html/accountroot.html +1 -1
  71. data/manual/html/active.html +1 -1
  72. data/manual/html/adopt.task.html +1 -1
  73. data/manual/html/aggregate.html +1 -1
  74. data/manual/html/alert.html +1 -1
  75. data/manual/html/alertlevels.html +1 -1
  76. data/manual/html/allocate.html +1 -1
  77. data/manual/html/alphabet.html +1 -1
  78. data/manual/html/alternative.html +1 -1
  79. data/manual/html/author.html +3 -3
  80. data/manual/html/auxdir.html +69 -0
  81. data/manual/html/balance.html +3 -3
  82. data/manual/html/booking.resource.html +1 -1
  83. data/manual/html/booking.task.html +1 -1
  84. data/manual/html/caption.html +1 -1
  85. data/manual/html/cellcolor.column.html +1 -1
  86. data/manual/html/celltext.column.html +1 -1
  87. data/manual/html/center.html +1 -1
  88. data/manual/html/charge.html +1 -1
  89. data/manual/html/chargeset.html +1 -1
  90. data/manual/html/columnid.html +21 -9
  91. data/manual/html/columns.html +2 -2
  92. data/manual/html/complete.html +1 -1
  93. data/manual/html/copyright.html +1 -1
  94. data/manual/html/credits.html +1 -1
  95. data/manual/html/currency.html +1 -1
  96. data/manual/html/currencyformat.html +1 -1
  97. data/manual/html/dailymax.html +1 -1
  98. data/manual/html/dailymin.html +1 -1
  99. data/manual/html/dailyworkinghours.html +1 -1
  100. data/manual/html/date.extend.html +1 -1
  101. data/manual/html/date.html +1 -1
  102. data/manual/html/definitions.html +1 -1
  103. data/manual/html/depends.html +1 -1
  104. data/manual/html/details.html +1 -1
  105. data/manual/html/disabled.html +1 -1
  106. data/manual/html/duration.html +1 -1
  107. data/manual/html/efficiency.html +1 -1
  108. data/manual/html/effort.html +1 -1
  109. data/manual/html/email.html +1 -1
  110. data/manual/html/enabled.html +1 -1
  111. data/manual/html/end.column.html +1 -1
  112. data/manual/html/end.html +1 -1
  113. data/manual/html/end.limit.html +1 -1
  114. data/manual/html/end.report.html +1 -1
  115. data/manual/html/end.timesheet.html +1 -1
  116. data/manual/html/endcredit.html +1 -1
  117. data/manual/html/epilog.html +1 -1
  118. data/manual/html/export.html +1 -1
  119. data/manual/html/extend.html +1 -1
  120. data/manual/html/fail.html +1 -1
  121. data/manual/html/fdl.html +1 -1
  122. data/manual/html/flags.account.html +1 -1
  123. data/manual/html/flags.html +1 -1
  124. data/manual/html/flags.journalentry.html +1 -1
  125. data/manual/html/flags.report.html +1 -1
  126. data/manual/html/flags.resource.html +1 -1
  127. data/manual/html/flags.statussheet.html +1 -1
  128. data/manual/html/flags.task.html +1 -1
  129. data/manual/html/flags.timesheet.html +1 -1
  130. data/manual/html/fontcolor.column.html +1 -1
  131. data/manual/html/footer.html +1 -1
  132. data/manual/html/formats.export.html +1 -1
  133. data/manual/html/formats.html +1 -1
  134. data/manual/html/functions.html +1 -1
  135. data/manual/html/gapduration.html +1 -1
  136. data/manual/html/gaplength.html +1 -1
  137. data/manual/html/halign.center.html +1 -1
  138. data/manual/html/halign.column.html +1 -1
  139. data/manual/html/halign.left.html +1 -1
  140. data/manual/html/halign.right.html +1 -1
  141. data/manual/html/hasalert.html +1 -1
  142. data/manual/html/header.html +1 -1
  143. data/manual/html/headline.html +1 -1
  144. data/manual/html/height.html +1 -1
  145. data/manual/html/hideaccount.html +1 -1
  146. data/manual/html/hidejournalentry.html +1 -1
  147. data/manual/html/hidereport.html +1 -1
  148. data/manual/html/hideresource.html +1 -1
  149. data/manual/html/hidetask.html +1 -1
  150. data/manual/html/icalreport.html +1 -1
  151. data/manual/html/include.macro.html +1 -1
  152. data/manual/html/include.project.html +1 -1
  153. data/manual/html/include.properties.html +1 -1
  154. data/manual/html/index.html +1 -1
  155. data/manual/html/inherit.extend.html +1 -1
  156. data/manual/html/interval1.html +1 -1
  157. data/manual/html/interval2.html +1 -1
  158. data/manual/html/interval3.html +1 -1
  159. data/manual/html/interval4.html +1 -1
  160. data/manual/html/isactive.html +1 -1
  161. data/manual/html/ischildof.html +1 -1
  162. data/manual/html/isdependencyof.html +1 -1
  163. data/manual/html/isdutyof.html +1 -1
  164. data/manual/html/isfeatureof.html +1 -1
  165. data/manual/html/isleaf.html +1 -1
  166. data/manual/html/ismilestone.html +1 -1
  167. data/manual/html/isongoing.html +1 -1
  168. data/manual/html/isresource.html +1 -1
  169. data/manual/html/isresponsibilityof.html +1 -1
  170. data/manual/html/istask.html +1 -1
  171. data/manual/html/journalattributes.html +1 -1
  172. data/manual/html/journalentry.html +1 -1
  173. data/manual/html/journalmode.html +1 -1
  174. data/manual/html/leaveallowance.html +1 -1
  175. data/manual/html/leaves.html +1 -1
  176. data/manual/html/left.html +1 -1
  177. data/manual/html/length.html +1 -1
  178. data/manual/html/limits.allocate.html +1 -1
  179. data/manual/html/limits.html +1 -1
  180. data/manual/html/limits.resource.html +1 -1
  181. data/manual/html/limits.task.html +1 -1
  182. data/manual/html/listitem.column.html +1 -1
  183. data/manual/html/listtype.column.html +1 -1
  184. data/manual/html/loadunit.html +1 -1
  185. data/manual/html/logicalexpression.html +1 -1
  186. data/manual/html/logicalflagexpression.html +1 -1
  187. data/manual/html/macro.html +1 -1
  188. data/manual/html/managers.html +1 -1
  189. data/manual/html/mandatory.html +1 -1
  190. data/manual/html/maxend.html +1 -1
  191. data/manual/html/maximum.html +1 -1
  192. data/manual/html/maxstart.html +1 -1
  193. data/manual/html/milestone.html +1 -1
  194. data/manual/html/minend.html +1 -1
  195. data/manual/html/minimum.html +1 -1
  196. data/manual/html/minstart.html +1 -1
  197. data/manual/html/monthlymax.html +1 -1
  198. data/manual/html/monthlymin.html +1 -1
  199. data/manual/html/navbar.html +9 -1
  200. data/manual/html/navigator.html +1 -1
  201. data/manual/html/newtask.html +1 -1
  202. data/manual/html/nikureport.html +1 -1
  203. data/manual/html/note.task.html +1 -1
  204. data/manual/html/now.html +1 -1
  205. data/manual/html/numberformat.html +1 -1
  206. data/manual/html/onend.html +1 -1
  207. data/manual/html/onstart.html +1 -1
  208. data/manual/html/opennodes.html +1 -1
  209. data/manual/html/overtime.booking.html +1 -1
  210. data/manual/html/period.column.html +1 -1
  211. data/manual/html/period.limit.html +1 -1
  212. data/manual/html/period.report.html +1 -1
  213. data/manual/html/period.task.html +1 -1
  214. data/manual/html/persistent.html +1 -1
  215. data/manual/html/precedes.html +1 -1
  216. data/manual/html/priority.html +1 -1
  217. data/manual/html/priority.timesheet.html +1 -1
  218. data/manual/html/project.html +1 -1
  219. data/manual/html/projectid.html +1 -1
  220. data/manual/html/projectid.task.html +1 -1
  221. data/manual/html/projectids.html +1 -1
  222. data/manual/html/projection.html +1 -1
  223. data/manual/html/prolog.html +1 -1
  224. data/manual/html/properties.html +1 -1
  225. data/manual/html/purge.html +1 -1
  226. data/manual/html/rate.html +1 -1
  227. data/manual/html/rate.resource.html +3 -3
  228. data/manual/html/rawhtmlhead.html +68 -0
  229. data/manual/html/reference.extend.html +3 -3
  230. data/manual/html/remaining.html +1 -1
  231. data/manual/html/replace.html +1 -1
  232. data/manual/html/reportprefix.html +1 -1
  233. data/manual/html/resource.html +1 -1
  234. data/manual/html/resourceattributes.html +1 -1
  235. data/manual/html/resourceprefix.html +1 -1
  236. data/manual/html/resourcereport.html +14 -2
  237. data/manual/html/resourceroot.html +1 -1
  238. data/manual/html/resources.limit.html +1 -1
  239. data/manual/html/responsible.html +1 -1
  240. data/manual/html/richtext.extend.html +1 -1
  241. data/manual/html/right.html +1 -1
  242. data/manual/html/rollupaccount.html +1 -1
  243. data/manual/html/rollupresource.html +1 -1
  244. data/manual/html/rolluptask.html +1 -1
  245. data/manual/html/scale.column.html +1 -1
  246. data/manual/html/scenario.html +1 -1
  247. data/manual/html/scenario.ical.html +1 -1
  248. data/manual/html/scenarios.export.html +1 -1
  249. data/manual/html/scenarios.html +1 -1
  250. data/manual/html/scenariospecific.extend.html +1 -1
  251. data/manual/html/scheduled.html +1 -1
  252. data/manual/html/scheduling.html +2 -1
  253. data/manual/html/select.html +1 -1
  254. data/manual/html/selfcontained.html +1 -1
  255. data/manual/html/shift.allocate.html +1 -1
  256. data/manual/html/shift.html +1 -1
  257. data/manual/html/shift.resource.html +1 -1
  258. data/manual/html/shift.task.html +1 -1
  259. data/manual/html/shift.timesheet.html +1 -1
  260. data/manual/html/shifts.allocate.html +1 -1
  261. data/manual/html/shifts.resource.html +1 -1
  262. data/manual/html/shifts.task.html +1 -1
  263. data/manual/html/shorttimeformat.html +1 -1
  264. data/manual/html/sloppy.booking.html +1 -1
  265. data/manual/html/sloppy.projection.html +1 -1
  266. data/manual/html/sortaccounts.html +1 -1
  267. data/manual/html/sortjournalentries.html +1 -1
  268. data/manual/html/sortresources.html +1 -1
  269. data/manual/html/sorttasks.html +1 -1
  270. data/manual/html/start.column.html +1 -1
  271. data/manual/html/start.html +1 -1
  272. data/manual/html/start.limit.html +1 -1
  273. data/manual/html/start.report.html +1 -1
  274. data/manual/html/startcredit.html +1 -1
  275. data/manual/html/status.statussheet.html +1 -1
  276. data/manual/html/status.timesheet.html +1 -1
  277. data/manual/html/statussheet.html +1 -1
  278. data/manual/html/statussheetreport.html +1 -1
  279. data/manual/html/strict.projection.html +1 -1
  280. data/manual/html/summary.html +1 -1
  281. data/manual/html/supplement.html +1 -1
  282. data/manual/html/supplement.resource.html +1 -1
  283. data/manual/html/supplement.task.html +1 -1
  284. data/manual/html/tagfile.html +2 -2
  285. data/manual/html/task.html +1 -1
  286. data/manual/html/task.statussheet.html +1 -1
  287. data/manual/html/task.timesheet.html +1 -1
  288. data/manual/html/taskattributes.html +1 -1
  289. data/manual/html/taskprefix.html +1 -1
  290. data/manual/html/taskreport.html +14 -2
  291. data/manual/html/taskroot.export.html +1 -1
  292. data/manual/html/taskroot.html +1 -1
  293. data/manual/html/text.extend.html +1 -1
  294. data/manual/html/textreport.html +14 -2
  295. data/manual/html/timeformat.html +3 -3
  296. data/manual/html/timeformat1.html +67 -0
  297. data/manual/html/timeformat2.html +67 -0
  298. data/manual/html/timeoff.nikureport.html +3 -3
  299. data/manual/html/timesheet.html +1 -1
  300. data/manual/html/timesheetreport.html +1 -1
  301. data/manual/html/timezone.export.html +1 -1
  302. data/manual/html/timezone.html +1 -1
  303. data/manual/html/timezone.report.html +1 -1
  304. data/manual/html/timezone.shift.html +1 -1
  305. data/manual/html/timingresolution.html +1 -1
  306. data/manual/html/title.column.html +1 -1
  307. data/manual/html/title.html +1 -1
  308. data/manual/html/toc.html +270 -242
  309. data/manual/html/tooltip.column.html +1 -1
  310. data/manual/html/tracereport.html +14 -2
  311. data/manual/html/trackingscenario.html +1 -1
  312. data/manual/html/treelevel.html +1 -1
  313. data/manual/html/vacation.html +1 -1
  314. data/manual/html/vacation.resource.html +1 -1
  315. data/manual/html/vacation.shift.html +1 -1
  316. data/manual/html/warn.html +1 -1
  317. data/manual/html/weeklymax.html +1 -1
  318. data/manual/html/weeklymin.html +1 -1
  319. data/manual/html/weekstartsmonday.html +1 -1
  320. data/manual/html/weekstartssunday.html +1 -1
  321. data/manual/html/width.column.html +1 -1
  322. data/manual/html/width.html +1 -1
  323. data/manual/html/work.html +1 -1
  324. data/manual/html/workinghours.project.html +1 -1
  325. data/manual/html/workinghours.resource.html +1 -1
  326. data/manual/html/workinghours.shift.html +1 -1
  327. data/manual/html/yearlyworkingdays.html +1 -1
  328. data/tasks/kate.rake +8 -0
  329. data/test/TestSuite/HTML-Reports/Calendars.tjp +10 -0
  330. data/test/TestSuite/Scheduler/Correct/PersistentResources-2.tjp +33 -0
  331. data/test/TestSuite/Scheduler/Correct/PersistentResources.tjp +30 -0
  332. data/test/TestSuite/Scheduler/Correct/PriorityInversion.tjp +2 -0
  333. data/test/TestSuite/Syntax/Correct/Macro-4.tjp +4 -0
  334. data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
  335. data/test/test_BatchProcessor.rb +1 -1
  336. data/test/test_CSVFile.rb +10 -0
  337. data/test/test_RichText.rb +20 -0
  338. metadata +38 -9
@@ -179,10 +179,13 @@ class TaskJuggler
179
179
  Thread.new do
180
180
  loop do
181
181
  if TjTime.new - @lastPing > 120
182
- error('ps_heartbeat_lost',
183
- "Report server (Project #{@tj.project['projectid']} " +
184
- "report #{@reportId}) lost heartbeat " +
185
- 'from ProjectServer. Terminating.')
182
+ # Since the abort via error() is not thread safe, we issue a
183
+ # warning and abort manually.
184
+ warning('ps_heartbeat_lost',
185
+ "Report server (Project #{@tj.project['projectid']} " +
186
+ "report #{@reportId}) lost heartbeat " +
187
+ 'from ProjectServer. Terminating.')
188
+ exit 1
186
189
  end
187
190
  sleep 30
188
191
  end
@@ -27,6 +27,8 @@ class TaskJuggler
27
27
  def initialize(report)
28
28
  super
29
29
  @table = ReportTable.new
30
+ @table.selfcontained = report.get('selfcontained')
31
+ @table.auxDir = report.get('auxdir')
30
32
  end
31
33
 
32
34
  # Generate the table in the intermediate format.
@@ -27,9 +27,11 @@ class TaskJuggler
27
27
  # +separator+ and a +quote+ string for the CSV file.
28
28
  def initialize(data = nil, separator = ';', quote = '"')
29
29
  @data = data
30
- raise "Illegal separator: #{separator}" if '."'.include?(separator)
30
+ if !separator.nil? && '."'.include?(separator)
31
+ raise "Illegal separator: #{separator}"
32
+ end
31
33
  @separator = separator
32
- raise "Illegal quote: #{separator}" if quote == '.'
34
+ raise "Illegal quote: #{quote}" if quote == '.'
33
35
  @quote = quote
34
36
  end
35
37
 
@@ -64,6 +66,8 @@ class TaskJuggler
64
66
 
65
67
  # Convert the CSV data into a CSV formatted String.
66
68
  def to_s
69
+ raise "No seperator defined." if @separator.nil?
70
+
67
71
  s = ''
68
72
  @data.each do |line|
69
73
  first = true
@@ -90,6 +94,9 @@ class TaskJuggler
90
94
  # Make sure the input is terminated with a record end.
91
95
  str += "\n" unless str[-1] == ?\n
92
96
 
97
+ # If the user hasn't defined a separator, we try to detect it.
98
+ @separator = detectSeparator(str) unless @separator
99
+
93
100
  line = 1
94
101
  str.each_utf8_char do |c|
95
102
  #puts "c: #{c} State: #{state}"
@@ -232,6 +239,21 @@ class TaskJuggler
232
239
  end
233
240
  end
234
241
 
242
+ def detectSeparator(str)
243
+ # Pick the separator that was found the most.
244
+ best = nil
245
+ bestCount = 0
246
+
247
+ "\t;:".each_char do |c|
248
+ if best.nil? || str.count(c) > bestCount
249
+ best = c
250
+ bestCount = str.count(c)
251
+ end
252
+ end
253
+
254
+ return best
255
+ end
256
+
235
257
  end
236
258
 
237
259
  end
@@ -43,11 +43,12 @@ class TaskJuggler
43
43
  # is the date that should be used as current date. _weekStartsMonday_ is
44
44
  # true if the weeks should start on Mondays instead of Sundays. _table_ is a
45
45
  # reference to the TableReport that the chart is part of.
46
- def initialize(now, weekStartsMonday, table = nil)
46
+ def initialize(now, weekStartsMonday, columnDef, table = nil)
47
47
  # The start and end dates of the reported interval.
48
48
  @start = nil
49
49
  @end = nil
50
50
  @now = now
51
+ @columnDef = columnDef
51
52
  @table = table
52
53
 
53
54
  # This defines the possible horizontal scales that the Gantt chart can
@@ -135,7 +136,7 @@ class TaskJuggler
135
136
  steps = @start.send(@scale['stepsToFunc'], @end)
136
137
  @width = @stepSize * steps
137
138
 
138
- @header = GanttHeader.new(self)
139
+ @header = GanttHeader.new(@columnDef, self)
139
140
  end
140
141
 
141
142
  # Convert the chart into an HTML representation.
@@ -25,7 +25,8 @@ class TaskJuggler
25
25
  attr_accessor :height
26
26
 
27
27
  # Create a GanttHeader object and generate the scales for the header.
28
- def initialize(chart)
28
+ def initialize(columnDef, chart)
29
+ @columnDef = columnDef
29
30
  @chart = chart
30
31
 
31
32
  @largeScale = []
@@ -70,29 +71,32 @@ class TaskJuggler
70
71
  case @chart.scale['name']
71
72
  when 'hour'
72
73
  genHeaderScale(@largeScale, 0, h, :midnight, :sameTimeNextDay,
73
- :weekdayAndDate)
74
+ @columnDef.timeformat1 || '%A %Y-%m-%d')
74
75
  genHeaderScale(@smallScale, h + 1, h, :beginOfHour, :sameTimeNextHour,
75
- :hour)
76
+ @columnDef.timeformat2 || '%H')
76
77
  when 'day'
77
78
  genHeaderScale(@largeScale, 0, h, :beginOfMonth, :sameTimeNextMonth,
78
- :monthAndYear)
79
- genHeaderScale(@smallScale, h + 1, h, :midnight, :sameTimeNextDay, :day)
79
+ @columnDef.timeformat1 || '%b %Y')
80
+ genHeaderScale(@smallScale, h + 1, h, :midnight, :sameTimeNextDay,
81
+ @columnDef.timeformat2 || '%d')
80
82
  when 'week'
81
83
  genHeaderScale(@largeScale, 0, h, :beginOfMonth, :sameTimeNextMonth,
82
- :monthAndYear)
84
+ @columnDef.timeformat1 || '%b %Y')
83
85
  genHeaderScale(@smallScale, h + 1, h, :beginOfWeek, :sameTimeNextWeek,
84
- :week)
86
+ @columnDef.timeformat2 || '%d')
85
87
  when 'month'
86
- genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear, :year)
88
+ genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
89
+ @columnDef.timeformat1 || '%Y')
87
90
  genHeaderScale(@smallScale, h + 1, h, :beginOfMonth, :sameTimeNextMonth,
88
- :shortMonthName)
91
+ @columnDef.timeformat2 || '%b')
89
92
  when 'quarter'
90
- genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear, :year)
93
+ genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
94
+ @columnDef.timeformat1 || '%Y')
91
95
  genHeaderScale(@smallScale, h + 1, h, :beginOfQuarter,
92
- :sameTimeNextQuarter, :quarterName)
96
+ :sameTimeNextQuarter, @columnDef.timeformat2 || 'Q%Q')
93
97
  when 'year'
94
98
  genHeaderScale(@smallScale, h + 1, h, :beginOfYear, :sameTimeNextYear,
95
- :year)
99
+ @columnDef.timeformat1 || '%Y')
96
100
  else
97
101
  raise "Unknown scale: #{@chart.scale['name']}"
98
102
  end
@@ -102,7 +106,7 @@ class TaskJuggler
102
106
  end
103
107
 
104
108
  # Generate the actual scale cells.
105
- def genHeaderScale(scale, y, h, beginOfFunc, sameTimeNextFunc, nameFunc)
109
+ def genHeaderScale(scale, y, h, beginOfFunc, sameTimeNextFunc, timeformat)
106
110
  # The beginOfWeek function needs a parameter, so we have to handle it as a
107
111
  # special case.
108
112
  if beginOfFunc == :beginOfWeek
@@ -125,11 +129,7 @@ class TaskJuggler
125
129
  else
126
130
  @cellStartDates << t
127
131
  end
128
- # Again, nameFunc needs special handling for the week case due to the
129
- # extra parameter.
130
- name = nameFunc == :week ? t.send(nameFunc, @chart.weekStartsMonday) :
131
- t.send(nameFunc)
132
- scale << GanttHeaderScaleItem.new(name, x, y, w, h)
132
+ scale << GanttHeaderScaleItem.new(t.to_s(timeformat), x, y, w, h)
133
133
  t = nextT
134
134
  end
135
135
  # Add the end date of the last cell when generating the small scale.
@@ -30,7 +30,7 @@ class TaskJuggler
30
30
  @lineHeight = line.height
31
31
  @x = x
32
32
  @y = @line.y
33
- @w = w
33
+ @w = w <= 0 ? 1 : w
34
34
  @drawFrame = false
35
35
  if values.length != categories.length
36
36
  raise "Values and categories must have the same number of entries!"
@@ -25,7 +25,11 @@ class TaskJuggler
25
25
  # Create a new object and set some default values.
26
26
  def initialize(report)
27
27
  super(report)
28
- @scenarioIdx = 0
28
+
29
+ # This report type currently only supports a single scenario. Use the
30
+ # first specified one.
31
+ @scenarioIdx = a('scenarios').first
32
+
29
33
  # Hash to map calendar names to UIDs (numbers).
30
34
  @calendarUIDs = {}
31
35
  @timeformat = "%Y-%m-%dT%H:%M:%S"
@@ -78,7 +78,7 @@ class TaskJuggler
78
78
  if @name.empty?
79
79
  error('empty_report_file_name',
80
80
  "Report #{@id} has output formats requested, but the " +
81
- "file name is empty.")
81
+ "file name is empty.", sourceFileInfo)
82
82
  end
83
83
 
84
84
  case format
@@ -179,8 +179,10 @@ class TaskJuggler
179
179
 
180
180
  html = HTMLDocument.new
181
181
  head = html.generateHead(@project['name'] + " - #{get('title') || @name}",
182
- 'description' => 'TaskJuggler Report',
183
- 'keywords' => 'taskjuggler, project, management')
182
+ { 'description' => 'TaskJuggler Report',
183
+ 'keywords' =>
184
+ 'taskjuggler, project, management' },
185
+ a('rawHtmlHead'))
184
186
  if a('selfcontained')
185
187
  auxSrcDir = AppConfig.dataDirs('data/css')[0]
186
188
  cssFileName = (auxSrcDir ? auxSrcDir + '/tjreport.css' : '')
@@ -192,7 +194,7 @@ class TaskJuggler
192
194
  if cssFile.empty?
193
195
  error('css_file_error',
194
196
  "Cannot read '#{cssFileName}'. Make sure the file is not " +
195
- "empty and you have read access permission.")
197
+ "empty and you have read access permission.", sourceFileInfo)
196
198
  end
197
199
  head << XMLElement.new('meta', 'http-equiv' => 'Content-Style-Type',
198
200
  'content' => 'text/css; charset=utf-8')
@@ -201,7 +203,7 @@ class TaskJuggler
201
203
  else
202
204
  head << XMLElement.new('link', 'rel' => 'stylesheet',
203
205
  'type' => 'text/css',
204
- 'href' => 'css/tjreport.css')
206
+ 'href' => "#{a('auxdir')}css/tjreport.css")
205
207
  end
206
208
  html.html <<
207
209
  XMLComment.new("Dynamic Report ID: " +
@@ -210,7 +212,7 @@ class TaskJuggler
210
212
 
211
213
  unless a('selfcontained')
212
214
  body << XMLElement.new('script', 'type' => 'text/javascript',
213
- 'src' => 'scripts/wz_tooltip.js')
215
+ 'src' => "#{a('auxdir')}scripts/wz_tooltip.js")
214
216
  body << (noscript = XMLElement.new('noscript'))
215
217
  noscript << (nsdiv = XMLElement.new('div',
216
218
  'style' => 'text-align:center; ' +
@@ -252,7 +254,8 @@ EOT
252
254
  begin
253
255
  html.write(fileName)
254
256
  rescue IOError, SystemCallError
255
- error('write_html', "Cannot write to file #{fileName}.\n#{$!}")
257
+ error('write_html', "Cannot write to file #{fileName}.\n#{$!}",
258
+ sourceFileInfo)
256
259
  end
257
260
  end
258
261
 
@@ -278,7 +281,8 @@ EOT
278
281
  @name + '.csv').untaint
279
282
  CSVFile.new(csv, ';').write(fileName)
280
283
  rescue IOError, SystemCallError
281
- error('write_csv', "Cannot write to file #{fileName}.\n#{$!}")
284
+ error('write_csv', "Cannot write to file #{fileName}.\n#{$!}",
285
+ sourceFileInfo)
282
286
  end
283
287
  end
284
288
 
@@ -302,7 +306,8 @@ EOT
302
306
  File.open(fileName, 'w') { |f| f.write(@content.to_tjp) }
303
307
  end
304
308
  rescue IOError, SystemCallError
305
- error('write_tjp', "Cannot write to file #{fileName}.\n#{$!}")
309
+ error('write_tjp', "Cannot write to file #{fileName}.\n#{$!}",
310
+ sourceFileInfo)
306
311
  end
307
312
  end
308
313
 
@@ -325,7 +330,8 @@ EOT
325
330
  File.open(fileName, 'w') { |f| f.write(@content.to_mspxml) }
326
331
  end
327
332
  rescue IOError, SystemCallError
328
- error('write_mspxml', "Cannot write to file #{fileName}.\n#{$!}")
333
+ error('write_mspxml', "Cannot write to file #{fileName}.\n#{$!}",
334
+ sourceFileInfo)
329
335
  end
330
336
  end
331
337
 
@@ -344,7 +350,8 @@ EOT
344
350
  @name + '.xml').untaint, 'w')
345
351
  f.puts "#{@content.to_niku}"
346
352
  rescue IOError, SystemCallError
347
- error('write_niku', "Cannot write to file #{@name}.\n#{$!}")
353
+ error('write_niku', "Cannot write to file #{@name}.\n#{$!}",
354
+ sourceFileInfo)
348
355
  end
349
356
  end
350
357
 
@@ -363,7 +370,8 @@ EOT
363
370
  @name + '.ics').untaint, 'w')
364
371
  f.puts "#{@content.to_iCal}"
365
372
  rescue IOError, SystemCallError
366
- error('write_ical', "Cannot write to file #{@name}.\n#{$!}")
373
+ error('write_ical', "Cannot write to file #{@name}.\n#{$!}",
374
+ sourceFileInfo)
367
375
  end
368
376
  end
369
377
 
@@ -382,13 +390,15 @@ EOT
382
390
  @name).untaint, 'w')
383
391
  f.puts "#{@content.to_ctags}"
384
392
  rescue IOError, SystemCallError
385
- error('write_ctags', "Cannot write to file #{@name}.\n#{$!}")
393
+ error('write_ctags', "Cannot write to file #{@name}.\n#{$!}",
394
+ sourceFileInfo)
386
395
  end
387
396
  end
388
397
 
389
398
  def copyAuxiliaryFiles
390
- # Don't copy files if output is stdout.
391
- return if @name == '.' || a('interactive')
399
+ # Don't copy files if output is stdout, the requested by the web server
400
+ # or the user has specified a custom aux directory.
401
+ return if @name == '.' || a('interactive') || !a('auxdir').empty?
392
402
 
393
403
  copyDirectory('css')
394
404
  copyDirectory('icons')
@@ -413,7 +423,7 @@ EOT
413
423
  FileUtils.cp_r(auxSrcDir, auxDstDir)
414
424
  rescue IOError, SystemCallError
415
425
  error('copy_dir', "Cannot copy directory #{auxSrcDir} to " +
416
- "#{auxDstDir}.\n#{$!}")
426
+ "#{auxDstDir}.\n#{$!}", sourceFileInfo)
417
427
  end
418
428
  end
419
429
 
@@ -432,7 +442,7 @@ EOT
432
442
  end
433
443
 
434
444
  def dataDirError(dirName, dirs)
435
- error('data_dir_error', <<"EOT"
445
+ error('data_dir_error', <<"EOT",
436
446
  Cannot find the #{dirName} directory. This is usually the result of an
437
447
  improper TaskJuggler installation. If you know the directory, you can use the
438
448
  TASKJUGGLER_DATA_PATH environment variable to specify the location. The
@@ -442,6 +452,7 @@ tried:
442
452
 
443
453
  #{dirs.join("\n")}
444
454
  EOT
455
+ sourceFileInfo
445
456
  )
446
457
  end
447
458
 
@@ -449,7 +460,7 @@ EOT
449
460
  if name =~ /[\\?%*:|"<>]/
450
461
  error('invalid_file_name',
451
462
  'File names may not contain any of the following characters: ' +
452
- '\?%*:|\"<>')
463
+ '\?%*:|\"<>', sourceFileInfo)
453
464
  end
454
465
  end
455
466
 
@@ -27,7 +27,7 @@ class TaskJuggler
27
27
  SCROLLBARHEIGHT = 20
28
28
 
29
29
  attr_reader :maxIndent, :headerLineHeight, :headerFontSize
30
- attr_accessor :equiLines, :embedded
30
+ attr_accessor :equiLines, :embedded, :selfcontained, :auxDir
31
31
 
32
32
  # Create a new ReportTable object.
33
33
  def initialize
@@ -44,6 +44,10 @@ class TaskJuggler
44
44
  @equiLines = false
45
45
  # True if the table is embedded as a column of another ReportTable.
46
46
  @embedded = false
47
+ # True if the report does not rely on the data of other files.
48
+ @selfcontained = false
49
+ # Path to the auxiliary data directory.
50
+ @auxDir = ''
47
51
  end
48
52
 
49
53
  # This function should only be called by the ReportTableColumn constructor.
@@ -23,7 +23,7 @@ class TaskJuggler
23
23
  attr_reader :line
24
24
  attr_accessor :data, :category, :hidden, :alignment, :padding,
25
25
  :text, :tooltip, :showTooltipHint,
26
- :iconTooltip, :selfcontained,
26
+ :iconTooltip,
27
27
  :cellColor, :indent, :icon, :fontSize, :fontColor,
28
28
  :bold, :width,
29
29
  :rows, :columns, :special
@@ -81,9 +81,6 @@ class TaskJuggler
81
81
  @rows = 1
82
82
  # The number of columns the cell spans
83
83
  @columns = 1
84
- # True of the resulting report should not contain any information from
85
- # other files.
86
- @selfcontained = false
87
84
  # Ignore everything and use this reference to generate the output.
88
85
  @special = nil
89
86
  end
@@ -134,10 +131,11 @@ class TaskJuggler
134
131
 
135
132
  # Overwrite the tooltip if the user has specified a custom tooltip.
136
133
  tooltip = @tooltip if @tooltip
137
- if tooltip && !tooltip.empty? && !@selfcontained
134
+ if tooltip && !tooltip.empty? && !selfcontained
138
135
  if @showTooltipHint
139
136
  row << (td = XMLElement.new('td'))
140
- td << XMLElement.new('img', 'src' => 'icons/details.png',
137
+ td << XMLElement.new('img',
138
+ 'src' => "#{auxDir}icons/details.png",
141
139
  'class' => 'tj_table_cell_tooltip')
142
140
  addHtmlTooltip(tooltip, td, cell)
143
141
  else
@@ -195,6 +193,14 @@ class TaskJuggler
195
193
 
196
194
  private
197
195
 
196
+ def selfcontained
197
+ @line && @line.table.selfcontained
198
+ end
199
+
200
+ def auxDir
201
+ @line ? @line.table.auxDir : nil
202
+ end
203
+
198
204
  def calculateIndentation
199
205
  # In tree sorting mode, some cells have to be indented to reflect the
200
206
  # tree nesting structure. The indentation is achieved with padding cells
@@ -220,9 +226,9 @@ class TaskJuggler
220
226
  end
221
227
 
222
228
  def cellIcon(cell)
223
- if @icon && !@selfcontained
229
+ if @icon && !selfcontained
224
230
  td = XMLElement.new('td', 'class' => 'tj_table_cell_icon')
225
- td << XMLElement.new('img', 'src' => "icons/#{@icon}.png",
231
+ td << XMLElement.new('img', 'src' => "#{auxDir}icons/#{@icon}.png",
226
232
  'alt' => "Icon")
227
233
  addHtmlTooltip(@iconTooltip, td, cell)
228
234
  return td
@@ -279,7 +285,7 @@ class TaskJuggler
279
285
  labelWidth = @width - 8
280
286
  labelWidth -= @leftIndent if @leftIndent
281
287
  labelWidth -= @rightIndent if @rightIndent
282
- if !@selfcontained
288
+ if !selfcontained
283
289
  # The icons are 20 pixels width including padding.
284
290
  labelWidth -= 20 if @icon
285
291
  labelWidth -= 20 if tooltip || @tooltip
@@ -342,7 +348,7 @@ class TaskJuggler
342
348
  end
343
349
 
344
350
  def addHtmlTooltip(tooltip, trigger, hook = nil)
345
- return unless tooltip && !tooltip.empty? && !@selfcontained
351
+ return unless tooltip && !tooltip.empty? && !selfcontained
346
352
 
347
353
  hook = trigger if hook.nil?
348
354
  if tooltip.respond_to?('functionHandler')