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.
- 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')
|