taskjuggler 3.2.0 → 3.3.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 +30 -0
- data/README.rdoc +1 -0
- data/data/tjp.vim +13 -9
- data/lib/taskjuggler/Allocation.rb +2 -2
- data/lib/taskjuggler/AttributeBase.rb +10 -0
- data/lib/taskjuggler/Attributes.rb +2 -8
- data/lib/taskjuggler/Journal.rb +20 -19
- data/lib/taskjuggler/PTNProxy.rb +14 -1
- data/lib/taskjuggler/ProjectFileParser.rb +3 -0
- data/lib/taskjuggler/ProjectFileScanner.rb +54 -44
- data/lib/taskjuggler/PropertyList.rb +32 -0
- data/lib/taskjuggler/PropertyTreeNode.rb +4 -0
- data/lib/taskjuggler/ResourceScenario.rb +53 -20
- data/lib/taskjuggler/RichText/Document.rb +7 -5
- data/lib/taskjuggler/RichText/Scanner.rb +38 -38
- data/lib/taskjuggler/RichText/TOCEntry.rb +1 -1
- data/lib/taskjuggler/TaskScenario.rb +78 -62
- data/lib/taskjuggler/TextParser.rb +4 -3
- data/lib/taskjuggler/TextParser/MacroTable.rb +3 -1
- data/lib/taskjuggler/TextParser/Scanner.rb +73 -58
- data/lib/taskjuggler/Tj3Config.rb +1 -1
- data/lib/taskjuggler/TjpSyntaxRules.rb +215 -67
- data/lib/taskjuggler/apps/Tj3Client.rb +1 -1
- data/lib/taskjuggler/daemon/ReportServer.rb +8 -1
- data/lib/taskjuggler/reports/ExportRE.rb +46 -0
- data/lib/taskjuggler/reports/MspXmlRE.rb +409 -0
- data/lib/taskjuggler/reports/Report.rb +29 -4
- data/lib/taskjuggler/reports/ReportBase.rb +0 -8
- data/lib/taskjuggler/reports/TableReport.rb +13 -3
- data/lib/taskjuggler/reports/TaskListRE.rb +1 -0
- data/lib/taskjuggler/reports/TjpExportRE.rb +1 -1
- data/manual/Rich_Text_Attributes +2 -2
- data/manual/Tutorial +15 -11
- 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 +1 -1
- data/manual/html/Intro.html +1 -1
- data/manual/html/Reporting_Bugs.html +1 -1
- data/manual/html/Rich_Text_Attributes.html +1 -1
- data/manual/html/Software.html +1 -1
- data/manual/html/TaskJuggler_2x_Migration.html +1 -1
- data/manual/html/TaskJuggler_Internals.html +1 -1
- data/manual/html/The_TaskJuggler_Syntax.html +1 -1
- data/manual/html/Tutorial.html +5 -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 +9 -3
- data/manual/html/accountroot.html +1 -1
- data/manual/html/active.html +1 -1
- data/manual/html/adopt.task.html +3 -3
- 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 +5 -2
- data/manual/html/alphabet.html +1 -1
- data/manual/html/alternative.html +1 -1
- data/manual/html/author.html +1 -1
- data/manual/html/balance.html +1 -1
- 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 +43 -4
- data/manual/html/center.html +1 -1
- data/manual/html/charge.html +1 -1
- data/manual/html/chargeset.html +2 -2
- data/manual/html/columnid.html +6 -6
- data/manual/html/columns.html +1 -1
- 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 +2 -2
- 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 +9 -3
- 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 +73 -5
- 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 +72 -0
- data/manual/html/formats.html +3 -3
- data/manual/html/functions.html +3 -3
- data/manual/html/gapduration.html +2 -2
- 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 +2 -2
- data/manual/html/interval2.html +2 -2
- data/manual/html/interval3.html +2 -2
- data/manual/html/interval4.html +2 -2
- 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 +11 -3
- 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 +2 -2
- 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 +5 -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 +8 -5
- data/manual/html/rate.html +1 -1
- data/manual/html/rate.resource.html +1 -1
- data/manual/html/reference.extend.html +1 -1
- 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 +9 -3
- 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 +2 -2
- data/manual/html/scheduling.html +1 -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 +1 -1
- 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 +9 -3
- data/manual/html/taskroot.export.html +104 -0
- data/manual/html/taskroot.html +3 -3
- data/manual/html/text.extend.html +3 -3
- data/manual/html/textreport.html +9 -3
- data/manual/html/timeformat.html +1 -1
- data/manual/html/timeoff.nikureport.html +1 -1
- 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 +203 -189
- data/manual/html/tooltip.column.html +1 -1
- data/manual/html/tracereport.html +9 -3
- 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/test/TestSuite/CSV-Reports/project-1.tji +0 -6
- data/test/TestSuite/CSV-Reports/refs/alert.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/celltext.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +0 -3
- data/test/TestSuite/CSV-Reports/refs/sortByTree.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/sortBy_duration.down.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/sortBy_effort.up.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/sortBy_plan.start.down.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/taskreport.csv +0 -7
- data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +0 -18
- data/test/TestSuite/CSV-Reports/refs/weekly.csv +0 -1
- data/test/TestSuite/HTML-Reports/Alerts-2.tjp +46 -0
- data/test/TestSuite/Scheduler/Correct/purge.tjp +30 -0
- data/test/TestSuite/Syntax/Correct/Export.tjp +8 -2
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +0 -1
- metadata +16 -10
- data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +0 -9
|
@@ -339,7 +339,8 @@ class TaskJuggler
|
|
|
339
339
|
# the syntax rules.
|
|
340
340
|
error("no_reduce",
|
|
341
341
|
"Unexpected token '#{token[1]}' found. " +
|
|
342
|
-
"Expecting
|
|
342
|
+
"Expecting #{@stack.last.state.expectedTokens.length > 1 ?
|
|
343
|
+
'one of ' : ''}" +
|
|
343
344
|
"#{@stack.last.state.expectedTokens.join(', ')}",
|
|
344
345
|
@scanner.sourceFileInfo)
|
|
345
346
|
end
|
|
@@ -428,8 +429,8 @@ class TaskJuggler
|
|
|
428
429
|
end
|
|
429
430
|
end
|
|
430
431
|
end
|
|
431
|
-
|
|
432
|
-
|
|
432
|
+
puts " -> #{sl.state ? sl.state.to_s(true) : 'nil'}" +
|
|
433
|
+
"#{sl.function.nil? ? '' : '(Called)'}"
|
|
433
434
|
end
|
|
434
435
|
end
|
|
435
436
|
|
|
@@ -62,9 +62,11 @@ class TaskJuggler::TextParser
|
|
|
62
62
|
resolved = @macros[name].value.dup
|
|
63
63
|
i = 0
|
|
64
64
|
args.each do |arg|
|
|
65
|
-
resolved.gsub!("
|
|
65
|
+
resolved.gsub!(Regexp.new("(([^$]|^))\\$\\{#{i}\\}"), "\\1#{arg}")
|
|
66
66
|
i += 1
|
|
67
67
|
end
|
|
68
|
+
# Remove the escape character from all the escaped '${...}'.
|
|
69
|
+
resolved.gsub!('$${', '${')
|
|
68
70
|
[ @macros[name], resolved ]
|
|
69
71
|
end
|
|
70
72
|
|
|
@@ -84,12 +84,11 @@ class TaskJuggler::TextParser
|
|
|
84
84
|
@line = preCall + text + @scanner.post_match
|
|
85
85
|
# Start the StringScanner again at the first character of the injected
|
|
86
86
|
# text.
|
|
87
|
-
@scanner =
|
|
87
|
+
@scanner.string = @line
|
|
88
88
|
@scanner.pos = preCall.bytesize
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def injectMacro(macro, args, text, callLength)
|
|
92
|
-
# We add 3 chars more for the ${}.
|
|
93
92
|
injectText(text, callLength)
|
|
94
93
|
|
|
95
94
|
# Simple detection for recursive macro calls.
|
|
@@ -99,7 +98,7 @@ class TaskJuggler::TextParser
|
|
|
99
98
|
true
|
|
100
99
|
end
|
|
101
100
|
|
|
102
|
-
def
|
|
101
|
+
def readyNextLine
|
|
103
102
|
# We read the file line by line with gets(). If we don't have a line
|
|
104
103
|
# yet or we've reached the end of a line, we get the next one.
|
|
105
104
|
if @scanner.nil? || @scanner.eos?
|
|
@@ -109,15 +108,20 @@ class TaskJuggler::TextParser
|
|
|
109
108
|
else
|
|
110
109
|
# We've reached the end of the current file.
|
|
111
110
|
@scanner = nil
|
|
112
|
-
|
|
113
|
-
return :scannerEOF
|
|
111
|
+
return false
|
|
114
112
|
end
|
|
115
113
|
@scanner = StringScanner.new(@line)
|
|
116
114
|
@wrapped = @line[-1] == ?\n
|
|
117
115
|
end
|
|
118
|
-
return nil if (token = @scanner.scan(re)).nil?
|
|
119
|
-
#puts "#{re.to_s[0..20]}: [#{token}]"
|
|
120
116
|
|
|
117
|
+
true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def scan(re)
|
|
121
|
+
@scanner.scan(re)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def cleanupMacroStack
|
|
121
125
|
if @nextMacroEnd
|
|
122
126
|
pos = @scanner.pos
|
|
123
127
|
while @nextMacroEnd && @nextMacroEnd < pos
|
|
@@ -125,8 +129,6 @@ class TaskJuggler::TextParser
|
|
|
125
129
|
@nextMacroEnd = @macroStack.empty? ? nil : @macroStack.last.endPos
|
|
126
130
|
end
|
|
127
131
|
end
|
|
128
|
-
|
|
129
|
-
token
|
|
130
132
|
end
|
|
131
133
|
|
|
132
134
|
def peek(n)
|
|
@@ -240,9 +242,9 @@ class TaskJuggler::TextParser
|
|
|
240
242
|
tokenPatterns.each do |pat|
|
|
241
243
|
type = pat[0]
|
|
242
244
|
regExp = pat[1]
|
|
243
|
-
mode = pat[
|
|
244
|
-
postProc = pat[
|
|
245
|
-
addPattern(type, regExp, mode, postProc)
|
|
245
|
+
mode = pat[3] || :tjp
|
|
246
|
+
postProc = pat[4]
|
|
247
|
+
addPattern(type, Regexp.new(regExp), mode, postProc)
|
|
246
248
|
end
|
|
247
249
|
self.mode = defaultMode
|
|
248
250
|
end
|
|
@@ -415,52 +417,7 @@ class TaskJuggler::TextParser
|
|
|
415
417
|
end
|
|
416
418
|
end
|
|
417
419
|
|
|
418
|
-
|
|
419
|
-
@startOfToken = sourceFileInfo
|
|
420
|
-
loop do
|
|
421
|
-
match = nil
|
|
422
|
-
begin
|
|
423
|
-
@activePatterns.each do |type, re, postProc|
|
|
424
|
-
if (match = @cf.scan(re))
|
|
425
|
-
if match == :scannerEOF
|
|
426
|
-
if @scannerMode != @defaultMode
|
|
427
|
-
# The stream resets the line number to 1. Since we still
|
|
428
|
-
# know the start of the token, we setup @lineDelta so that
|
|
429
|
-
# sourceFileInfo() returns the proper line number.
|
|
430
|
-
@lineDelta = -(@startOfToken.lineNo - 1)
|
|
431
|
-
error('runaway_token',
|
|
432
|
-
"Unterminated token starting at #{@startOfToken}")
|
|
433
|
-
end
|
|
434
|
-
# We've found the end of an input file. Return a special token
|
|
435
|
-
# that describes the end of a file.
|
|
436
|
-
@finishLastFile = true
|
|
437
|
-
return [ :eof, '<END>', @startOfToken ]
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
raise "#{re} matches empty string" if match.empty?
|
|
441
|
-
# If we have a post processing method, call it now. It may modify
|
|
442
|
-
# the type or the found token String.
|
|
443
|
-
type, match = postProc.call(type, match) if postProc
|
|
444
|
-
|
|
445
|
-
break if type.nil? # Ignore certain tokens with nil type.
|
|
446
|
-
|
|
447
|
-
return [ type, match, @startOfToken ]
|
|
448
|
-
end
|
|
449
|
-
end
|
|
450
|
-
rescue ArgumentError
|
|
451
|
-
error('scan_encoding_error', $!.to_s)
|
|
452
|
-
end
|
|
453
|
-
|
|
454
|
-
if match.nil?
|
|
455
|
-
if @cf.eof?
|
|
456
|
-
error('unexpected_eof',
|
|
457
|
-
"Unexpected end of file found")
|
|
458
|
-
else
|
|
459
|
-
error('no_token_match',
|
|
460
|
-
"Unexpected characters found: '#{@cf.peek(10)}...'")
|
|
461
|
-
end
|
|
462
|
-
end
|
|
463
|
-
end
|
|
420
|
+
scanToken
|
|
464
421
|
end
|
|
465
422
|
|
|
466
423
|
# Return a token to retrieve it with the next nextToken() call again. Only 1
|
|
@@ -515,6 +472,64 @@ class TaskJuggler::TextParser
|
|
|
515
472
|
|
|
516
473
|
private
|
|
517
474
|
|
|
475
|
+
def scanToken
|
|
476
|
+
@startOfToken = sourceFileInfo
|
|
477
|
+
begin
|
|
478
|
+
match = nil
|
|
479
|
+
loop do
|
|
480
|
+
# First make sure that the line buffer has been filled and we have a
|
|
481
|
+
# line to parse.
|
|
482
|
+
unless @cf.readyNextLine
|
|
483
|
+
if @scannerMode != @defaultMode
|
|
484
|
+
# The stream resets the line number to 1. Since we still
|
|
485
|
+
# know the start of the token, we setup @lineDelta so that
|
|
486
|
+
# sourceFileInfo() returns the proper line number.
|
|
487
|
+
@lineDelta = -(@startOfToken.lineNo - 1)
|
|
488
|
+
error('runaway_token',
|
|
489
|
+
"Unterminated token starting at line #{@startOfToken}")
|
|
490
|
+
end
|
|
491
|
+
# We've found the end of an input file. Return a special token
|
|
492
|
+
# that describes the end of a file.
|
|
493
|
+
@finishLastFile = true
|
|
494
|
+
return [ :eof, '<END>', @startOfToken ]
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
@activePatterns.each do |type, re, postProc|
|
|
498
|
+
if (match = @cf.scan(re))
|
|
499
|
+
#raise "#{re} matches empty string" if match.empty?
|
|
500
|
+
# If we have a post processing method, call it now. It may modify
|
|
501
|
+
# the type or the found token String.
|
|
502
|
+
type, match = postProc.call(type, match) if postProc
|
|
503
|
+
|
|
504
|
+
break if type.nil? # Ignore certain tokens with nil type.
|
|
505
|
+
|
|
506
|
+
@cf.cleanupMacroStack
|
|
507
|
+
return [ type, match, @startOfToken ]
|
|
508
|
+
end
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
if match.nil?
|
|
512
|
+
# If we haven't found a match, we either hit EOF or a token we did
|
|
513
|
+
# not expect.
|
|
514
|
+
if @cf.eof?
|
|
515
|
+
error('unexpected_eof',
|
|
516
|
+
"Unexpected end of file found")
|
|
517
|
+
else
|
|
518
|
+
error('no_token_match',
|
|
519
|
+
"Unexpected characters found: '#{@cf.peek(10)}...'")
|
|
520
|
+
end
|
|
521
|
+
else
|
|
522
|
+
# Remove completely scanned expanded macros from stack.
|
|
523
|
+
@cf.cleanupMacroStack
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
rescue ArgumentError
|
|
527
|
+
# This is triggered by StringScanner.scan, but we don't want to put
|
|
528
|
+
# the block in the inner loops for performance reasons.
|
|
529
|
+
error('scan_encoding_error', $!.to_s)
|
|
530
|
+
end
|
|
531
|
+
end
|
|
532
|
+
|
|
518
533
|
def message(type, id, text, sfi, data)
|
|
519
534
|
unless text.empty?
|
|
520
535
|
line = @cf ? @cf.line : nil
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
require 'taskjuggler/UTF8String'
|
|
15
15
|
require 'taskjuggler/AppConfig'
|
|
16
16
|
|
|
17
|
-
AppConfig.version = '3.
|
|
17
|
+
AppConfig.version = '3.3.0'
|
|
18
18
|
AppConfig.packageName = 'taskjuggler'
|
|
19
19
|
AppConfig.softwareName = 'TaskJuggler'
|
|
20
20
|
AppConfig.packageInfo = 'A Project Management Software'
|
|
@@ -247,6 +247,11 @@ exactly it will be assigned to the task. Shifts and limits can be used to
|
|
|
247
247
|
restrict the allocation to certain time intervals or to limit them to a
|
|
248
248
|
certain maximum per time period. The purge statement can be used to remove
|
|
249
249
|
inherited allocations or flags.
|
|
250
|
+
|
|
251
|
+
For effort-based tasks the task duration is clipped to only extend from the
|
|
252
|
+
begining of the first allocation to the end of the last allocation. This is
|
|
253
|
+
done to optimize for an overall minimum project duration as dependent tasks
|
|
254
|
+
can potentially use the unallocated, clipped slots.
|
|
250
255
|
EOT
|
|
251
256
|
)
|
|
252
257
|
example('Allocate-1', '1')
|
|
@@ -611,7 +616,7 @@ consists of one or more accounts. Each account must be a leaf account. The
|
|
|
611
616
|
account ID may be followed by a percentage value that determines the share for
|
|
612
617
|
this account. The total percentage of all accounts must be exactly 100%. If
|
|
613
618
|
some accounts don't have a percentage specification, the remainder to 100% is
|
|
614
|
-
distributed evenly
|
|
619
|
+
distributed evenly between them.
|
|
615
620
|
EOT
|
|
616
621
|
)
|
|
617
622
|
end
|
|
@@ -731,7 +736,7 @@ which cells the text should be used. If multiple celltext patterns are
|
|
|
731
736
|
provided for a column, the first matching one is taken for each cell.
|
|
732
737
|
EOT
|
|
733
738
|
)
|
|
734
|
-
arg(
|
|
739
|
+
arg(2, 'text',
|
|
735
740
|
'Alterntive cell text specified as [[Rich_Text_Attributes|Rich Text]]')
|
|
736
741
|
|
|
737
742
|
pattern(%w( _cellcolor !logicalExpression !color ), lambda {
|
|
@@ -1012,7 +1017,7 @@ EOT
|
|
|
1012
1017
|
|
|
1013
1018
|
def rule_export
|
|
1014
1019
|
pattern(%w( !exportHeader !exportBody ), lambda {
|
|
1015
|
-
@property =
|
|
1020
|
+
@property = @property.parent
|
|
1016
1021
|
})
|
|
1017
1022
|
doc('export', <<'EOT'
|
|
1018
1023
|
The export report looks like a regular TaskJuggler file with the provided
|
|
@@ -1033,30 +1038,6 @@ EOT
|
|
|
1033
1038
|
example('Export')
|
|
1034
1039
|
end
|
|
1035
1040
|
|
|
1036
|
-
def rule_exportHeader
|
|
1037
|
-
pattern(%w( _export !optionalID $STRING ), lambda {
|
|
1038
|
-
newReport(@val[1], @val[2], :export, @sourceFileInfo[0])
|
|
1039
|
-
@property.set('formats', [ :tjp ])
|
|
1040
|
-
|
|
1041
|
-
# By default, we export all scenarios.
|
|
1042
|
-
scenarios = Array.new(@project.scenarios.items) { |i| i }
|
|
1043
|
-
scenarios.delete_if { |sc| !@project.scenario(sc).get('active') }
|
|
1044
|
-
@property.set('scenarios', scenarios)
|
|
1045
|
-
# Show all tasks, sorted by seqno-up.
|
|
1046
|
-
@property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
|
|
1047
|
-
@property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
|
|
1048
|
-
# Show all resources, sorted by seqno-up.
|
|
1049
|
-
@property.set('hideResource',
|
|
1050
|
-
LogicalExpression.new(LogicalOperation.new(0)))
|
|
1051
|
-
@property.set('sortResources', [ [ 'seqno', true, -1 ] ])
|
|
1052
|
-
})
|
|
1053
|
-
arg(2, 'file name', <<'EOT'
|
|
1054
|
-
The name of the report file to generate. It must end with a .tjp or .tji
|
|
1055
|
-
extension, or use . to use the standard output channel.
|
|
1056
|
-
EOT
|
|
1057
|
-
)
|
|
1058
|
-
end
|
|
1059
|
-
|
|
1060
1041
|
def rule_exportAttributes
|
|
1061
1042
|
optional
|
|
1062
1043
|
repeatable
|
|
@@ -1078,10 +1059,26 @@ EOT
|
|
|
1078
1059
|
'projecids' => 'Include project IDs',
|
|
1079
1060
|
'tasks' => 'Include task definitions',
|
|
1080
1061
|
'resources' => 'Include resource definitions' })
|
|
1062
|
+
|
|
1063
|
+
pattern(%w( _formats !exportFormats ), lambda {
|
|
1064
|
+
@property.set('formats', @val[1])
|
|
1065
|
+
})
|
|
1066
|
+
level(:beta)
|
|
1067
|
+
doc('formats.export', <<'EOT'
|
|
1068
|
+
This attribute defines for which output formats the export report should be
|
|
1069
|
+
generated. By default, the TJP format will be used.
|
|
1070
|
+
EOT
|
|
1071
|
+
)
|
|
1072
|
+
|
|
1081
1073
|
pattern(%w( !hideresource ))
|
|
1082
1074
|
pattern(%w( !hidetask ))
|
|
1075
|
+
|
|
1076
|
+
pattern(%w( !loadunit ))
|
|
1077
|
+
|
|
1078
|
+
pattern(%w( !purge ))
|
|
1083
1079
|
pattern(%w( !reportEnd ))
|
|
1084
1080
|
pattern(%w( !reportPeriod ))
|
|
1081
|
+
pattern(%w( !reports ))
|
|
1085
1082
|
pattern(%w( !reportStart ))
|
|
1086
1083
|
|
|
1087
1084
|
pattern(%w( _resourceattributes !exportableResourceAttributes ), lambda {
|
|
@@ -1131,6 +1128,24 @@ EOT
|
|
|
1131
1128
|
'priority' => 'Include priorities',
|
|
1132
1129
|
'responsible' => 'Include responsible resource' })
|
|
1133
1130
|
|
|
1131
|
+
pattern(%w( _taskroot !taskId), lambda {
|
|
1132
|
+
if @val[1].leaf?
|
|
1133
|
+
error('taskroot_leaf',
|
|
1134
|
+
"#{@val[1].fullId} is not a container task",
|
|
1135
|
+
@sourceFileInfo[1])
|
|
1136
|
+
end
|
|
1137
|
+
@property.set('taskroot', @val[1])
|
|
1138
|
+
})
|
|
1139
|
+
level(:experimental)
|
|
1140
|
+
doc('taskroot.export', <<'EOT'
|
|
1141
|
+
Only tasks below the specified root-level tasks are exported. The exported
|
|
1142
|
+
tasks will have the ID of the root-level task stripped from their ID, so that
|
|
1143
|
+
the sub-tasks of the root-level task become top-level tasks in the report
|
|
1144
|
+
file.
|
|
1145
|
+
EOT
|
|
1146
|
+
)
|
|
1147
|
+
example('TaskRoot')
|
|
1148
|
+
|
|
1134
1149
|
pattern(%w( _timezone !validTimeZone ), lambda {
|
|
1135
1150
|
@property.set('timezone', @val[1])
|
|
1136
1151
|
})
|
|
@@ -1142,6 +1157,72 @@ EOT
|
|
|
1142
1157
|
optionsRule('exportAttributes')
|
|
1143
1158
|
end
|
|
1144
1159
|
|
|
1160
|
+
def rule_exportFormat
|
|
1161
|
+
pattern(%w( _tjp ), lambda {
|
|
1162
|
+
:tjp
|
|
1163
|
+
})
|
|
1164
|
+
descr('Export of the scheduled project in TJP syntax.')
|
|
1165
|
+
|
|
1166
|
+
pattern(%w( _mspxml ), lambda {
|
|
1167
|
+
:mspxml
|
|
1168
|
+
})
|
|
1169
|
+
descr(<<'EOT'
|
|
1170
|
+
Export of the scheduled project in Microsoft Project XML format. This will
|
|
1171
|
+
export the data of the fully scheduled project. The exported data include the
|
|
1172
|
+
tasks, resources and the assignments of resources to task. This is only a
|
|
1173
|
+
small subset of the data that TaskJuggler can manage. This export is intended
|
|
1174
|
+
to share resource assignment data with other teams using Microsoft Project.
|
|
1175
|
+
TaskJuggler manages assignments with a larger accuracy than the Microsft
|
|
1176
|
+
Project XML format can represent. This will inevitably lead to some rounding
|
|
1177
|
+
errors and different interpretation of the data. The numbers you will see in
|
|
1178
|
+
Project are not necessarily an exact match of the numbers you see in
|
|
1179
|
+
TaskJuggler.
|
|
1180
|
+
EOT
|
|
1181
|
+
)
|
|
1182
|
+
end
|
|
1183
|
+
|
|
1184
|
+
def rule_exportFormats
|
|
1185
|
+
pattern(%w( !exportFormat !moreExportFormats ), lambda {
|
|
1186
|
+
[ @val[0] ] + (@val[1].nil? ? [] : @val[1])
|
|
1187
|
+
})
|
|
1188
|
+
end
|
|
1189
|
+
|
|
1190
|
+
def rule_exportHeader
|
|
1191
|
+
pattern(%w( _export !optionalID $STRING ), lambda {
|
|
1192
|
+
newReport(@val[1], @val[2], :export, @sourceFileInfo[0])
|
|
1193
|
+
unless @property.modified?('formats')
|
|
1194
|
+
@property.set('formats', [ :tjp ])
|
|
1195
|
+
end
|
|
1196
|
+
|
|
1197
|
+
# By default, we export all scenarios.
|
|
1198
|
+
unless @property.modified?('scenarios')
|
|
1199
|
+
scenarios = Array.new(@project.scenarios.items) { |i| i }
|
|
1200
|
+
scenarios.delete_if { |sc| !@project.scenario(sc).get('active') }
|
|
1201
|
+
@property.set('scenarios', scenarios)
|
|
1202
|
+
end
|
|
1203
|
+
# Show all tasks, sorted by seqno-up.
|
|
1204
|
+
unless @property.modified?('hideTask')
|
|
1205
|
+
@property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
|
|
1206
|
+
end
|
|
1207
|
+
unless @property.modified?('sortTasks')
|
|
1208
|
+
@property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
|
|
1209
|
+
end
|
|
1210
|
+
# Show all resources, sorted by seqno-up.
|
|
1211
|
+
unless @property.modified?('hideResource')
|
|
1212
|
+
@property.set('hideResource',
|
|
1213
|
+
LogicalExpression.new(LogicalOperation.new(0)))
|
|
1214
|
+
end
|
|
1215
|
+
unless @property.modified?('sortResources')
|
|
1216
|
+
@property.set('sortResources', [ [ 'seqno', true, -1 ] ])
|
|
1217
|
+
end
|
|
1218
|
+
})
|
|
1219
|
+
arg(2, 'file name', <<'EOT'
|
|
1220
|
+
The name of the report file to generate. It must end with a .tjp or .tji
|
|
1221
|
+
extension, or use . to use the standard output channel.
|
|
1222
|
+
EOT
|
|
1223
|
+
)
|
|
1224
|
+
end
|
|
1225
|
+
|
|
1145
1226
|
def rule_extendAttributes
|
|
1146
1227
|
optional
|
|
1147
1228
|
repeatable
|
|
@@ -1912,12 +1993,23 @@ EOT
|
|
|
1912
1993
|
error('zero_duration', "The interval duration may not be 0.",
|
|
1913
1994
|
@sourceFileInfo[1])
|
|
1914
1995
|
end
|
|
1915
|
-
duration = @val[0] * convFactors[@val[1]]
|
|
1996
|
+
duration = (@val[0] * convFactors[@val[1]]).to_i
|
|
1916
1997
|
resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
|
|
1998
|
+
if @val[1] == 4
|
|
1999
|
+
# If the duration unit is months, we have to align the duration with
|
|
2000
|
+
# the timing resolution of the project.
|
|
2001
|
+
duration = (duration / resolution).to_i * resolution
|
|
2002
|
+
end
|
|
1917
2003
|
# Make sure the interval aligns with the timing resolution.
|
|
1918
|
-
|
|
2004
|
+
if duration % resolution != 0
|
|
2005
|
+
error('iv_duration_not_aligned',
|
|
2006
|
+
"The interval duration must be a multiple of the specified " +
|
|
2007
|
+
"timing resolution (#{resolution / 60} min) of the project.")
|
|
2008
|
+
end
|
|
2009
|
+
duration
|
|
1919
2010
|
})
|
|
1920
|
-
arg(0, 'duration', 'The duration of the interval. May not be 0
|
|
2011
|
+
arg(0, 'duration', 'The duration of the interval. May not be 0 and must ' +
|
|
2012
|
+
'be a multiple of [[timingresolution]].')
|
|
1921
2013
|
end
|
|
1922
2014
|
|
|
1923
2015
|
def rule_intervalEnd
|
|
@@ -1993,6 +2085,14 @@ EOT
|
|
|
1993
2085
|
This mode only yields entries if used in the context of a task. It contains
|
|
1994
2086
|
all journal entries that are dated in the query interval for the task and all
|
|
1995
2087
|
its sub tasks.
|
|
2088
|
+
EOT
|
|
2089
|
+
)
|
|
2090
|
+
pattern(%w( _status_dep ), lambda { :status_dep })
|
|
2091
|
+
descr(<<'EOT'
|
|
2092
|
+
In this mode only the last entries before the report end date for each
|
|
2093
|
+
property and all its sub-properties and their dependencies are included. If
|
|
2094
|
+
there are multiple entries at the exact same date, then all these entries are
|
|
2095
|
+
included.
|
|
1996
2096
|
EOT
|
|
1997
2097
|
)
|
|
1998
2098
|
pattern(%w( _status_down ), lambda { :status_down })
|
|
@@ -2009,6 +2109,16 @@ property are included. If there are multiple entries at the exact same date,
|
|
|
2009
2109
|
then all these entries are included. If any of the parent properties has a
|
|
2010
2110
|
more recent entry that is still before the report end date, no entries will be
|
|
2011
2111
|
included.
|
|
2112
|
+
EOT
|
|
2113
|
+
)
|
|
2114
|
+
pattern(%w( _alerts_dep ), lambda { :alerts_dep })
|
|
2115
|
+
descr(<<'EOT'
|
|
2116
|
+
In this mode only the last entries before the report end date for the context
|
|
2117
|
+
property and all its sub-properties and their dependencies is included. If
|
|
2118
|
+
there are multiple entries at the exact same date, then all these entries are
|
|
2119
|
+
included. In contrast to the ''''status_down'''' mode, only entries with an
|
|
2120
|
+
alert level above the default level, and only those with the highest overall
|
|
2121
|
+
alert level are included.
|
|
2012
2122
|
EOT
|
|
2013
2123
|
)
|
|
2014
2124
|
pattern(%w( _alerts_down ), lambda { :alerts_down })
|
|
@@ -2412,6 +2522,16 @@ EOT
|
|
|
2412
2522
|
end
|
|
2413
2523
|
|
|
2414
2524
|
def rule_loadunit
|
|
2525
|
+
pattern(%w( _loadunit !loadunitName ), lambda {
|
|
2526
|
+
@property.set('loadUnit', @val[1])
|
|
2527
|
+
})
|
|
2528
|
+
doc('loadunit', <<'EOT'
|
|
2529
|
+
Determines what unit should be used to display all load values in this report.
|
|
2530
|
+
EOT
|
|
2531
|
+
)
|
|
2532
|
+
end
|
|
2533
|
+
|
|
2534
|
+
def rule_loadunitName
|
|
2415
2535
|
pattern([ '_days' ], lambda { :days })
|
|
2416
2536
|
descr('Display all load and duration values as days.')
|
|
2417
2537
|
|
|
@@ -2455,7 +2575,7 @@ EOT
|
|
|
2455
2575
|
LogicalExpression.new(@val[0], sourceFileInfo)
|
|
2456
2576
|
})
|
|
2457
2577
|
pattern(%w( _@ !allOrNone ), lambda {
|
|
2458
|
-
LogicalOperation.new(@val[1])
|
|
2578
|
+
LogicalExpression.new(LogicalOperation.new(@val[1]), sourceFileInfo)
|
|
2459
2579
|
})
|
|
2460
2580
|
doc('logicalexpression', <<'EOT'
|
|
2461
2581
|
A logical expression is a combination of operands and mathematical operations.
|
|
@@ -2559,6 +2679,10 @@ EOT
|
|
|
2559
2679
|
commaListRule('!taskDep')
|
|
2560
2680
|
end
|
|
2561
2681
|
|
|
2682
|
+
def rule_moreExportFormats
|
|
2683
|
+
commaListRule('!exportFormat')
|
|
2684
|
+
end
|
|
2685
|
+
|
|
2562
2686
|
def rule_moreJournalSortCriteria
|
|
2563
2687
|
commaListRule('!journalSortCriterium')
|
|
2564
2688
|
end
|
|
@@ -2909,6 +3033,17 @@ EOT
|
|
|
2909
3033
|
@val[0] / 100.0
|
|
2910
3034
|
})
|
|
2911
3035
|
end
|
|
3036
|
+
def rule_optionalScenarioIdCol
|
|
3037
|
+
optional
|
|
3038
|
+
pattern(%w( $ID_WITH_COLON ), lambda {
|
|
3039
|
+
if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
|
|
3040
|
+
error('unknown_scenario_id', "Unknown scenario: #{@val[0]}",
|
|
3041
|
+
@sourceFileInfo[0])
|
|
3042
|
+
end
|
|
3043
|
+
@scenarioIdx
|
|
3044
|
+
})
|
|
3045
|
+
end
|
|
3046
|
+
|
|
2912
3047
|
|
|
2913
3048
|
def rule_optionalVersion
|
|
2914
3049
|
optional
|
|
@@ -3447,21 +3582,27 @@ EOT
|
|
|
3447
3582
|
end
|
|
3448
3583
|
|
|
3449
3584
|
def rule_purge
|
|
3450
|
-
pattern(%w( _purge $ID ), lambda {
|
|
3451
|
-
|
|
3585
|
+
pattern(%w( _purge !optionalScenarioIdCol $ID ), lambda {
|
|
3586
|
+
attrId = @val[2]
|
|
3587
|
+
if (attributeDefinition = @property.attributeDefinition(attrId)).nil?
|
|
3452
3588
|
error('purge_unknown_id',
|
|
3453
|
-
"#{
|
|
3454
|
-
@sourceFileInfo[
|
|
3589
|
+
"#{attrId} is not a known attribute for this property",
|
|
3590
|
+
@sourceFileInfo[2])
|
|
3455
3591
|
end
|
|
3456
3592
|
if attributeDefinition.scenarioSpecific
|
|
3457
|
-
|
|
3593
|
+
@scenarioIdx = 0 unless @val[1]
|
|
3594
|
+
attr = @property[attrId, 0]
|
|
3458
3595
|
else
|
|
3459
|
-
|
|
3596
|
+
if @val[1]
|
|
3597
|
+
error('purge_non_sc_spec_attr',
|
|
3598
|
+
'Scenario specified for a non-scenario specific attribute')
|
|
3599
|
+
end
|
|
3600
|
+
attr = @property.get(attrId)
|
|
3460
3601
|
end
|
|
3461
|
-
if @property.attributeDefinition(
|
|
3462
|
-
@property.getAttribute(
|
|
3602
|
+
if @property.attributeDefinition(attrId).scenarioSpecific
|
|
3603
|
+
@property.getAttribute(attrId, @scenarioIdx).reset
|
|
3463
3604
|
else
|
|
3464
|
-
@property.getAttribute(
|
|
3605
|
+
@property.getAttribute(attrId).reset
|
|
3465
3606
|
end
|
|
3466
3607
|
})
|
|
3467
3608
|
doc('purge', <<'EOT'
|
|
@@ -3475,6 +3616,10 @@ the list that was inherited from the enclosing property. The purge
|
|
|
3475
3616
|
attribute resets any attribute to its default value. A subsequent definition
|
|
3476
3617
|
for the attribute within the property will then add their values to an empty
|
|
3477
3618
|
list. The value of the enclosing property is not affected by purge.
|
|
3619
|
+
|
|
3620
|
+
For scenario specific attributes, an optional scenario ID can be specified
|
|
3621
|
+
before the attribute ID. If it's missing, the default (first) scenario will be
|
|
3622
|
+
used.
|
|
3478
3623
|
EOT
|
|
3479
3624
|
)
|
|
3480
3625
|
arg(1, 'attribute', 'Any name of a list attribute')
|
|
@@ -3506,6 +3651,7 @@ EOT
|
|
|
3506
3651
|
|
|
3507
3652
|
def rule_reports
|
|
3508
3653
|
pattern(%w( !accountReport ))
|
|
3654
|
+
pattern(%w( !export ))
|
|
3509
3655
|
pattern(%w( !resourceReport ))
|
|
3510
3656
|
pattern(%w( !taskReport ))
|
|
3511
3657
|
pattern(%w( !textReport ))
|
|
@@ -3524,14 +3670,14 @@ EOT
|
|
|
3524
3670
|
singlePattern('_annualleave')
|
|
3525
3671
|
descr(<<'EOT'
|
|
3526
3672
|
The number of annual leave units within the reported time period. The unit
|
|
3527
|
-
can be adjusted with [[loadunit]].
|
|
3673
|
+
can be adjusted with [[loadunit.report]].
|
|
3528
3674
|
EOT
|
|
3529
3675
|
)
|
|
3530
3676
|
|
|
3531
3677
|
singlePattern('_annualleavebalance')
|
|
3532
3678
|
descr(<<'EOT'
|
|
3533
3679
|
The balance of the annual leave at the end of the reporting interval. The unit
|
|
3534
|
-
can be adjusted with [[loadunit]].
|
|
3680
|
+
can be adjusted with [[loadunit.report]].
|
|
3535
3681
|
EOT
|
|
3536
3682
|
)
|
|
3537
3683
|
|
|
@@ -3880,14 +4026,14 @@ EOT
|
|
|
3880
4026
|
singlePattern('_sickleave')
|
|
3881
4027
|
descr(<<'EOT'
|
|
3882
4028
|
The number of sick leave units within the reported time period. The unit can
|
|
3883
|
-
be adjusted with [[loadunit]].
|
|
4029
|
+
be adjusted with [[loadunit.report]].
|
|
3884
4030
|
EOT
|
|
3885
4031
|
)
|
|
3886
4032
|
|
|
3887
4033
|
singlePattern('_specialleave')
|
|
3888
4034
|
descr(<<'EOT'
|
|
3889
4035
|
The number of special leave units within the reported time period. The unit
|
|
3890
|
-
can be adjusted with [[loadunit]].
|
|
4036
|
+
can be adjusted with [[loadunit.report]].
|
|
3891
4037
|
EOT
|
|
3892
4038
|
)
|
|
3893
4039
|
|
|
@@ -3921,7 +4067,7 @@ EOT
|
|
|
3921
4067
|
singlePattern('_unpaidleave')
|
|
3922
4068
|
descr(<<'EOT'
|
|
3923
4069
|
The number of unpaid leave units within the reported time period. The unit
|
|
3924
|
-
can be adjusted with [[loadunit]].
|
|
4070
|
+
can be adjusted with [[loadunit.report]].
|
|
3925
4071
|
EOT
|
|
3926
4072
|
)
|
|
3927
4073
|
|
|
@@ -4084,13 +4230,7 @@ EOT
|
|
|
4084
4230
|
)
|
|
4085
4231
|
example('textreport')
|
|
4086
4232
|
|
|
4087
|
-
pattern(%w(
|
|
4088
|
-
@property.set('loadUnit', @val[1])
|
|
4089
|
-
})
|
|
4090
|
-
doc('loadunit', <<'EOT'
|
|
4091
|
-
Determines what unit should be used to display all load values in this report.
|
|
4092
|
-
EOT
|
|
4093
|
-
)
|
|
4233
|
+
pattern(%w( !loadunit ))
|
|
4094
4234
|
|
|
4095
4235
|
pattern(%w( !numberFormat ), lambda {
|
|
4096
4236
|
@property.set('numberFormat', @val[0])
|
|
@@ -4308,7 +4448,6 @@ EOT
|
|
|
4308
4448
|
end
|
|
4309
4449
|
|
|
4310
4450
|
def rule_reportProperties
|
|
4311
|
-
pattern(%w( !export ))
|
|
4312
4451
|
pattern(%w( !iCalReport ))
|
|
4313
4452
|
pattern(%w( !nikuReport ))
|
|
4314
4453
|
pattern(%w( !reports ))
|
|
@@ -4393,7 +4532,7 @@ EOT
|
|
|
4393
4532
|
})
|
|
4394
4533
|
|
|
4395
4534
|
pattern(%w( _supplement !resourceId !resourceBody ), lambda {
|
|
4396
|
-
@property = @
|
|
4535
|
+
@property = @idStack.pop
|
|
4397
4536
|
})
|
|
4398
4537
|
doc('supplement.resource', <<'EOT'
|
|
4399
4538
|
The supplement keyword provides a mechanism to add more attributes to already
|
|
@@ -5416,21 +5555,22 @@ EOT
|
|
|
5416
5555
|
|
|
5417
5556
|
def rule_supplement
|
|
5418
5557
|
pattern(%w( !supplementAccount !accountBody ), lambda {
|
|
5419
|
-
@property =
|
|
5558
|
+
@property = @idStack.pop
|
|
5420
5559
|
})
|
|
5421
5560
|
pattern(%w( !supplementReport !reportBody ), lambda {
|
|
5422
|
-
@property =
|
|
5561
|
+
@property = @idStack.pop
|
|
5423
5562
|
})
|
|
5424
5563
|
pattern(%w( !supplementResource !resourceBody ), lambda {
|
|
5425
|
-
@property =
|
|
5564
|
+
@property = @idStack.pop
|
|
5426
5565
|
})
|
|
5427
5566
|
pattern(%w( !supplementTask !taskBody ), lambda {
|
|
5428
|
-
@property =
|
|
5567
|
+
@property = @idStack.pop
|
|
5429
5568
|
})
|
|
5430
5569
|
end
|
|
5431
5570
|
|
|
5432
5571
|
def rule_supplementAccount
|
|
5433
5572
|
pattern(%w( _account !accountId ), lambda {
|
|
5573
|
+
@idStack.push(@property)
|
|
5434
5574
|
@property = @val[1]
|
|
5435
5575
|
})
|
|
5436
5576
|
arg(1, 'account ID', 'The ID of an already defined account.')
|
|
@@ -5438,6 +5578,7 @@ EOT
|
|
|
5438
5578
|
|
|
5439
5579
|
def rule_supplementReport
|
|
5440
5580
|
pattern(%w( _report !reportId ), lambda {
|
|
5581
|
+
@idStack.push(@property)
|
|
5441
5582
|
@property = @val[1]
|
|
5442
5583
|
})
|
|
5443
5584
|
arg(1, 'report ID', 'The absolute ID of an already defined report.')
|
|
@@ -5445,6 +5586,7 @@ EOT
|
|
|
5445
5586
|
|
|
5446
5587
|
def rule_supplementResource
|
|
5447
5588
|
pattern(%w( _resource !resourceId ), lambda {
|
|
5589
|
+
@idStack.push(@property)
|
|
5448
5590
|
@property = @val[1]
|
|
5449
5591
|
})
|
|
5450
5592
|
arg(1, 'resource ID', 'The ID of an already defined resource.')
|
|
@@ -5452,6 +5594,7 @@ EOT
|
|
|
5452
5594
|
|
|
5453
5595
|
def rule_supplementTask
|
|
5454
5596
|
pattern(%w( _task !taskId ), lambda {
|
|
5597
|
+
@idStack.push(@property)
|
|
5455
5598
|
@property = @val[1]
|
|
5456
5599
|
})
|
|
5457
5600
|
arg(1, 'task ID', 'The absolute ID of an already defined task.')
|
|
@@ -5533,13 +5676,16 @@ EOT
|
|
|
5533
5676
|
})
|
|
5534
5677
|
level(:experimental)
|
|
5535
5678
|
doc('adopt.task', <<'EOT'
|
|
5536
|
-
Add a previously defined task
|
|
5537
|
-
to create virtual
|
|
5538
|
-
|
|
5539
|
-
parents. However, the adopting task is scheduled to fit all adopted
|
|
5540
|
-
|
|
5679
|
+
Add a previously defined task and its sub-tasks to this task. This can be used
|
|
5680
|
+
to create virtual projects that contain task (sub-)trees that are originally
|
|
5681
|
+
defined in another task context. Adopted tasks don't inherit anything from
|
|
5682
|
+
their step parents. However, the adopting task is scheduled to fit all adopted
|
|
5683
|
+
sub-tasks.
|
|
5541
5684
|
|
|
5542
|
-
A top-level tasks must never
|
|
5685
|
+
A top-level task and all its sub-tasks must never contain the same task more
|
|
5686
|
+
than once. All reports must use appropriate filters by setting [[taskroot]],
|
|
5687
|
+
[[hidetask]] or [[rolluptask]] to ensure that no tasks are contained more than
|
|
5688
|
+
once in the report.
|
|
5543
5689
|
EOT
|
|
5544
5690
|
)
|
|
5545
5691
|
|
|
@@ -5557,7 +5703,7 @@ EOT
|
|
|
5557
5703
|
pattern(%w( !purge ))
|
|
5558
5704
|
|
|
5559
5705
|
pattern(%w( _supplement !supplementTask !taskBody ), lambda {
|
|
5560
|
-
@property = @
|
|
5706
|
+
@property = @idStack.pop
|
|
5561
5707
|
})
|
|
5562
5708
|
doc('supplement.task', <<'EOT'
|
|
5563
5709
|
The supplement keyword provides a mechanism to add more attributes to already
|
|
@@ -6245,8 +6391,10 @@ EOT
|
|
|
6245
6391
|
@property['scheduled', @scenarioIdx] = true
|
|
6246
6392
|
})
|
|
6247
6393
|
doc('scheduled', <<'EOT'
|
|
6248
|
-
This is mostly for internal use. It specifies that the task
|
|
6249
|
-
scheduling in the scenario.
|
|
6394
|
+
This is mostly for internal use. It specifies that the task should be ignored
|
|
6395
|
+
for scheduling in the scenario. This option only makes sense if you provide
|
|
6396
|
+
all resource [[booking.resource|bookings]] manually. Without booking
|
|
6397
|
+
statements, the task will be reported with 0 effort and no resources assigned.
|
|
6250
6398
|
EOT
|
|
6251
6399
|
)
|
|
6252
6400
|
|