taskjuggler 3.3.0 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -0
- data/data/tjp.vim +21 -7
- data/lib/taskjuggler/Allocation.rb +27 -3
- data/lib/taskjuggler/Attributes.rb +3 -2
- data/lib/taskjuggler/HTMLDocument.rb +3 -1
- data/lib/taskjuggler/KateSyntax.rb +213 -0
- data/lib/taskjuggler/Limits.rb +22 -0
- data/lib/taskjuggler/Log.rb +1 -1
- data/lib/taskjuggler/MessageHandler.rb +20 -10
- data/lib/taskjuggler/PTNProxy.rb +6 -1
- data/lib/taskjuggler/Project.rb +10 -4
- data/lib/taskjuggler/ProjectFileParser.rb +1 -2
- data/lib/taskjuggler/ProjectFileScanner.rb +41 -42
- data/lib/taskjuggler/ResourceScenario.rb +41 -1
- data/lib/taskjuggler/RichText/Element.rb +8 -0
- data/lib/taskjuggler/RichText/Parser.rb +1 -1
- data/lib/taskjuggler/RichText/RTFReportLink.rb +20 -10
- data/lib/taskjuggler/RichText/Scanner.rb +54 -38
- data/lib/taskjuggler/RichText/SyntaxRules.rb +12 -0
- data/lib/taskjuggler/SheetReceiver.rb +1 -1
- data/lib/taskjuggler/TableColumnDefinition.rb +5 -1
- data/lib/taskjuggler/TaskJuggler.rb +2 -2
- data/lib/taskjuggler/TaskScenario.rb +117 -33
- data/lib/taskjuggler/TextParser.rb +2 -4
- data/lib/taskjuggler/TextParser/MacroTable.rb +7 -0
- data/lib/taskjuggler/TextParser/Scanner.rb +10 -9
- data/lib/taskjuggler/Tj3Config.rb +1 -1
- data/lib/taskjuggler/TjTime.rb +5 -28
- data/lib/taskjuggler/TjpSyntaxRules.rb +85 -13
- data/lib/taskjuggler/UTF8String.rb +5 -0
- data/lib/taskjuggler/XMLElement.rb +2 -1
- data/lib/taskjuggler/apps/Tj3.rb +29 -5
- data/lib/taskjuggler/daemon/ProcessIntercom.rb +1 -1
- data/lib/taskjuggler/daemon/ProjectServer.rb +5 -2
- data/lib/taskjuggler/daemon/ReportServer.rb +7 -4
- data/lib/taskjuggler/reports/AccountListRE.rb +2 -0
- data/lib/taskjuggler/reports/CSVFile.rb +24 -2
- data/lib/taskjuggler/reports/GanttChart.rb +3 -2
- data/lib/taskjuggler/reports/GanttHeader.rb +18 -18
- data/lib/taskjuggler/reports/GanttLoadStack.rb +1 -1
- data/lib/taskjuggler/reports/MspXmlRE.rb +5 -1
- data/lib/taskjuggler/reports/Report.rb +29 -18
- data/lib/taskjuggler/reports/ReportTable.rb +5 -1
- data/lib/taskjuggler/reports/ReportTableCell.rb +16 -10
- data/lib/taskjuggler/reports/ResourceListRE.rb +2 -0
- data/lib/taskjuggler/reports/TableReport.rb +23 -16
- data/lib/taskjuggler/reports/TaskListRE.rb +2 -0
- data/lib/taskjuggler/reports/TraceReport.rb +1 -1
- data/manual/Installation +5 -1
- data/manual/Intro +1 -0
- data/manual/Rich_Text_Attributes +5 -0
- data/manual/TaskJuggler_Internals +82 -34
- data/manual/Tutorial +1 -1
- data/manual/html/Day_To_Day_Juggling.html +1 -1
- data/manual/html/Getting_Started.html +1 -1
- data/manual/html/How_To_Contribute.html +1 -1
- data/manual/html/Installation.html +3 -2
- data/manual/html/Intro.html +2 -1
- data/manual/html/Reporting_Bugs.html +1 -1
- data/manual/html/Rich_Text_Attributes.html +2 -1
- data/manual/html/Software.html +1 -1
- data/manual/html/TaskJuggler_2x_Migration.html +1 -1
- data/manual/html/TaskJuggler_Internals.html +15 -13
- data/manual/html/The_TaskJuggler_Syntax.html +1 -1
- data/manual/html/Tutorial.html +2 -2
- data/manual/html/account.html +1 -1
- data/manual/html/account.task.html +1 -1
- data/manual/html/accountprefix.html +1 -1
- data/manual/html/accountreport.html +14 -2
- data/manual/html/accountroot.html +1 -1
- data/manual/html/active.html +1 -1
- data/manual/html/adopt.task.html +1 -1
- data/manual/html/aggregate.html +1 -1
- data/manual/html/alert.html +1 -1
- data/manual/html/alertlevels.html +1 -1
- data/manual/html/allocate.html +1 -1
- data/manual/html/alphabet.html +1 -1
- data/manual/html/alternative.html +1 -1
- data/manual/html/author.html +3 -3
- data/manual/html/auxdir.html +69 -0
- data/manual/html/balance.html +3 -3
- data/manual/html/booking.resource.html +1 -1
- data/manual/html/booking.task.html +1 -1
- data/manual/html/caption.html +1 -1
- data/manual/html/cellcolor.column.html +1 -1
- data/manual/html/celltext.column.html +1 -1
- data/manual/html/center.html +1 -1
- data/manual/html/charge.html +1 -1
- data/manual/html/chargeset.html +1 -1
- data/manual/html/columnid.html +21 -9
- data/manual/html/columns.html +2 -2
- data/manual/html/complete.html +1 -1
- data/manual/html/copyright.html +1 -1
- data/manual/html/credits.html +1 -1
- data/manual/html/currency.html +1 -1
- data/manual/html/currencyformat.html +1 -1
- data/manual/html/dailymax.html +1 -1
- data/manual/html/dailymin.html +1 -1
- data/manual/html/dailyworkinghours.html +1 -1
- data/manual/html/date.extend.html +1 -1
- data/manual/html/date.html +1 -1
- data/manual/html/definitions.html +1 -1
- data/manual/html/depends.html +1 -1
- data/manual/html/details.html +1 -1
- data/manual/html/disabled.html +1 -1
- data/manual/html/duration.html +1 -1
- data/manual/html/efficiency.html +1 -1
- data/manual/html/effort.html +1 -1
- data/manual/html/email.html +1 -1
- data/manual/html/enabled.html +1 -1
- data/manual/html/end.column.html +1 -1
- data/manual/html/end.html +1 -1
- data/manual/html/end.limit.html +1 -1
- data/manual/html/end.report.html +1 -1
- data/manual/html/end.timesheet.html +1 -1
- data/manual/html/endcredit.html +1 -1
- data/manual/html/epilog.html +1 -1
- data/manual/html/export.html +1 -1
- data/manual/html/extend.html +1 -1
- data/manual/html/fail.html +1 -1
- data/manual/html/fdl.html +1 -1
- data/manual/html/flags.account.html +1 -1
- data/manual/html/flags.html +1 -1
- data/manual/html/flags.journalentry.html +1 -1
- data/manual/html/flags.report.html +1 -1
- data/manual/html/flags.resource.html +1 -1
- data/manual/html/flags.statussheet.html +1 -1
- data/manual/html/flags.task.html +1 -1
- data/manual/html/flags.timesheet.html +1 -1
- data/manual/html/fontcolor.column.html +1 -1
- data/manual/html/footer.html +1 -1
- data/manual/html/formats.export.html +1 -1
- data/manual/html/formats.html +1 -1
- data/manual/html/functions.html +1 -1
- data/manual/html/gapduration.html +1 -1
- data/manual/html/gaplength.html +1 -1
- data/manual/html/halign.center.html +1 -1
- data/manual/html/halign.column.html +1 -1
- data/manual/html/halign.left.html +1 -1
- data/manual/html/halign.right.html +1 -1
- data/manual/html/hasalert.html +1 -1
- data/manual/html/header.html +1 -1
- data/manual/html/headline.html +1 -1
- data/manual/html/height.html +1 -1
- data/manual/html/hideaccount.html +1 -1
- data/manual/html/hidejournalentry.html +1 -1
- data/manual/html/hidereport.html +1 -1
- data/manual/html/hideresource.html +1 -1
- data/manual/html/hidetask.html +1 -1
- data/manual/html/icalreport.html +1 -1
- data/manual/html/include.macro.html +1 -1
- data/manual/html/include.project.html +1 -1
- data/manual/html/include.properties.html +1 -1
- data/manual/html/index.html +1 -1
- data/manual/html/inherit.extend.html +1 -1
- data/manual/html/interval1.html +1 -1
- data/manual/html/interval2.html +1 -1
- data/manual/html/interval3.html +1 -1
- data/manual/html/interval4.html +1 -1
- data/manual/html/isactive.html +1 -1
- data/manual/html/ischildof.html +1 -1
- data/manual/html/isdependencyof.html +1 -1
- data/manual/html/isdutyof.html +1 -1
- data/manual/html/isfeatureof.html +1 -1
- data/manual/html/isleaf.html +1 -1
- data/manual/html/ismilestone.html +1 -1
- data/manual/html/isongoing.html +1 -1
- data/manual/html/isresource.html +1 -1
- data/manual/html/isresponsibilityof.html +1 -1
- data/manual/html/istask.html +1 -1
- data/manual/html/journalattributes.html +1 -1
- data/manual/html/journalentry.html +1 -1
- data/manual/html/journalmode.html +1 -1
- data/manual/html/leaveallowance.html +1 -1
- data/manual/html/leaves.html +1 -1
- data/manual/html/left.html +1 -1
- data/manual/html/length.html +1 -1
- data/manual/html/limits.allocate.html +1 -1
- data/manual/html/limits.html +1 -1
- data/manual/html/limits.resource.html +1 -1
- data/manual/html/limits.task.html +1 -1
- data/manual/html/listitem.column.html +1 -1
- data/manual/html/listtype.column.html +1 -1
- data/manual/html/loadunit.html +1 -1
- data/manual/html/logicalexpression.html +1 -1
- data/manual/html/logicalflagexpression.html +1 -1
- data/manual/html/macro.html +1 -1
- data/manual/html/managers.html +1 -1
- data/manual/html/mandatory.html +1 -1
- data/manual/html/maxend.html +1 -1
- data/manual/html/maximum.html +1 -1
- data/manual/html/maxstart.html +1 -1
- data/manual/html/milestone.html +1 -1
- data/manual/html/minend.html +1 -1
- data/manual/html/minimum.html +1 -1
- data/manual/html/minstart.html +1 -1
- data/manual/html/monthlymax.html +1 -1
- data/manual/html/monthlymin.html +1 -1
- data/manual/html/navbar.html +9 -1
- data/manual/html/navigator.html +1 -1
- data/manual/html/newtask.html +1 -1
- data/manual/html/nikureport.html +1 -1
- data/manual/html/note.task.html +1 -1
- data/manual/html/now.html +1 -1
- data/manual/html/numberformat.html +1 -1
- data/manual/html/onend.html +1 -1
- data/manual/html/onstart.html +1 -1
- data/manual/html/opennodes.html +1 -1
- data/manual/html/overtime.booking.html +1 -1
- data/manual/html/period.column.html +1 -1
- data/manual/html/period.limit.html +1 -1
- data/manual/html/period.report.html +1 -1
- data/manual/html/period.task.html +1 -1
- data/manual/html/persistent.html +1 -1
- data/manual/html/precedes.html +1 -1
- data/manual/html/priority.html +1 -1
- data/manual/html/priority.timesheet.html +1 -1
- data/manual/html/project.html +1 -1
- data/manual/html/projectid.html +1 -1
- data/manual/html/projectid.task.html +1 -1
- data/manual/html/projectids.html +1 -1
- data/manual/html/projection.html +1 -1
- data/manual/html/prolog.html +1 -1
- data/manual/html/properties.html +1 -1
- data/manual/html/purge.html +1 -1
- data/manual/html/rate.html +1 -1
- data/manual/html/rate.resource.html +3 -3
- data/manual/html/rawhtmlhead.html +68 -0
- data/manual/html/reference.extend.html +3 -3
- data/manual/html/remaining.html +1 -1
- data/manual/html/replace.html +1 -1
- data/manual/html/reportprefix.html +1 -1
- data/manual/html/resource.html +1 -1
- data/manual/html/resourceattributes.html +1 -1
- data/manual/html/resourceprefix.html +1 -1
- data/manual/html/resourcereport.html +14 -2
- data/manual/html/resourceroot.html +1 -1
- data/manual/html/resources.limit.html +1 -1
- data/manual/html/responsible.html +1 -1
- data/manual/html/richtext.extend.html +1 -1
- data/manual/html/right.html +1 -1
- data/manual/html/rollupaccount.html +1 -1
- data/manual/html/rollupresource.html +1 -1
- data/manual/html/rolluptask.html +1 -1
- data/manual/html/scale.column.html +1 -1
- data/manual/html/scenario.html +1 -1
- data/manual/html/scenario.ical.html +1 -1
- data/manual/html/scenarios.export.html +1 -1
- data/manual/html/scenarios.html +1 -1
- data/manual/html/scenariospecific.extend.html +1 -1
- data/manual/html/scheduled.html +1 -1
- data/manual/html/scheduling.html +2 -1
- data/manual/html/select.html +1 -1
- data/manual/html/selfcontained.html +1 -1
- data/manual/html/shift.allocate.html +1 -1
- data/manual/html/shift.html +1 -1
- data/manual/html/shift.resource.html +1 -1
- data/manual/html/shift.task.html +1 -1
- data/manual/html/shift.timesheet.html +1 -1
- data/manual/html/shifts.allocate.html +1 -1
- data/manual/html/shifts.resource.html +1 -1
- data/manual/html/shifts.task.html +1 -1
- data/manual/html/shorttimeformat.html +1 -1
- data/manual/html/sloppy.booking.html +1 -1
- data/manual/html/sloppy.projection.html +1 -1
- data/manual/html/sortaccounts.html +1 -1
- data/manual/html/sortjournalentries.html +1 -1
- data/manual/html/sortresources.html +1 -1
- data/manual/html/sorttasks.html +1 -1
- data/manual/html/start.column.html +1 -1
- data/manual/html/start.html +1 -1
- data/manual/html/start.limit.html +1 -1
- data/manual/html/start.report.html +1 -1
- data/manual/html/startcredit.html +1 -1
- data/manual/html/status.statussheet.html +1 -1
- data/manual/html/status.timesheet.html +1 -1
- data/manual/html/statussheet.html +1 -1
- data/manual/html/statussheetreport.html +1 -1
- data/manual/html/strict.projection.html +1 -1
- data/manual/html/summary.html +1 -1
- data/manual/html/supplement.html +1 -1
- data/manual/html/supplement.resource.html +1 -1
- data/manual/html/supplement.task.html +1 -1
- data/manual/html/tagfile.html +2 -2
- data/manual/html/task.html +1 -1
- data/manual/html/task.statussheet.html +1 -1
- data/manual/html/task.timesheet.html +1 -1
- data/manual/html/taskattributes.html +1 -1
- data/manual/html/taskprefix.html +1 -1
- data/manual/html/taskreport.html +14 -2
- data/manual/html/taskroot.export.html +1 -1
- data/manual/html/taskroot.html +1 -1
- data/manual/html/text.extend.html +1 -1
- data/manual/html/textreport.html +14 -2
- data/manual/html/timeformat.html +3 -3
- data/manual/html/timeformat1.html +67 -0
- data/manual/html/timeformat2.html +67 -0
- data/manual/html/timeoff.nikureport.html +3 -3
- data/manual/html/timesheet.html +1 -1
- data/manual/html/timesheetreport.html +1 -1
- data/manual/html/timezone.export.html +1 -1
- data/manual/html/timezone.html +1 -1
- data/manual/html/timezone.report.html +1 -1
- data/manual/html/timezone.shift.html +1 -1
- data/manual/html/timingresolution.html +1 -1
- data/manual/html/title.column.html +1 -1
- data/manual/html/title.html +1 -1
- data/manual/html/toc.html +270 -242
- data/manual/html/tooltip.column.html +1 -1
- data/manual/html/tracereport.html +14 -2
- data/manual/html/trackingscenario.html +1 -1
- data/manual/html/treelevel.html +1 -1
- data/manual/html/vacation.html +1 -1
- data/manual/html/vacation.resource.html +1 -1
- data/manual/html/vacation.shift.html +1 -1
- data/manual/html/warn.html +1 -1
- data/manual/html/weeklymax.html +1 -1
- data/manual/html/weeklymin.html +1 -1
- data/manual/html/weekstartsmonday.html +1 -1
- data/manual/html/weekstartssunday.html +1 -1
- data/manual/html/width.column.html +1 -1
- data/manual/html/width.html +1 -1
- data/manual/html/work.html +1 -1
- data/manual/html/workinghours.project.html +1 -1
- data/manual/html/workinghours.resource.html +1 -1
- data/manual/html/workinghours.shift.html +1 -1
- data/manual/html/yearlyworkingdays.html +1 -1
- data/tasks/kate.rake +8 -0
- data/test/TestSuite/HTML-Reports/Calendars.tjp +10 -0
- data/test/TestSuite/Scheduler/Correct/PersistentResources-2.tjp +33 -0
- data/test/TestSuite/Scheduler/Correct/PersistentResources.tjp +30 -0
- data/test/TestSuite/Scheduler/Correct/PriorityInversion.tjp +2 -0
- data/test/TestSuite/Syntax/Correct/Macro-4.tjp +4 -0
- data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
- data/test/test_BatchProcessor.rb +1 -1
- data/test/test_CSVFile.rb +10 -0
- data/test/test_RichText.rb +20 -0
- 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(
|
183
|
-
|
184
|
-
|
185
|
-
|
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,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
|
-
|
30
|
+
if !separator.nil? && '."'.include?(separator)
|
31
|
+
raise "Illegal separator: #{separator}"
|
32
|
+
end
|
31
33
|
@separator = separator
|
32
|
-
raise "Illegal 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
|
-
|
74
|
+
@columnDef.timeformat1 || '%A %Y-%m-%d')
|
74
75
|
genHeaderScale(@smallScale, h + 1, h, :beginOfHour, :sameTimeNextHour,
|
75
|
-
|
76
|
+
@columnDef.timeformat2 || '%H')
|
76
77
|
when 'day'
|
77
78
|
genHeaderScale(@largeScale, 0, h, :beginOfMonth, :sameTimeNextMonth,
|
78
|
-
|
79
|
-
genHeaderScale(@smallScale, h + 1, h, :midnight, :sameTimeNextDay,
|
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
|
-
|
84
|
+
@columnDef.timeformat1 || '%b %Y')
|
83
85
|
genHeaderScale(@smallScale, h + 1, h, :beginOfWeek, :sameTimeNextWeek,
|
84
|
-
|
86
|
+
@columnDef.timeformat2 || '%d')
|
85
87
|
when 'month'
|
86
|
-
genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
|
88
|
+
genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
|
89
|
+
@columnDef.timeformat1 || '%Y')
|
87
90
|
genHeaderScale(@smallScale, h + 1, h, :beginOfMonth, :sameTimeNextMonth,
|
88
|
-
|
91
|
+
@columnDef.timeformat2 || '%b')
|
89
92
|
when 'quarter'
|
90
|
-
genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
|
93
|
+
genHeaderScale(@largeScale, 0, h, :beginOfYear, :sameTimeNextYear,
|
94
|
+
@columnDef.timeformat1 || '%Y')
|
91
95
|
genHeaderScale(@smallScale, h + 1, h, :beginOfQuarter,
|
92
|
-
:sameTimeNextQuarter,
|
96
|
+
:sameTimeNextQuarter, @columnDef.timeformat2 || 'Q%Q')
|
93
97
|
when 'year'
|
94
98
|
genHeaderScale(@smallScale, h + 1, h, :beginOfYear, :sameTimeNextYear,
|
95
|
-
|
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,
|
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
|
-
|
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.
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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? &&
|
134
|
+
if tooltip && !tooltip.empty? && !selfcontained
|
138
135
|
if @showTooltipHint
|
139
136
|
row << (td = XMLElement.new('td'))
|
140
|
-
td << XMLElement.new('img',
|
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 &&
|
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
|
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? &&
|
351
|
+
return unless tooltip && !tooltip.empty? && !selfcontained
|
346
352
|
|
347
353
|
hook = trigger if hook.nil?
|
348
354
|
if tooltip.respond_to?('functionHandler')
|