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
@@ -36,7 +36,7 @@ class TaskJuggler
|
|
36
36
|
@variables = [ :LINEBREAK, :SPACE, :WORD,
|
37
37
|
:BOLD, :ITALIC, :CODE, :BOLDITALIC, :PRE,
|
38
38
|
:HREF, :HREFEND, :REF, :REFEND, :HLINE,
|
39
|
-
:FCOLSTART, :FCOLEND,
|
39
|
+
:HTMLBLOB, :FCOLSTART, :FCOLEND,
|
40
40
|
:QUERY,
|
41
41
|
:INLINEFUNCSTART, :INLINEFUNCEND,
|
42
42
|
:BLOCKFUNCSTART, :BLOCKFUNCEND, :ID, :STRING,
|
@@ -31,20 +31,14 @@ class TaskJuggler
|
|
31
31
|
|
32
32
|
# Not supported for this function
|
33
33
|
def to_s(args)
|
34
|
-
|
34
|
+
report = checkArgs(args)
|
35
|
+
|
36
|
+
report.name
|
35
37
|
end
|
36
38
|
|
37
39
|
# Return a HTML tree for the report.
|
38
40
|
def to_html(args)
|
39
|
-
|
40
|
-
error('rtp_report_id',
|
41
|
-
"Argument 'id' missing to specify the report to be used.")
|
42
|
-
return nil
|
43
|
-
end
|
44
|
-
unless (report = @project.report(id))
|
45
|
-
error('rtp_report_unknown_id', "Unknown report #{id}")
|
46
|
-
return nil
|
47
|
-
end
|
41
|
+
report = checkArgs(args)
|
48
42
|
|
49
43
|
# The URL for interactive reports is different than for static reports.
|
50
44
|
if report.interactive?
|
@@ -71,6 +65,22 @@ class TaskJuggler
|
|
71
65
|
nil
|
72
66
|
end
|
73
67
|
|
68
|
+
private
|
69
|
+
|
70
|
+
def checkArgs(args)
|
71
|
+
if args.nil? || (id = args['id']).nil?
|
72
|
+
error('rtp_report_id',
|
73
|
+
"Argument 'id' missing to specify the report to be used.")
|
74
|
+
return nil
|
75
|
+
end
|
76
|
+
unless (report = @project.report(id))
|
77
|
+
error('rtp_report_unknown_id', "Unknown report #{id}")
|
78
|
+
return nil
|
79
|
+
end
|
80
|
+
|
81
|
+
report
|
82
|
+
end
|
83
|
+
|
74
84
|
end
|
75
85
|
|
76
86
|
end
|
@@ -25,6 +25,7 @@ class TaskJuggler
|
|
25
25
|
# :bol : at the begining of a line.
|
26
26
|
# :inline : in the middle of a line
|
27
27
|
# :nowiki : ignoring all MediaWiki special tokens
|
28
|
+
# :html : read anything until </html>
|
28
29
|
# :ref : inside of a REF [[ .. ]]
|
29
30
|
# :href : inside of an HREF [ .. ]
|
30
31
|
# :func : inside of a block <[ .. ]> or inline <- .. -> function
|
@@ -33,66 +34,71 @@ class TaskJuggler
|
|
33
34
|
def initialize(masterFile, log)
|
34
35
|
tokenPatterns = [
|
35
36
|
# :bol mode rules
|
36
|
-
[ :LINEBREAK,
|
37
|
-
[ nil,
|
37
|
+
[ :LINEBREAK, /\s*\n/, :bol, method('linebreak') ],
|
38
|
+
[ nil, /\s+/, :bol, method('inlineMode') ],
|
38
39
|
|
39
40
|
# :bop mode rules
|
40
|
-
[ :PRE,
|
41
|
-
[ nil,
|
41
|
+
[ :PRE, / [^\n]+\n?/, :bop, method('pre') ],
|
42
|
+
[ nil, /\s*\n/, :bop, method('linebreak') ],
|
42
43
|
|
43
44
|
# :inline mode rules
|
44
|
-
[ :SPACE,
|
45
|
+
[ :SPACE, /[ \t\n]+/, :inline, method('space') ],
|
45
46
|
|
46
47
|
# :bop and :bol mode rules
|
47
|
-
[ :INLINEFUNCSTART,
|
48
|
+
[ :INLINEFUNCSTART, /<-/, [ :bop, :bol, :inline ],
|
48
49
|
method('functionStart') ],
|
49
|
-
[ :BLOCKFUNCSTART,
|
50
|
-
[ ':TITLE*',
|
51
|
-
[ 'TITLE*END',
|
52
|
-
[ 'BULLET*',
|
53
|
-
[ 'NUMBER*',
|
54
|
-
[ :HLINE,
|
50
|
+
[ :BLOCKFUNCSTART, /<\[/, [ :bop, :bol ], method('functionStart') ],
|
51
|
+
[ ':TITLE*', /={2,5}/, [ :bop, :bol ], method('titleStart') ],
|
52
|
+
[ 'TITLE*END', /={2,5}/, :inline, method('titleEnd') ],
|
53
|
+
[ 'BULLET*', /\*{1,4}[ \t]+/, [ :bop, :bol ], method('bullet') ],
|
54
|
+
[ 'NUMBER*', /\#{1,4}[ \t]+/, [ :bop, :bol ], method('number') ],
|
55
|
+
[ :HLINE, /----/, [ :bop, :bol ], method('inlineMode') ],
|
55
56
|
|
56
57
|
# :bop, :bol and :inline mode rules
|
57
58
|
# The <nowiki> token puts the scanner into :nowiki mode.
|
58
|
-
[ nil,
|
59
|
-
[
|
59
|
+
[ nil, /<nowiki>/, [ :bop, :bol, :inline ], method('nowikiStart') ],
|
60
|
+
[ nil, /<html>/, [ :bop, :bol, :inline ], method('htmlStart') ],
|
61
|
+
[ :FCOLSTART, /<fcol:([a-z]+|#[0-9A-Fa-f]{3,6})>/, [ :bop, :bol,
|
60
62
|
:inline ],
|
61
63
|
method('fontColorStart') ],
|
62
|
-
[ :FCOLEND,
|
64
|
+
[ :FCOLEND, /<\/fcol>/, [ :bop, :bol, :inline ],
|
63
65
|
method('fontColorEnd') ],
|
64
|
-
[ :QUOTES,
|
65
|
-
[ :REF,
|
66
|
-
[ :HREF,
|
67
|
-
[ :WORD,
|
66
|
+
[ :QUOTES, /'{2,5}/, [ :bop, :bol, :inline ], method('quotes') ],
|
67
|
+
[ :REF, /\[\[/, [ :bop, :bol, :inline ], method('refStart') ],
|
68
|
+
[ :HREF, /\[/, [ :bop, :bol, :inline], method('hrefStart') ],
|
69
|
+
[ :WORD, /.[^ \n\t\[<']*/, [ :bop, :bol, :inline ],
|
68
70
|
method('inlineMode') ],
|
69
71
|
|
70
72
|
# :nowiki mode rules
|
71
|
-
[ nil,
|
72
|
-
[ :WORD,
|
73
|
-
[ :SPACE,
|
74
|
-
[ :LINEBREAK,
|
73
|
+
[ nil, /<\/nowiki>/, :nowiki, method('nowikiEnd') ],
|
74
|
+
[ :WORD, /(<(?!\/nowiki>)|[^ \t\n<])+/, :nowiki ],
|
75
|
+
[ :SPACE, /[ \t]+/, :nowiki ],
|
76
|
+
[ :LINEBREAK, /\s*\n/, :nowiki ],
|
77
|
+
|
78
|
+
# :html mode rules
|
79
|
+
[ :HTMLBLOB, /(.|\n)*<\/html>/ , :html, method('htmlEnd') ],
|
80
|
+
[ :HTMLBLOB, /.*\n/ , :html ],
|
75
81
|
|
76
82
|
# :ref mode rules
|
77
|
-
[ :REFEND,
|
78
|
-
[ :WORD,
|
79
|
-
[ :QUERY,
|
80
|
-
[ :LITERAL,
|
83
|
+
[ :REFEND, /\]\]/, :ref, method('refEnd') ],
|
84
|
+
[ :WORD, /(<(?!-)|(\](?!\])|[^|<\]]))+/, :ref ],
|
85
|
+
[ :QUERY, /<-\w+->/, :ref, method('query') ],
|
86
|
+
[ :LITERAL, /./, :ref ],
|
81
87
|
|
82
88
|
# :href mode rules
|
83
|
-
[ :HREFEND,
|
84
|
-
[ :WORD,
|
85
|
-
[ :QUERY,
|
86
|
-
[ :SPACE,
|
89
|
+
[ :HREFEND, /\]/, :href, method('hrefEnd') ],
|
90
|
+
[ :WORD, /(<(?!-)|[^ \t\n\]<])+/, :href ],
|
91
|
+
[ :QUERY, /<-\w+->/, :href, method('query') ],
|
92
|
+
[ :SPACE, /[ \t\n]+/, :href ],
|
87
93
|
|
88
94
|
# :func mode rules
|
89
|
-
[ :INLINEFUNCEND,
|
90
|
-
[ :BLOCKFUNCEND,
|
91
|
-
[ :ID,
|
92
|
-
[ :STRING,
|
93
|
-
[ :STRING,
|
94
|
-
[ nil,
|
95
|
-
[ :LITERAL,
|
95
|
+
[ :INLINEFUNCEND, /->/ , :func, method('functionEnd') ],
|
96
|
+
[ :BLOCKFUNCEND, /\]>/, :func, method('functionEnd') ],
|
97
|
+
[ :ID, /[a-zA-Z_]\w*/, :func ],
|
98
|
+
[ :STRING, /"(\\"|[^"])*"/, :func, method('dqString') ],
|
99
|
+
[ :STRING, /'(\\'|[^'])*'/, :func, method('sqString') ],
|
100
|
+
[ nil, /[ \t\n]+/, :func ],
|
101
|
+
[ :LITERAL, /./, :func ]
|
96
102
|
]
|
97
103
|
super(masterFile, log, tokenPatterns, :bop)
|
98
104
|
end
|
@@ -166,6 +172,16 @@ class TaskJuggler
|
|
166
172
|
[ types[match.length], match ]
|
167
173
|
end
|
168
174
|
|
175
|
+
def htmlStart(type, match)
|
176
|
+
self.mode = :html
|
177
|
+
[ type, match ]
|
178
|
+
end
|
179
|
+
|
180
|
+
def htmlEnd(type, match)
|
181
|
+
self.mode = :inline
|
182
|
+
[ type, match[0..-8] ]
|
183
|
+
end
|
184
|
+
|
169
185
|
def nowikiStart(type, match)
|
170
186
|
self.mode = :nowiki
|
171
187
|
[ type, match ]
|
@@ -371,6 +371,11 @@ class TaskJuggler
|
|
371
371
|
def rule_plainText
|
372
372
|
repeatable
|
373
373
|
optional
|
374
|
+
pattern(%w( !htmlBlob !space ), lambda {
|
375
|
+
el = RichTextElement.new(@richTextI, :htmlblob, @val[0].join)
|
376
|
+
el.appendSpace = !@val[1].nil?
|
377
|
+
el
|
378
|
+
})
|
374
379
|
pattern(%w( $WORD !space ), lambda {
|
375
380
|
el = RichTextElement.new(@richTextI, :text, @val[0])
|
376
381
|
el.appendSpace = !@val[1].nil?
|
@@ -387,6 +392,13 @@ class TaskJuggler
|
|
387
392
|
})
|
388
393
|
end
|
389
394
|
|
395
|
+
def rule_htmlBlob
|
396
|
+
repeatable
|
397
|
+
pattern(%w( $HTMLBLOB ), lambda {
|
398
|
+
@val[0]
|
399
|
+
})
|
400
|
+
end
|
401
|
+
|
390
402
|
def rule_space
|
391
403
|
optional
|
392
404
|
repeatable
|
@@ -60,7 +60,7 @@ class TaskJuggler
|
|
60
60
|
|
61
61
|
attr_reader :id, :cellText, :tooltip, :hAlign, :cellColor, :fontColor
|
62
62
|
attr_accessor :title, :start, :end, :scale, :listItem, :listType,
|
63
|
-
:width, :content, :column
|
63
|
+
:width, :content, :column, :timeformat1, :timeformat2
|
64
64
|
|
65
65
|
def initialize(id, title)
|
66
66
|
# The column ID. It must be unique within the report.
|
@@ -99,6 +99,10 @@ class TaskJuggler
|
|
99
99
|
@scale = 'week'
|
100
100
|
# The width of columns.
|
101
101
|
@width = nil
|
102
|
+
# Format of the upper calendar header line
|
103
|
+
@timeformat1 = nil
|
104
|
+
# Format of the lower calendar header line
|
105
|
+
@timeformat2 = nil
|
102
106
|
|
103
107
|
# Reference to the ReportTableColumn object that was created based on this
|
104
108
|
# definition.
|
@@ -218,13 +218,13 @@ class TaskJuggler
|
|
218
218
|
# Check the master file is really a file and not stdin.
|
219
219
|
unless (masterFile = @project.inputFiles.masterFile)
|
220
220
|
error('cannot_freeze_stdin',
|
221
|
-
"The project freeze feature only when the " +
|
221
|
+
"The project freeze feature can only be used when the " +
|
222
222
|
"master file is a real file, not standard input.")
|
223
223
|
end
|
224
224
|
|
225
225
|
# Derive the file names for the header and bookings file from the base
|
226
226
|
# name of the master file.
|
227
|
-
masterFileBase = File.basename(masterFile, '.tjp')
|
227
|
+
masterFileBase = Dir.pwd + '/' + File.basename(masterFile, '.tjp')
|
228
228
|
headerFile = masterFileBase + '-header.tji'
|
229
229
|
bookingsFileBase = masterFileBase + '-bookings'
|
230
230
|
bookingsFile = bookingsFileBase + '.tji'
|
@@ -27,7 +27,8 @@ class TaskJuggler
|
|
27
27
|
# time. So make sure some needed attributes really exist so we don't
|
28
28
|
# have to check for existance each time we access them.
|
29
29
|
%w( allocate assignedresources booking charge chargeset complete
|
30
|
-
criticalness depends duration
|
30
|
+
competitors criticalness depends duration
|
31
|
+
effort end forward gauge length
|
31
32
|
maxend maxstart minend minstart milestone pathcriticalness
|
32
33
|
precedes priority scheduled shifts start status ).each do |attr|
|
33
34
|
@property[attr, @scenarioIdx]
|
@@ -38,6 +39,20 @@ class TaskJuggler
|
|
38
39
|
@dCache = DataCache.instance
|
39
40
|
end
|
40
41
|
|
42
|
+
def markAsScheduled
|
43
|
+
return if @scheduled
|
44
|
+
@scheduled = true
|
45
|
+
if @milestone
|
46
|
+
typename = 'Milestone'
|
47
|
+
elsif @property.leaf?
|
48
|
+
typename = 'Task'
|
49
|
+
else
|
50
|
+
typename = 'Container'
|
51
|
+
end
|
52
|
+
|
53
|
+
Log.msg { "#{typename} #{@property.fullId} has been scheduled." }
|
54
|
+
end
|
55
|
+
|
41
56
|
# Call this function to reset all scheduling related data prior to
|
42
57
|
# scheduling.
|
43
58
|
def prepareScheduling
|
@@ -78,18 +93,17 @@ class TaskJuggler
|
|
78
93
|
@hasDurationSpec = true
|
79
94
|
:durationTask
|
80
95
|
else
|
81
|
-
# If the task is set as milestone
|
96
|
+
# If the task is set as milestone it has a duration spec.
|
82
97
|
@hasDurationSpec = @milestone
|
83
98
|
:startEndTask
|
84
99
|
end
|
85
100
|
|
86
|
-
|
101
|
+
markAsMilestone
|
87
102
|
|
88
103
|
# For start-end-tasks without allocation, we don't have to do
|
89
104
|
# anything but to set the 'scheduled' flag.
|
90
105
|
if @durationType == :startEndTask && @start && @end && @allocate.empty?
|
91
|
-
|
92
|
-
Log.msg { "Task #{@property.fullId}: #{period_to_s}" }
|
106
|
+
markAsScheduled
|
93
107
|
end
|
94
108
|
|
95
109
|
# Collect the limits of this task and all parent tasks into a single
|
@@ -575,6 +589,21 @@ class TaskJuggler
|
|
575
589
|
"to ensure allocations or use a higher 'priority'.")
|
576
590
|
end
|
577
591
|
|
592
|
+
thieves = []
|
593
|
+
@competitors.each do |t|
|
594
|
+
thieves << t if t['priority', @scenarioIdx] < @priority
|
595
|
+
end
|
596
|
+
unless thieves.empty?
|
597
|
+
warning('priority_inversion',
|
598
|
+
"Due to a mix of ALAP and ASAP scheduled tasks or a " +
|
599
|
+
"dependency on a lower priority tasks the following " +
|
600
|
+
"task#{thieves.length > 1 ? 's' : ''} stole resources from " +
|
601
|
+
"#{@property.fullId} despite having a lower priority:")
|
602
|
+
thieves.each do |t|
|
603
|
+
info('priority_inversion_info', "Task #{t.fullId}", t.sourceFileInfo)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
578
607
|
@errors == 0
|
579
608
|
end
|
580
609
|
|
@@ -966,25 +995,27 @@ class TaskJuggler
|
|
966
995
|
# are only set in scheduleContainer().
|
967
996
|
if @property.leaf?
|
968
997
|
instance_variable_set(('@' + thisEnd).intern, date)
|
998
|
+
typename = 'Task'
|
969
999
|
if @durationType == :startEndTask
|
970
1000
|
instance_variable_set(('@' + thisEnd + 'Idx').intern,
|
971
1001
|
@project.dateToIdx(date))
|
1002
|
+
if @milestone
|
1003
|
+
typename = 'Milestone'
|
1004
|
+
end
|
972
1005
|
end
|
973
|
-
Log.msg { "
|
1006
|
+
Log.msg { "Update #{typename} #{@property.fullId}: #{period_to_s}" }
|
974
1007
|
end
|
975
1008
|
|
976
1009
|
if @milestone
|
977
1010
|
# Start and end date of a milestone are identical.
|
978
|
-
|
1011
|
+
markAsScheduled
|
979
1012
|
if a(otherEnd).nil?
|
980
1013
|
propagateDate(a(thisEnd), !atEnd)
|
981
1014
|
end
|
982
|
-
Log.msg { "Milestone #{@property.fullId}: #{period_to_s}" }
|
983
1015
|
elsif !@scheduled && @start && @end &&
|
984
1016
|
!(@length == 0 && @duration == 0 && @effort == 0 &&
|
985
1017
|
!@allocate.empty?)
|
986
|
-
|
987
|
-
Log.msg { "Task #{@property.fullId} has been scheduled" }
|
1018
|
+
markAsScheduled
|
988
1019
|
end
|
989
1020
|
|
990
1021
|
# Propagate date to all dependent tasks. Don't do this for start
|
@@ -1115,8 +1146,8 @@ class TaskJuggler
|
|
1115
1146
|
unless @start && @end
|
1116
1147
|
raise "Start (#{@start}) and end (#{@end}) must be set"
|
1117
1148
|
end
|
1118
|
-
@scheduled = true
|
1119
1149
|
Log.msg { "Container task #{@property.fullId} completed: #{period_to_s}" }
|
1150
|
+
markAsScheduled
|
1120
1151
|
|
1121
1152
|
# If we have modified the start or end date, we need to communicate this
|
1122
1153
|
# new date to surrounding tasks.
|
@@ -1260,6 +1291,11 @@ class TaskJuggler
|
|
1260
1291
|
query.string = "#{count.to_i}"
|
1261
1292
|
end
|
1262
1293
|
|
1294
|
+
def query_competitorcount(query)
|
1295
|
+
query.sortable = query.numerical = @competitors.length
|
1296
|
+
query.string = "#{@competitors.length}"
|
1297
|
+
end
|
1298
|
+
|
1263
1299
|
def query_complete(query)
|
1264
1300
|
# If we haven't calculated the value yet, calculate it first.
|
1265
1301
|
unless @complete
|
@@ -1481,6 +1517,10 @@ class TaskJuggler
|
|
1481
1517
|
end
|
1482
1518
|
end
|
1483
1519
|
|
1520
|
+
def query_scheduling(query)
|
1521
|
+
query.string = @forward ? 'ASAP' : 'ASAP' if @property.leaf?
|
1522
|
+
end
|
1523
|
+
|
1484
1524
|
def query_status(query)
|
1485
1525
|
# If we haven't calculated the completion yet, calculate it first.
|
1486
1526
|
calcStatus if @status.empty?
|
@@ -1751,7 +1791,7 @@ class TaskJuggler
|
|
1751
1791
|
# scheduled once we have reached the other end.
|
1752
1792
|
if (@forward && @currentSlotIdx >= @endIdx) |
|
1753
1793
|
(!@forward && @currentSlotIdx <= @startIdx)
|
1754
|
-
|
1794
|
+
markAsScheduled
|
1755
1795
|
@property.parents.each do |parent|
|
1756
1796
|
parent.scheduleContainer(@scenarioIdx)
|
1757
1797
|
end
|
@@ -1821,16 +1861,35 @@ class TaskJuggler
|
|
1821
1861
|
|
1822
1862
|
# In case we have a persistent allocation we need to check if there
|
1823
1863
|
# is already a locked resource and use it.
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1864
|
+
locked_candidate = allocation.lockedResource
|
1865
|
+
if locked_candidate
|
1866
|
+
next if bookResource(locked_candidate)
|
1867
|
+
|
1868
|
+
if allocation.atomic &&
|
1869
|
+
locked_candidate.bookedTask(@scenarioIdx, @currentSlotIdx)
|
1870
|
+
rollbackBookings
|
1871
|
+
return
|
1872
|
+
end
|
1873
|
+
|
1874
|
+
if @forward
|
1875
|
+
next if @currentSlotIdx < locked_candidate.getMaxSlot(@scenarioIdx)
|
1876
|
+
else
|
1877
|
+
next if @currentSlotIdx > locked_candidate.getMinSlot(@scenarioIdx)
|
1878
|
+
end
|
1879
|
+
# Persistent candidate is gone for the rest of the project!
|
1880
|
+
# Warn and assign somebody else, if available!
|
1881
|
+
warning('broken_persistence',
|
1882
|
+
"Persistence broken for Task #{@property.fullId} " +
|
1883
|
+
"- resource #{locked_candidate.name} is gone")
|
1884
|
+
allocation.lockedResource = nil
|
1885
|
+
end
|
1886
|
+
|
1887
|
+
# Create a list of candidates in the proper order and
|
1888
|
+
# assign the first one available.
|
1889
|
+
allocation.candidates(@scenarioIdx).each do |candidate|
|
1890
|
+
if bookResource(candidate)
|
1891
|
+
allocation.lockedResource = candidate if allocation.persistent
|
1892
|
+
break
|
1834
1893
|
end
|
1835
1894
|
end
|
1836
1895
|
end
|
@@ -1846,6 +1905,10 @@ class TaskJuggler
|
|
1846
1905
|
@doneEffort >= @effort) || !limitsOk?(@currentSlotIdx, r)
|
1847
1906
|
|
1848
1907
|
if r.book(@scenarioIdx, @currentSlotIdx, @property)
|
1908
|
+
# This method is _very_ performance sensitive. Uncomment this log
|
1909
|
+
# message only if you really need it.
|
1910
|
+
#Log.msg { "Book #{resource.name} on task #{@property.fullId}" }
|
1911
|
+
|
1849
1912
|
# For effort based task we adjust the the start end (as defined by
|
1850
1913
|
# the scheduling direction) to align with the first booked time
|
1851
1914
|
# slot.
|
@@ -1878,6 +1941,11 @@ class TaskJuggler
|
|
1878
1941
|
@assignedresources << r
|
1879
1942
|
end
|
1880
1943
|
booked = true
|
1944
|
+
elsif (competitor = r.bookedTask(@scenarioIdx, @currentSlotIdx))
|
1945
|
+
# Keep a list of all the Tasks that have successfully competed for
|
1946
|
+
# the same resources and are potentially delaying the progress of
|
1947
|
+
# this Task.
|
1948
|
+
@competitors << competitor unless @competitors.include?(competitor)
|
1881
1949
|
end
|
1882
1950
|
end
|
1883
1951
|
|
@@ -1966,7 +2034,7 @@ class TaskJuggler
|
|
1966
2034
|
if @effort > 0
|
1967
2035
|
if @doneEffort >= @effort
|
1968
2036
|
@end = tentativeEnd
|
1969
|
-
|
2037
|
+
markAsScheduled
|
1970
2038
|
end
|
1971
2039
|
elsif @length > 0
|
1972
2040
|
@doneLength = 0
|
@@ -1980,7 +2048,7 @@ class TaskJuggler
|
|
1980
2048
|
if @doneLength >= @length && date >= tentativeEnd
|
1981
2049
|
endDate = @project.idxToDate(idx + 1)
|
1982
2050
|
@end = [ endDate, tentativeEnd ].max
|
1983
|
-
|
2051
|
+
markAsScheduled
|
1984
2052
|
break
|
1985
2053
|
end
|
1986
2054
|
end
|
@@ -1988,13 +2056,13 @@ class TaskJuggler
|
|
1988
2056
|
@doneDuration = ((tentativeEnd - @start) / slotDuration).to_i
|
1989
2057
|
if @doneDuration >= @duration
|
1990
2058
|
@end = tentativeEnd
|
1991
|
-
|
2059
|
+
markAsScheduled
|
1992
2060
|
elsif @duration * slotDuration < (@project['now'] - @start)
|
1993
2061
|
# This handles the case where the bookings don't provide enough
|
1994
2062
|
# @doneDuration to reach @duration, but the now date would be
|
1995
2063
|
# after the @start + @duration date.
|
1996
2064
|
@end = @start + @duration * slotDuration
|
1997
|
-
|
2065
|
+
markAsScheduled
|
1998
2066
|
end
|
1999
2067
|
end
|
2000
2068
|
end
|
@@ -2041,6 +2109,19 @@ class TaskJuggler
|
|
2041
2109
|
end
|
2042
2110
|
end
|
2043
2111
|
|
2112
|
+
def rollbackBookings
|
2113
|
+
@doneEffort = 0.0
|
2114
|
+
|
2115
|
+
@allocate.each do |allocation|
|
2116
|
+
allocation.lockedResource = nil
|
2117
|
+
allocation.candidates(@scenarioIdx).each do |resource|
|
2118
|
+
resource.allLeaves.each do |r|
|
2119
|
+
r.rollbackBookings(@scenarioIdx, @property)
|
2120
|
+
end
|
2121
|
+
end
|
2122
|
+
end
|
2123
|
+
end
|
2124
|
+
|
2044
2125
|
# This function checks if the task has a dependency on another task or
|
2045
2126
|
# fixed date for a certain end. If +atEnd+ is true, the task end will be
|
2046
2127
|
# checked. Otherwise the start.
|
@@ -2096,7 +2177,7 @@ class TaskJuggler
|
|
2096
2177
|
|
2097
2178
|
# This function determines if a task is a milestones and marks it
|
2098
2179
|
# accordingly.
|
2099
|
-
def
|
2180
|
+
def markAsMilestone
|
2100
2181
|
return if @property.container? || @hasDurationSpec ||
|
2101
2182
|
!@booking.empty? || !@allocate.empty?
|
2102
2183
|
|
@@ -2123,6 +2204,7 @@ class TaskJuggler
|
|
2123
2204
|
@hasDurationSpec = true
|
2124
2205
|
@end = @start if @start && !@end
|
2125
2206
|
@start = @end if !@start && @end
|
2207
|
+
Log.msg { "Mark as milestone #{@property.fullId}" }
|
2126
2208
|
end
|
2127
2209
|
end
|
2128
2210
|
|
@@ -2390,10 +2472,11 @@ class TaskJuggler
|
|
2390
2472
|
|
2391
2473
|
# Recursively compile a list of Task properties which depend on the
|
2392
2474
|
# current task.
|
2393
|
-
def inputs(foundInputs, includeChildren, checkedTasks =
|
2475
|
+
def inputs(foundInputs, includeChildren, checkedTasks = {})
|
2394
2476
|
# Ignore tasks that we have already included in the checked tasks list.
|
2395
|
-
|
2396
|
-
|
2477
|
+
taskSignature = [ @property, includeChildren ]
|
2478
|
+
return if checkedTasks.include?(taskSignature)
|
2479
|
+
checkedTasks[taskSignature] = true
|
2397
2480
|
|
2398
2481
|
# An "input" must be a leaf task that has no direct or indirect (through
|
2399
2482
|
# parent) following tasks. Only milestones are recognized as inputs.
|
@@ -2424,10 +2507,11 @@ class TaskJuggler
|
|
2424
2507
|
|
2425
2508
|
# Recursively compile a list of Task properties which depend on the
|
2426
2509
|
# current task.
|
2427
|
-
def targets(foundTargets, includeChildren, checkedTasks =
|
2510
|
+
def targets(foundTargets, includeChildren, checkedTasks = {})
|
2428
2511
|
# Ignore tasks that we have already included in the checked tasks list.
|
2429
|
-
|
2430
|
-
|
2512
|
+
taskSignature = [ @property, includeChildren ]
|
2513
|
+
return if checkedTasks.include?(taskSignature)
|
2514
|
+
checkedTasks[taskSignature] = true
|
2431
2515
|
|
2432
2516
|
# A target must be a leaf function that has no direct or indirect
|
2433
2517
|
# (through parent) following tasks. Only milestones are recognized as
|