taskjuggler 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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')