taskjuggler 3.1.0 → 3.2.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 +44 -0
- data/bin/tj3webd +4 -0
- data/data/css/tjreport.css +14 -5
- data/data/tjp.vim +22 -7
- data/examples/Fedora-20/reports.tji +2 -4
- data/examples/Scrum/Product Burndown.csv +26 -0
- data/examples/Scrum/Sprint 1 Burndown.csv +26 -0
- data/examples/Scrum/Sprint 2 Burndown.csv +26 -0
- data/examples/Scrum/Sprint 3 Burndown.csv +26 -0
- data/examples/Scrum/scrum.tjp +141 -0
- data/examples/Tutorial/tutorial.tjp +13 -7
- data/lib/taskjuggler/Attributes.rb +2 -3
- data/lib/taskjuggler/HTMLDocument.rb +25 -18
- data/lib/taskjuggler/Journal.rb +85 -65
- data/lib/taskjuggler/KeywordDocumentation.rb +25 -13
- data/lib/taskjuggler/LeaveList.rb +1 -1
- data/lib/taskjuggler/Limits.rb +3 -5
- data/lib/taskjuggler/MessageHandler.rb +173 -19
- data/lib/taskjuggler/Painter.rb +75 -0
- data/lib/taskjuggler/Painter/BasicShapes.rb +76 -0
- data/lib/taskjuggler/Painter/Color.rb +273 -0
- data/lib/taskjuggler/Painter/Element.rb +56 -0
- data/lib/taskjuggler/Painter/FontData.rb +221 -0
- data/lib/taskjuggler/Painter/FontMetrics.rb +125 -0
- data/lib/taskjuggler/Painter/FontMetricsData.rb +151 -0
- data/lib/taskjuggler/Painter/Group.rb +77 -0
- data/lib/taskjuggler/Painter/Points.rb +47 -0
- data/lib/taskjuggler/Painter/Primitives.rb +100 -0
- data/lib/taskjuggler/Painter/SVGSupport.rb +36 -0
- data/lib/taskjuggler/Painter/Text.rb +36 -0
- data/lib/taskjuggler/Project.rb +46 -29
- data/lib/taskjuggler/ProjectFileParser.rb +24 -22
- data/lib/taskjuggler/ProjectFileScanner.rb +2 -2
- data/lib/taskjuggler/PropertyTreeNode.rb +26 -34
- data/lib/taskjuggler/Query.rb +8 -5
- data/lib/taskjuggler/RealFormat.rb +3 -0
- data/lib/taskjuggler/Resource.rb +3 -5
- data/lib/taskjuggler/ResourceScenario.rb +19 -7
- data/lib/taskjuggler/RichText.rb +4 -6
- data/lib/taskjuggler/RichText/FunctionExample.rb +1 -1
- data/lib/taskjuggler/RichText/FunctionHandler.rb +5 -6
- data/lib/taskjuggler/RichText/Parser.rb +4 -6
- data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
- data/lib/taskjuggler/RichText/RTFQuery.rb +2 -3
- data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
- data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -2
- data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
- data/lib/taskjuggler/RichText/Scanner.rb +6 -6
- data/lib/taskjuggler/RichText/Snip.rb +1 -2
- data/lib/taskjuggler/RuntimeConfig.rb +9 -6
- data/lib/taskjuggler/ScenarioData.rb +4 -3
- data/lib/taskjuggler/Scoreboard.rb +6 -0
- data/lib/taskjuggler/SheetHandlerBase.rb +25 -8
- data/lib/taskjuggler/SimpleQueryExpander.rb +14 -5
- data/lib/taskjuggler/SyntaxReference.rb +1 -2
- data/lib/taskjuggler/TableColumnSorter.rb +84 -0
- data/lib/taskjuggler/Task.rb +3 -5
- data/lib/taskjuggler/TaskJuggler.rb +36 -29
- data/lib/taskjuggler/TaskScenario.rb +154 -66
- data/lib/taskjuggler/TextParser.rb +24 -17
- data/lib/taskjuggler/TextParser/Scanner.rb +16 -11
- data/lib/taskjuggler/TextParser/SourceFileInfo.rb +20 -15
- data/lib/taskjuggler/TimeSheets.rb +6 -12
- data/lib/taskjuggler/Tj3AppBase.rb +35 -16
- data/lib/taskjuggler/Tj3Config.rb +1 -1
- data/lib/taskjuggler/TjpSyntaxRules.rb +239 -49
- data/lib/taskjuggler/XMLElement.rb +9 -2
- data/lib/taskjuggler/apps/Tj3.rb +43 -37
- data/lib/taskjuggler/apps/Tj3Client.rb +62 -112
- data/lib/taskjuggler/apps/Tj3Daemon.rb +66 -29
- data/lib/taskjuggler/apps/Tj3Man.rb +5 -5
- data/lib/taskjuggler/apps/Tj3SsReceiver.rb +10 -13
- data/lib/taskjuggler/apps/Tj3SsSender.rb +13 -16
- data/lib/taskjuggler/apps/Tj3TsReceiver.rb +10 -13
- data/lib/taskjuggler/apps/Tj3TsSender.rb +12 -15
- data/lib/taskjuggler/apps/Tj3TsSummary.rb +12 -15
- data/lib/taskjuggler/apps/Tj3WebD.rb +99 -0
- data/lib/taskjuggler/daemon/Daemon.rb +50 -10
- data/lib/taskjuggler/daemon/DaemonConnector.rb +127 -0
- data/lib/taskjuggler/daemon/ProcessIntercom.rb +36 -21
- data/lib/taskjuggler/daemon/ProjectBroker.rb +122 -112
- data/lib/taskjuggler/daemon/ProjectServer.rb +78 -46
- data/lib/taskjuggler/daemon/ReportServer.rb +52 -28
- data/lib/taskjuggler/daemon/ReportServlet.rb +92 -21
- data/lib/taskjuggler/daemon/WebServer.rb +75 -22
- data/lib/taskjuggler/daemon/WelcomePage.rb +1 -0
- data/lib/taskjuggler/reports/AccountListRE.rb +3 -3
- data/lib/taskjuggler/reports/CSVFile.rb +9 -2
- data/lib/taskjuggler/reports/ChartPlotter.rb +453 -0
- data/lib/taskjuggler/reports/Navigator.rb +1 -0
- data/lib/taskjuggler/reports/NikuReport.rb +4 -4
- data/lib/taskjuggler/reports/Report.rb +6 -18
- data/lib/taskjuggler/reports/ReportBase.rb +9 -9
- data/lib/taskjuggler/reports/ReportContext.rb +2 -2
- data/lib/taskjuggler/reports/StatusSheetReport.rb +6 -6
- data/lib/taskjuggler/reports/TableReport.rb +24 -15
- data/lib/taskjuggler/reports/TimeSheetReport.rb +5 -5
- data/lib/taskjuggler/reports/TraceReport.rb +251 -0
- data/lib/tj3webd.rb +17 -0
- data/manual/Day_To_Day_Juggling +10 -3
- data/manual/Installation +38 -19
- data/manual/Software +25 -19
- data/manual/Tutorial +119 -110
- data/manual/html/Day_To_Day_Juggling.html +7 -5
- data/manual/html/Getting_Started.html +4 -4
- data/manual/html/How_To_Contribute.html +4 -4
- data/manual/html/Installation.html +19 -11
- data/manual/html/Intro.html +4 -4
- data/manual/html/Reporting_Bugs.html +4 -4
- data/manual/html/Rich_Text_Attributes.html +4 -4
- data/manual/html/Software.html +15 -11
- data/manual/html/TaskJuggler_2x_Migration.html +4 -4
- data/manual/html/TaskJuggler_Internals.html +4 -4
- data/manual/html/The_TaskJuggler_Syntax.html +4 -4
- data/manual/html/Tutorial.html +41 -32
- data/manual/html/account.html +4 -4
- data/manual/html/account.task.html +4 -4
- data/manual/html/accountprefix.html +4 -4
- data/manual/html/accountreport.html +27 -9
- data/manual/html/accountroot.html +5 -5
- data/manual/html/active.html +4 -4
- data/manual/html/adopt.task.html +4 -4
- data/manual/html/aggregate.html +4 -4
- data/manual/html/alert.html +4 -4
- data/manual/html/alertlevels.html +4 -4
- data/manual/html/allocate.html +5 -5
- data/manual/html/alphabet.html +4 -4
- data/manual/html/alternative.html +4 -4
- data/manual/html/author.html +4 -4
- data/manual/html/balance.html +5 -5
- data/manual/html/booking.resource.html +4 -4
- data/manual/html/booking.task.html +4 -4
- data/manual/html/caption.html +5 -5
- data/manual/html/cellcolor.column.html +43 -8
- data/manual/html/celltext.column.html +4 -4
- data/manual/html/center.html +5 -5
- data/manual/html/charge.html +4 -4
- data/manual/html/chargeset.html +4 -4
- data/manual/html/columnid.html +27 -15
- data/manual/html/columns.html +5 -5
- data/manual/html/complete.html +4 -4
- data/manual/html/copyright.html +4 -4
- data/manual/html/credits.html +4 -4
- data/manual/html/css/tjreport.css +14 -5
- data/manual/html/currency.html +4 -4
- data/manual/html/currencyformat.html +5 -5
- data/manual/html/dailymax.html +5 -5
- data/manual/html/dailymin.html +5 -5
- data/manual/html/dailyworkinghours.html +4 -4
- data/manual/html/date.extend.html +4 -4
- data/manual/html/date.html +5 -5
- data/manual/html/definitions.html +4 -4
- data/manual/html/depends.html +4 -4
- data/manual/html/details.html +4 -4
- data/manual/html/disabled.html +4 -4
- data/manual/html/duration.html +4 -4
- data/manual/html/efficiency.html +4 -4
- data/manual/html/effort.html +4 -4
- data/manual/html/email.html +4 -4
- data/manual/html/enabled.html +4 -4
- data/manual/html/end.column.html +4 -4
- data/manual/html/end.html +4 -4
- data/manual/html/end.limit.html +4 -4
- data/manual/html/end.report.html +5 -5
- data/manual/html/end.timesheet.html +4 -4
- data/manual/html/endcredit.html +4 -4
- data/manual/html/epilog.html +5 -5
- data/manual/html/export.html +4 -4
- data/manual/html/extend.html +4 -4
- data/manual/html/fail.html +43 -8
- data/manual/html/fdl.html +4 -4
- data/manual/html/flags.account.html +4 -4
- data/manual/html/flags.html +4 -4
- data/manual/html/flags.journalentry.html +4 -4
- data/manual/html/flags.report.html +5 -5
- data/manual/html/flags.resource.html +4 -4
- data/manual/html/flags.statussheet.html +4 -4
- data/manual/html/flags.task.html +4 -4
- data/manual/html/flags.timesheet.html +4 -4
- data/manual/html/fontcolor.column.html +43 -8
- data/manual/html/footer.html +5 -5
- data/manual/html/formats.html +5 -5
- data/manual/html/functions.html +4 -4
- data/manual/html/gapduration.html +4 -4
- data/manual/html/gaplength.html +4 -4
- data/manual/html/halign.center.html +4 -4
- data/manual/html/halign.column.html +43 -8
- data/manual/html/halign.left.html +4 -4
- data/manual/html/halign.right.html +4 -4
- data/manual/html/hasalert.html +4 -4
- data/manual/html/header.html +5 -5
- data/manual/html/headline.html +7 -7
- data/manual/html/height.html +72 -0
- data/manual/html/hideaccount.html +46 -11
- data/manual/html/hidejournalentry.html +5 -5
- data/manual/html/hidereport.html +43 -8
- data/manual/html/hideresource.html +44 -9
- data/manual/html/hidetask.html +44 -9
- data/manual/html/icalreport.html +4 -4
- data/manual/html/include.macro.html +4 -4
- data/manual/html/include.project.html +4 -4
- data/manual/html/include.properties.html +4 -4
- data/manual/html/index.html +2 -1
- data/manual/html/inherit.extend.html +4 -4
- data/manual/html/interval1.html +4 -4
- data/manual/html/interval2.html +4 -4
- data/manual/html/interval3.html +4 -4
- data/manual/html/interval4.html +4 -4
- data/manual/html/isactive.html +4 -4
- data/manual/html/ischildof.html +4 -4
- data/manual/html/isdependencyof.html +4 -4
- data/manual/html/isdutyof.html +4 -4
- data/manual/html/isfeatureof.html +4 -4
- data/manual/html/isleaf.html +4 -4
- data/manual/html/ismilestone.html +4 -4
- data/manual/html/isongoing.html +4 -4
- data/manual/html/isresource.html +4 -4
- data/manual/html/isresponsibilityof.html +4 -4
- data/manual/html/istask.html +4 -4
- data/manual/html/journalattributes.html +11 -7
- data/manual/html/journalentry.html +4 -4
- data/manual/html/journalmode.html +5 -5
- data/manual/html/leaveallowance.html +5 -5
- data/manual/html/leaves.html +5 -6
- data/manual/html/left.html +5 -5
- data/manual/html/length.html +4 -4
- data/manual/html/limits.allocate.html +4 -4
- data/manual/html/limits.html +4 -4
- data/manual/html/limits.resource.html +4 -4
- data/manual/html/limits.task.html +4 -4
- data/manual/html/listitem.column.html +4 -4
- data/manual/html/listtype.column.html +4 -4
- data/manual/html/loadunit.html +5 -5
- data/manual/html/logicalexpression.html +8 -44
- data/manual/html/logicalflagexpression.html +4 -4
- data/manual/html/macro.html +4 -4
- data/manual/html/managers.html +4 -4
- data/manual/html/mandatory.html +4 -4
- data/manual/html/maxend.html +4 -4
- data/manual/html/maximum.html +5 -5
- data/manual/html/maxstart.html +4 -4
- data/manual/html/milestone.html +4 -4
- data/manual/html/minend.html +4 -4
- data/manual/html/minimum.html +5 -5
- data/manual/html/minstart.html +4 -4
- data/manual/html/monthlymax.html +5 -5
- data/manual/html/monthlymin.html +5 -5
- data/manual/html/navbar.html +10 -4
- data/manual/html/navigator.html +4 -4
- data/manual/html/newtask.html +4 -4
- data/manual/html/nikureport.html +4 -4
- data/manual/html/note.task.html +4 -4
- data/manual/html/now.html +4 -4
- data/manual/html/numberformat.html +5 -5
- data/manual/html/onend.html +4 -4
- data/manual/html/onstart.html +4 -4
- data/manual/html/opennodes.html +5 -5
- data/manual/html/overtime.booking.html +4 -4
- data/manual/html/period.column.html +4 -4
- data/manual/html/period.limit.html +4 -4
- data/manual/html/period.report.html +5 -5
- data/manual/html/period.task.html +4 -4
- data/manual/html/persistent.html +4 -4
- data/manual/html/precedes.html +4 -4
- data/manual/html/priority.html +4 -4
- data/manual/html/priority.timesheet.html +4 -4
- data/manual/html/project.html +4 -4
- data/manual/html/projectid.html +4 -4
- data/manual/html/projectid.task.html +4 -4
- data/manual/html/projectids.html +4 -4
- data/manual/html/projection.html +5 -7
- data/manual/html/prolog.html +5 -5
- data/manual/html/properties.html +11 -5
- data/manual/html/purge.html +5 -5
- data/manual/html/rate.html +4 -4
- data/manual/html/rate.resource.html +4 -4
- data/manual/html/reference.extend.html +4 -4
- data/manual/html/remaining.html +4 -4
- data/manual/html/replace.html +4 -4
- data/manual/html/reportprefix.html +4 -4
- data/manual/html/resource.html +4 -10
- data/manual/html/resourceattributes.html +4 -4
- data/manual/html/resourceprefix.html +4 -4
- data/manual/html/resourcereport.html +28 -10
- data/manual/html/resourceroot.html +5 -5
- data/manual/html/resources.limit.html +4 -4
- data/manual/html/responsible.html +4 -4
- data/manual/html/richtext.extend.html +4 -4
- data/manual/html/right.html +5 -5
- data/manual/html/rollupaccount.html +44 -9
- data/manual/html/rollupresource.html +44 -9
- data/manual/html/rolluptask.html +44 -9
- data/manual/html/scale.column.html +4 -4
- data/manual/html/scenario.html +4 -22
- data/manual/html/scenario.ical.html +4 -4
- data/manual/html/scenarios.export.html +4 -4
- data/manual/html/scenarios.html +5 -5
- data/manual/html/scenariospecific.extend.html +4 -4
- data/manual/html/scheduled.html +4 -4
- data/manual/html/scheduling.html +4 -4
- data/manual/html/select.html +4 -4
- data/manual/html/selfcontained.html +5 -5
- data/manual/html/shift.allocate.html +4 -4
- data/manual/html/shift.html +4 -4
- data/manual/html/shift.resource.html +5 -5
- data/manual/html/shift.task.html +4 -4
- data/manual/html/shift.timesheet.html +4 -4
- data/manual/html/shifts.allocate.html +4 -4
- data/manual/html/shifts.resource.html +4 -4
- data/manual/html/shifts.task.html +4 -4
- data/manual/html/shorttimeformat.html +4 -4
- data/manual/html/sloppy.booking.html +4 -4
- data/manual/html/sloppy.projection.html +5 -5
- data/manual/html/sortaccounts.html +5 -5
- data/manual/html/sortjournalentries.html +5 -5
- data/manual/html/sortresources.html +5 -5
- data/manual/html/sorttasks.html +5 -5
- data/manual/html/start.column.html +4 -4
- data/manual/html/start.html +4 -4
- data/manual/html/start.limit.html +4 -4
- data/manual/html/start.report.html +5 -5
- data/manual/html/startcredit.html +4 -4
- data/manual/html/status.statussheet.html +4 -4
- data/manual/html/status.timesheet.html +4 -4
- data/manual/html/statussheet.html +4 -4
- data/manual/html/statussheetreport.html +4 -4
- data/manual/html/strict.projection.html +5 -5
- data/manual/html/summary.html +4 -4
- data/manual/html/supplement.html +4 -4
- data/manual/html/supplement.resource.html +4 -10
- data/manual/html/supplement.task.html +4 -28
- data/manual/html/tagfile.html +4 -4
- data/manual/html/task.html +4 -28
- data/manual/html/task.statussheet.html +4 -4
- data/manual/html/task.timesheet.html +4 -4
- data/manual/html/taskattributes.html +4 -4
- data/manual/html/taskprefix.html +4 -4
- data/manual/html/taskreport.html +28 -10
- data/manual/html/taskroot.html +5 -5
- data/manual/html/text.extend.html +4 -4
- data/manual/html/textreport.html +27 -9
- data/manual/html/timeformat.html +5 -5
- data/manual/html/timeoff.nikureport.html +4 -4
- data/manual/html/timesheet.html +4 -4
- data/manual/html/timesheetreport.html +23 -5
- data/manual/html/timezone.export.html +4 -4
- data/manual/html/timezone.html +4 -4
- data/manual/html/timezone.report.html +5 -5
- data/manual/html/timezone.shift.html +4 -4
- data/manual/html/timingresolution.html +4 -4
- data/manual/html/title.column.html +4 -4
- data/manual/html/title.html +5 -5
- data/manual/html/toc.html +207 -179
- data/manual/html/tooltip.column.html +45 -10
- data/manual/html/tracereport.html +405 -0
- data/manual/html/trackingscenario.html +6 -6
- data/manual/html/treelevel.html +4 -4
- data/manual/html/vacation.html +4 -4
- data/manual/html/vacation.resource.html +4 -4
- data/manual/html/vacation.shift.html +4 -4
- data/manual/html/warn.html +43 -8
- data/manual/html/weeklymax.html +5 -5
- data/manual/html/weeklymin.html +5 -5
- data/manual/html/weekstartsmonday.html +4 -4
- data/manual/html/weekstartssunday.html +6 -6
- data/manual/html/width.column.html +6 -6
- data/manual/html/width.html +72 -0
- data/manual/html/work.html +4 -4
- data/manual/html/workinghours.project.html +4 -4
- data/manual/html/workinghours.resource.html +4 -4
- data/manual/html/workinghours.shift.html +4 -4
- data/manual/html/yearlyworkingdays.html +4 -4
- data/spec/Color_spec.rb +60 -0
- data/spec/ProjectBroker_spec.rb +3 -2
- data/spec/StatusSheets_spec.rb +5 -4
- data/spec/TableColumnSorter_spec.rb +78 -0
- data/spec/TimeSheets_spec.rb +6 -2
- data/spec/Tj3Daemon_spec.rb +2 -2
- data/spec/TraceReport_spec.rb +117 -0
- data/taskjuggler.gemspec +1 -1
- data/test/MessageChecker.rb +3 -1
- data/test/ReferenceGenerator.rb +1 -1
- data/test/TestSuite/CSV-Reports/Leave.tjp +1 -1
- data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +3 -0
- data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +9 -0
- data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +19 -16
- data/test/TestSuite/CSV-Reports/refs/weekly.csv +1 -0
- data/test/TestSuite/Export-Reports/refs/LogicalExpression.tjp +14 -2
- data/test/TestSuite/Export-Reports/refs/tutorial.tjp +98 -86
- data/test/TestSuite/Scheduler/Correct/Leaves.tjp +25 -0
- data/test/TestSuite/Syntax/Correct/Leave.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/LogicalExpression.tjp +9 -1
- data/test/TestSuite/Syntax/Correct/TraceReport.tjp +10 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +10 -4
- data/test/test_CSV-Reports.rb +3 -3
- data/test/test_Export-Reports.rb +91 -86
- data/test/test_Journal.rb +15 -12
- data/test/test_Limits.rb +3 -3
- data/test/test_Project.rb +1 -2
- data/test/test_ProjectFileScanner.rb +1 -1
- data/test/test_PropertySet.rb +1 -1
- data/test/test_Query.rb +5 -6
- data/test/test_ReportGenerator.rb +15 -7
- data/test/test_RichText.rb +4 -3
- data/test/test_Scheduler.rb +19 -7
- data/test/test_ShiftAssignments.rb +2 -2
- data/test/test_SimpleQueryExpander.rb +29 -2
- data/test/test_Syntax.rb +14 -5
- metadata +49 -10
- data/lib/taskjuggler/LogFile.rb +0 -73
|
@@ -306,8 +306,8 @@ EOT
|
|
|
306
306
|
'journalMode' => a('journalMode'),
|
|
307
307
|
'journalAttributes' => a('journalAttributes'),
|
|
308
308
|
'sortJournalEntries' => a('sortJournalEntries'),
|
|
309
|
-
'costAccount' => a('
|
|
310
|
-
'revenueAccount' => a('
|
|
309
|
+
'costAccount' => a('costaccount'),
|
|
310
|
+
'revenueAccount' => a('revenueaccount') }
|
|
311
311
|
query = Query.new(queryAttrs)
|
|
312
312
|
|
|
313
313
|
# Calculate the number of working days in the report interval.
|
|
@@ -440,8 +440,8 @@ EOT
|
|
|
440
440
|
'journalMode' => a('journalMode'),
|
|
441
441
|
'journalAttributes' => a('journalAttributes'),
|
|
442
442
|
'sortJournalEntries' => a('sortJournalEntries'),
|
|
443
|
-
'costAccount' => a('
|
|
444
|
-
'revenueAccount' => a('
|
|
443
|
+
'costAccount' => a('costaccount'),
|
|
444
|
+
'revenueAccount' => a('revenueaccount') }
|
|
445
445
|
query = Query.new(queryAttrs)
|
|
446
446
|
|
|
447
447
|
timeOffId = @report.get('timeOffId')
|
|
@@ -18,6 +18,7 @@ require 'taskjuggler/reports/AccountListRE'
|
|
|
18
18
|
require 'taskjuggler/reports/TextReport'
|
|
19
19
|
require 'taskjuggler/reports/TaskListRE'
|
|
20
20
|
require 'taskjuggler/reports/ResourceListRE'
|
|
21
|
+
require 'taskjuggler/reports/TraceReport'
|
|
21
22
|
require 'taskjuggler/reports/TagFile'
|
|
22
23
|
require 'taskjuggler/reports/TjpExportRE'
|
|
23
24
|
require 'taskjuggler/reports/StatusSheetReport'
|
|
@@ -45,6 +46,7 @@ class TaskJuggler
|
|
|
45
46
|
# Create a new report object.
|
|
46
47
|
def initialize(project, id, name, parent)
|
|
47
48
|
super(project.reports, id, name, parent)
|
|
49
|
+
@messageHandler = MessageHandlerInstance.instance
|
|
48
50
|
checkFileName(name)
|
|
49
51
|
project.addReport(self)
|
|
50
52
|
|
|
@@ -129,6 +131,8 @@ class TaskJuggler
|
|
|
129
131
|
@content = TextReport.new(self)
|
|
130
132
|
when :taskreport
|
|
131
133
|
@content = TaskListRE.new(self)
|
|
134
|
+
when :tracereport
|
|
135
|
+
@content = TraceReport.new(self)
|
|
132
136
|
when :statusSheet
|
|
133
137
|
@content = StatusSheetReport.new(self)
|
|
134
138
|
when :timeSheet
|
|
@@ -154,22 +158,6 @@ class TaskJuggler
|
|
|
154
158
|
@project.reportContexts.first.report.get('interactive')
|
|
155
159
|
end
|
|
156
160
|
|
|
157
|
-
def error(id, message)
|
|
158
|
-
if message && !message.empty?
|
|
159
|
-
@project.messageHandler.error(id, message, @sourceFileInfo)
|
|
160
|
-
else
|
|
161
|
-
# We have no message, so the error has already been reported to the
|
|
162
|
-
# MessageHandler. Just trigger another exception to signal the error.
|
|
163
|
-
raise TjException
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def warning(id, message)
|
|
168
|
-
if message && !message.empty?
|
|
169
|
-
@project.messageHandler.warning(id, message, @sourceFileInfo)
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
161
|
private
|
|
174
162
|
# Convenience function to access a report attribute
|
|
175
163
|
def a(attribute)
|
|
@@ -187,7 +175,7 @@ class TaskJuggler
|
|
|
187
175
|
return nil
|
|
188
176
|
end
|
|
189
177
|
|
|
190
|
-
html = HTMLDocument.new
|
|
178
|
+
html = HTMLDocument.new
|
|
191
179
|
head = html.generateHead(@project['name'] + " - #{get('title') || @name}",
|
|
192
180
|
'description' => 'TaskJuggler Report',
|
|
193
181
|
'keywords' => 'taskjuggler, project, management')
|
|
@@ -347,7 +335,7 @@ EOT
|
|
|
347
335
|
begin
|
|
348
336
|
f = @name == '.' ? $stdout :
|
|
349
337
|
File.new(((@name[0] == '/' ? '' : @project.outputDir) +
|
|
350
|
-
@name + '.
|
|
338
|
+
@name + '.ics').untaint, 'w')
|
|
351
339
|
f.puts "#{@content.to_iCal}"
|
|
352
340
|
rescue IOError, SystemCallError
|
|
353
341
|
error('write_ical', "Cannot write to file #{@name}.\n#{$!}")
|
|
@@ -48,25 +48,25 @@ class TaskJuggler
|
|
|
48
48
|
|
|
49
49
|
# Take the complete account list and remove all accounts that are matching
|
|
50
50
|
# the hide expression, the rollup Expression or are not a descendent of
|
|
51
|
-
#
|
|
51
|
+
# accountroot.
|
|
52
52
|
def filterAccountList(list_, hideExpr, rollupExpr, openNodes)
|
|
53
53
|
list = PropertyList.new(list_)
|
|
54
|
-
if (
|
|
55
|
-
# Remove all accounts that are not descendents of the
|
|
56
|
-
list.delete_if { |account| !account.isChildOf?(
|
|
54
|
+
if (accountroot = a('accountroot'))
|
|
55
|
+
# Remove all accounts that are not descendents of the accountroot.
|
|
56
|
+
list.delete_if { |account| !account.isChildOf?(accountroot) }
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
standardFilterOps(list, hideExpr, rollupExpr, openNodes, nil,
|
|
60
|
-
|
|
60
|
+
accountroot)
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
# Take the complete task list and remove all tasks that are matching the
|
|
64
64
|
# hide expression, the rollup Expression or are not a descendent of
|
|
65
|
-
#
|
|
65
|
+
# taskroot. In case resource is not nil, a task is only included if
|
|
66
66
|
# the resource is allocated to it in any of the reported scenarios.
|
|
67
67
|
def filterTaskList(list_, resource, hideExpr, rollupExpr, openNodes)
|
|
68
68
|
list = PropertyList.new(list_)
|
|
69
|
-
if (taskRoot = a('
|
|
69
|
+
if (taskRoot = a('taskroot'))
|
|
70
70
|
# Remove all tasks that are not descendents of the taskRoot.
|
|
71
71
|
list.delete_if { |task| !task.isChildOf?(taskRoot) }
|
|
72
72
|
end
|
|
@@ -94,11 +94,11 @@ class TaskJuggler
|
|
|
94
94
|
|
|
95
95
|
# Take the complete resource list and remove all resources that are matching
|
|
96
96
|
# the hide expression, the rollup Expression or are not a descendent of
|
|
97
|
-
#
|
|
97
|
+
# resourceroot. In case task is not nil, a resource is only included if
|
|
98
98
|
# it is assigned to the task in any of the reported scenarios.
|
|
99
99
|
def filterResourceList(list_, task, hideExpr, rollupExpr, openNodes)
|
|
100
100
|
list = PropertyList.new(list_)
|
|
101
|
-
if (resourceRoot = a('
|
|
101
|
+
if (resourceRoot = a('resourceroot'))
|
|
102
102
|
# Remove all resources that are not descendents of the resourceRoot.
|
|
103
103
|
list.delete_if { |resource| !resource.isChildOf?(resourceRoot) }
|
|
104
104
|
end
|
|
@@ -38,8 +38,8 @@ class TaskJuggler
|
|
|
38
38
|
'journalMode' => @report.get('journalMode'),
|
|
39
39
|
'journalAttributes' => @report.get('journalAttributes'),
|
|
40
40
|
'sortJournalEntries' => @report.get('sortJournalEntries'),
|
|
41
|
-
'costAccount' => @report.get('
|
|
42
|
-
'revenueAccount' => @report.get('
|
|
41
|
+
'costAccount' => @report.get('costaccount'),
|
|
42
|
+
'revenueAccount' => @report.get('revenueaccount')
|
|
43
43
|
}
|
|
44
44
|
@query = Query.new(queryAttrs)
|
|
45
45
|
if (@parent = @project.reportContexts.last)
|
|
@@ -82,17 +82,17 @@ class TaskJuggler
|
|
|
82
82
|
queryAttrs = { 'project' => @project,
|
|
83
83
|
'scopeProperty' => nil,
|
|
84
84
|
'scenarioIdx' => scenarioIdx,
|
|
85
|
-
'loadUnit' =>
|
|
86
|
-
'numberFormat' =>
|
|
87
|
-
'timeFormat' =>
|
|
85
|
+
'loadUnit' => :days,
|
|
86
|
+
'numberFormat' => RealFormat.new([ '-', '', '', '.', 1]),
|
|
87
|
+
'timeFormat' => "%Y-%m-%d",
|
|
88
88
|
'currencyFormat' => a('currencyFormat'),
|
|
89
89
|
'start' => a('start'), 'end' => a('end'),
|
|
90
90
|
'hideJournalEntry' => a('hideJournalEntry'),
|
|
91
91
|
'journalMode' => a('journalMode'),
|
|
92
92
|
'journalAttributes' => a('journalAttributes'),
|
|
93
93
|
'sortJournalEntries' => a('sortJournalEntries'),
|
|
94
|
-
'costAccount' => a('
|
|
95
|
-
'revenueAccount' => a('
|
|
94
|
+
'costAccount' => a('costaccount'),
|
|
95
|
+
'revenueAccount' => a('revenueaccount') }
|
|
96
96
|
resourceList.query = Query.new(queryAttrs)
|
|
97
97
|
resourceList.sort!
|
|
98
98
|
|
|
@@ -129,7 +129,7 @@ class TaskJuggler
|
|
|
129
129
|
# all it's sub tasks.
|
|
130
130
|
entries = @project['journal'].
|
|
131
131
|
currentEntriesR(a('end'), task, 0, a('start') + 1,
|
|
132
|
-
resourceList.query
|
|
132
|
+
resourceList.query)
|
|
133
133
|
next if entries.empty?
|
|
134
134
|
|
|
135
135
|
manager.responsibilities << ManagerResponsibilities.new(task, entries)
|
|
@@ -29,14 +29,16 @@ class TaskJuggler
|
|
|
29
29
|
|
|
30
30
|
@@propertiesById = {
|
|
31
31
|
# ID Header Indent Align Scen Spec.
|
|
32
|
+
'activetasks' => [ 'Active Tasks', true, :right, true ],
|
|
32
33
|
'annualleave' => [ 'Annual Leave', true, :right, true ],
|
|
33
|
-
'annualleavebalance'=> [ 'Annual Leave Balance', false,
|
|
34
|
+
'annualleavebalance'=> [ 'Annual Leave Balance', false, :right, true ],
|
|
34
35
|
'alert' => [ 'Alert', true, :left, false ],
|
|
35
36
|
'alertmessages' => [ 'Alert Messages', false, :left, false ],
|
|
36
37
|
'alertsummaries' => [ 'Alert Summaries', false, :left, false ],
|
|
37
38
|
'alerttrend' => [ 'Alert Trend', false, :left, false ],
|
|
38
39
|
'balance' => [ 'Balance', true, :right, true ],
|
|
39
40
|
'bsi' => [ 'BSI', false, :left, false ],
|
|
41
|
+
'closedtasks' => [ 'Closed Tasks', true, :right, true ],
|
|
40
42
|
'complete' => [ 'Completion', false, :right, true ],
|
|
41
43
|
'cost' => [ 'Cost', true, :right, true ],
|
|
42
44
|
'duration' => [ 'Duration', true, :right, true ],
|
|
@@ -57,6 +59,7 @@ class TaskJuggler
|
|
|
57
59
|
'line' => [ 'Line No.', false, :right, false ],
|
|
58
60
|
'name' => [ 'Name', true, :left, false ],
|
|
59
61
|
'no' => [ 'No.', false, :right, false ],
|
|
62
|
+
'opentasks' => [ 'Open Tasks', true, :right, true ],
|
|
60
63
|
'precursors' => [ 'Precursors', false, :left, true ],
|
|
61
64
|
'rate' => [ 'Rate', true, :right, true ],
|
|
62
65
|
'resources' => [ 'Resources', false, :left, true ],
|
|
@@ -208,33 +211,37 @@ class TaskJuggler
|
|
|
208
211
|
# If we have user specified dates for the report period or the column
|
|
209
212
|
# period, we don't adjust the period. This flag is used to mark if we
|
|
210
213
|
# have user-provided values.
|
|
211
|
-
|
|
214
|
+
doNotAdjustStart = false
|
|
215
|
+
doNotAdjustEnd = false
|
|
212
216
|
|
|
213
217
|
# Determine the start date for the column.
|
|
214
218
|
if columnDef.start
|
|
215
219
|
# We have a user-specified, column specific start date.
|
|
216
220
|
rStart = columnDef.start
|
|
217
|
-
|
|
221
|
+
doNotAdjustStart = true
|
|
218
222
|
else
|
|
219
223
|
# Use the report start date.
|
|
220
224
|
rStart = a('start')
|
|
221
|
-
|
|
225
|
+
doNotAdjustStart = true if rStart != @project['start']
|
|
222
226
|
end
|
|
223
227
|
|
|
224
228
|
if columnDef.end
|
|
225
229
|
rEnd = columnDef.end
|
|
226
|
-
|
|
230
|
+
doNotAdjustEnd = true
|
|
227
231
|
else
|
|
228
232
|
rEnd = a('end')
|
|
229
|
-
|
|
233
|
+
doNotAdjustEnd = true if rEnd != @project['end']
|
|
230
234
|
end
|
|
235
|
+
origStart = rStart
|
|
236
|
+
origEnd = rEnd
|
|
231
237
|
|
|
232
238
|
# Save the unadjusted dates to the columns Hash.
|
|
233
239
|
@columns[columnDef] = TableReportColumn.new(rStart, rEnd)
|
|
234
240
|
|
|
235
241
|
# If the task list is empty or the user has provided a custom start or
|
|
236
242
|
# end date, we don't touch the report period.
|
|
237
|
-
return if tasks.empty? || scenarios.empty? ||
|
|
243
|
+
return if tasks.empty? || scenarios.empty? ||
|
|
244
|
+
(doNotAdjustStart && doNotAdjustEnd)
|
|
238
245
|
|
|
239
246
|
# Find the start date of the earliest tasks included in the report and
|
|
240
247
|
# the end date of the last included tasks.
|
|
@@ -289,19 +296,21 @@ class TaskJuggler
|
|
|
289
296
|
margin = entry[0] * entry[2]
|
|
290
297
|
minWidth = entry[0] * entry[1] if minWidth < entry[0] * entry[1]
|
|
291
298
|
else
|
|
292
|
-
|
|
299
|
+
doNotAdjustStart = doNotAdjustEnd = true
|
|
293
300
|
end
|
|
294
301
|
|
|
295
|
-
unless
|
|
302
|
+
unless doNotAdjustStart && doNotAdjustEnd
|
|
296
303
|
if minWidth > (rEnd - rStart + 1)
|
|
297
|
-
margin
|
|
304
|
+
margin = (minWidth - (rEnd - rStart + 1)) / 2
|
|
298
305
|
end
|
|
299
306
|
|
|
300
307
|
rStart -= margin
|
|
301
308
|
rEnd += margin
|
|
302
309
|
|
|
303
310
|
# Save the adjusted dates to the columns Hash.
|
|
304
|
-
@columns[columnDef] = TableReportColumn.new(
|
|
311
|
+
@columns[columnDef] = TableReportColumn.new(
|
|
312
|
+
doNotAdjustStart ? origStart : rStart,
|
|
313
|
+
doNotAdjustEnd ? origEnd : rEnd)
|
|
305
314
|
end
|
|
306
315
|
end
|
|
307
316
|
|
|
@@ -390,7 +399,7 @@ class TaskJuggler
|
|
|
390
399
|
line.no = no
|
|
391
400
|
line.lineNo = lineNo
|
|
392
401
|
line.subLineNo = @table.lines
|
|
393
|
-
setIndent(line, a('
|
|
402
|
+
setIndent(line, a('accountroot'), accountList.treeMode?)
|
|
394
403
|
|
|
395
404
|
# Generate a cell for each column in this line.
|
|
396
405
|
a('columns').each do |columnDef|
|
|
@@ -437,7 +446,7 @@ class TaskJuggler
|
|
|
437
446
|
line.no = no unless scopeLine
|
|
438
447
|
line.lineNo = lineNo
|
|
439
448
|
line.subLineNo = @table.lines
|
|
440
|
-
setIndent(line, a('
|
|
449
|
+
setIndent(line, a('taskroot'), taskList.treeMode?)
|
|
441
450
|
|
|
442
451
|
# Generate a cell for each column in this line.
|
|
443
452
|
a('columns').each do |columnDef|
|
|
@@ -494,7 +503,7 @@ class TaskJuggler
|
|
|
494
503
|
line.no = no unless scopeLine
|
|
495
504
|
line.lineNo = lineNo
|
|
496
505
|
line.subLineNo = @table.lines
|
|
497
|
-
setIndent(line, a('
|
|
506
|
+
setIndent(line, a('resourceroot'), resourceList.treeMode?)
|
|
498
507
|
|
|
499
508
|
# Generate a cell for each column in this line.
|
|
500
509
|
a('columns').each do |column|
|
|
@@ -953,7 +962,7 @@ class TaskJuggler
|
|
|
953
962
|
query.scopeProperty = nil
|
|
954
963
|
query.attributeId = 'effort'
|
|
955
964
|
query.startIdx = @project.dateToIdx(t)
|
|
956
|
-
query.endIdx = @project.dateToIdx(nextT)
|
|
965
|
+
query.endIdx = @project.dateToIdx(nextT)
|
|
957
966
|
query.process
|
|
958
967
|
workLoad = query.to_num
|
|
959
968
|
scaledWorkLoad = query.to_s
|
|
@@ -187,17 +187,17 @@ EOT
|
|
|
187
187
|
queryAttrs = { 'project' => @project,
|
|
188
188
|
'scopeProperty' => nil,
|
|
189
189
|
'scenarioIdx' => scenarioIdx,
|
|
190
|
-
'loadUnit' =>
|
|
191
|
-
'numberFormat' =>
|
|
192
|
-
'timeFormat' =>
|
|
190
|
+
'loadUnit' => :days,
|
|
191
|
+
'numberFormat' => RealFormat.new([ '-', '', '', '.', 1]),
|
|
192
|
+
'timeFormat' => "%Y-%m-%d",
|
|
193
193
|
'currencyFormat' => a('currencyFormat'),
|
|
194
194
|
'start' => from, 'end' => to,
|
|
195
195
|
'hideJournalEntry' => a('hideJournalEntry'),
|
|
196
196
|
'journalMode' => a('journalMode'),
|
|
197
197
|
'journalAttributes' => a('journalAttributes'),
|
|
198
198
|
'sortJournalEntries' => a('sortJournalEntries'),
|
|
199
|
-
'costAccount' => a('
|
|
200
|
-
'revenueAccount' => a('
|
|
199
|
+
'costAccount' => a('costaccount'),
|
|
200
|
+
'revenueAccount' => a('revenueaccount') }
|
|
201
201
|
resourceList.query = Query.new(queryAttrs)
|
|
202
202
|
resourceList.sort!
|
|
203
203
|
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = TraceReport.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
|
+
# by Chris Schlaeger <chris@linux.com>
|
|
8
|
+
#
|
|
9
|
+
# This program is free software; you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
11
|
+
# published by the Free Software Foundation.
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require 'taskjuggler/reports/ReportBase'
|
|
15
|
+
require 'taskjuggler/reports/CSVFile'
|
|
16
|
+
require 'taskjuggler/reports/ChartPlotter'
|
|
17
|
+
require 'taskjuggler/TableColumnSorter'
|
|
18
|
+
require 'taskjuggler/MessageHandler'
|
|
19
|
+
|
|
20
|
+
class TaskJuggler
|
|
21
|
+
|
|
22
|
+
# The trace report is used to periodically snapshot a specific list of
|
|
23
|
+
# property attributes and add them to a CSV file.
|
|
24
|
+
class TraceReport < ReportBase
|
|
25
|
+
|
|
26
|
+
include MessageHandler
|
|
27
|
+
|
|
28
|
+
# Create a new object and set some default values.
|
|
29
|
+
def initialize(report)
|
|
30
|
+
super
|
|
31
|
+
@table = nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Generate the table in the intermediate format.
|
|
35
|
+
def generateIntermediateFormat
|
|
36
|
+
super
|
|
37
|
+
|
|
38
|
+
queryAttrs = { 'project' => @project,
|
|
39
|
+
'scopeProperty' => nil,
|
|
40
|
+
'loadUnit' => a('loadUnit'),
|
|
41
|
+
'numberFormat' => a('numberFormat'),
|
|
42
|
+
# We use a hardcoded %Y-%m-%d format for tracereports.
|
|
43
|
+
'timeFormat' => "%Y-%m-%d",
|
|
44
|
+
'currencyFormat' => a('currencyFormat'),
|
|
45
|
+
'start' => a('start'), 'end' => a('end'),
|
|
46
|
+
'hideJournalEntry' => a('hideJournalEntry'),
|
|
47
|
+
'journalMode' => a('journalMode'),
|
|
48
|
+
'journalAttributes' => a('journalAttributes'),
|
|
49
|
+
'sortJournalEntries' => a('sortJournalEntries'),
|
|
50
|
+
'costAccount' => a('costaccount'),
|
|
51
|
+
'revenueAccount' => a('revenueaccount') }
|
|
52
|
+
query = Query.new(queryAttrs)
|
|
53
|
+
|
|
54
|
+
# Prepare the account list.
|
|
55
|
+
accountList = PropertyList.new(@project.accounts)
|
|
56
|
+
accountList.setSorting(a('sortAccounts'))
|
|
57
|
+
accountList.query = query
|
|
58
|
+
accountList = filterAccountList(accountList, a('hideAccount'),
|
|
59
|
+
a('rollupAccount'), a('openNodes'))
|
|
60
|
+
accountList.sort!
|
|
61
|
+
|
|
62
|
+
# Prepare the resource list.
|
|
63
|
+
resourceList = PropertyList.new(@project.resources)
|
|
64
|
+
resourceList.setSorting(a('sortResources'))
|
|
65
|
+
resourceList.query = query
|
|
66
|
+
resourceList = filterTaskList(resourceList, nil, a('hideResource'),
|
|
67
|
+
a('rollupResource'), a('openNodes'))
|
|
68
|
+
resourceList.sort!
|
|
69
|
+
|
|
70
|
+
# Prepare the task list.
|
|
71
|
+
taskList = PropertyList.new(@project.tasks)
|
|
72
|
+
taskList.includeAdopted
|
|
73
|
+
taskList.setSorting(a('sortTasks'))
|
|
74
|
+
taskList.query = query
|
|
75
|
+
taskList = filterTaskList(taskList, nil, a('hideTask'), a('rollupTask'),
|
|
76
|
+
a('openNodes'))
|
|
77
|
+
taskList.sort!
|
|
78
|
+
|
|
79
|
+
@fileName = ((@report.name[0] == '/' ? '' : @project.outputDir) +
|
|
80
|
+
@report.name + '.csv').untaint
|
|
81
|
+
|
|
82
|
+
# Generate the table header.
|
|
83
|
+
headers = [ 'Date' ] +
|
|
84
|
+
generatePropertyListHeader(accountList, query) +
|
|
85
|
+
generatePropertyListHeader(resourceList, query) +
|
|
86
|
+
generatePropertyListHeader(taskList, query)
|
|
87
|
+
|
|
88
|
+
discontinuedColumns = 0
|
|
89
|
+
if File.exists?(@fileName)
|
|
90
|
+
begin
|
|
91
|
+
@table = CSVFile.new.read(@fileName)
|
|
92
|
+
rescue
|
|
93
|
+
error('tr_cannot_read_csv',
|
|
94
|
+
"Cannot read CSV file #{@fileName}: #{$!}")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
if @table[0] != headers
|
|
98
|
+
# Some columns have changed. We move all discontinued columns to the
|
|
99
|
+
# last columns and rearrange the others according to the new
|
|
100
|
+
# headers. New columns will be filled with nil in previous rows.
|
|
101
|
+
sorter = TableColumnSorter.new(@table)
|
|
102
|
+
@table = sorter.sort(headers)
|
|
103
|
+
discontinuedColumns = sorter.discontinuedColumns
|
|
104
|
+
end
|
|
105
|
+
else
|
|
106
|
+
@table = [ headers ]
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Convert empty strings into nil objects and dates in %Y-%m-%d format
|
|
110
|
+
# into TjTime objects.
|
|
111
|
+
@table.each do |line|
|
|
112
|
+
line.length.times do |i|
|
|
113
|
+
if line[i] == ''
|
|
114
|
+
line[i] = nil
|
|
115
|
+
elsif line[i].is_a?(String) && /\d{4}-\d{2}-\d{2}/ =~ line[i]
|
|
116
|
+
line[i] = TjTime.new(line[i])
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
query = @project.reportContexts.last.query.dup
|
|
122
|
+
dateTag = @project['now'].midnight
|
|
123
|
+
|
|
124
|
+
idx = @table.index { |line| line[0] == dateTag }
|
|
125
|
+
discColumnValues = discontinuedColumns > 0 ?
|
|
126
|
+
Array.new(discontinuedColumns, nil) : []
|
|
127
|
+
if idx
|
|
128
|
+
# We already have an entry for the current date. All old values of
|
|
129
|
+
# this line will be overwritten with the current values. The old
|
|
130
|
+
# values in the discontinued columns will be kept.
|
|
131
|
+
if discontinuedColumns > 0
|
|
132
|
+
discColumnValues = @table[idx][headers.length..-1]
|
|
133
|
+
end
|
|
134
|
+
@table[idx] = []
|
|
135
|
+
else
|
|
136
|
+
# Append a new line of values to the table.
|
|
137
|
+
@table << []
|
|
138
|
+
idx = -1
|
|
139
|
+
end
|
|
140
|
+
# The first entry is always the current date.
|
|
141
|
+
@table[idx] << dateTag
|
|
142
|
+
|
|
143
|
+
# Now add the new values to the line
|
|
144
|
+
generatePropertyListValues(idx, accountList, query)
|
|
145
|
+
generatePropertyListValues(idx, resourceList, query)
|
|
146
|
+
generatePropertyListValues(idx, taskList, query)
|
|
147
|
+
|
|
148
|
+
# Fill the discontinued columns with old values or nil.
|
|
149
|
+
@table[idx] += discColumnValues
|
|
150
|
+
|
|
151
|
+
# Sort the table by ascending first column dates. We need to ensure that
|
|
152
|
+
# the header remains the first line in the table.
|
|
153
|
+
@table.sort! { |l1, l2| l1[0].is_a?(String) ? -1 :
|
|
154
|
+
(l2[0].is_a?(String) ? 1 : l1[0] <=> l2[0]) }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def to_html
|
|
158
|
+
html = []
|
|
159
|
+
html << rt_to_html('header')
|
|
160
|
+
|
|
161
|
+
begin
|
|
162
|
+
plotter = ChartPlotter.new(a('width'), a('height'), @table)
|
|
163
|
+
plotter.generate
|
|
164
|
+
html << plotter.to_svg
|
|
165
|
+
rescue ChartPlotterError => exception
|
|
166
|
+
warning('chartPlotterError', exception.message, @report.sourceFileInfo)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
html << rt_to_html('footer')
|
|
170
|
+
|
|
171
|
+
html
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def to_csv
|
|
175
|
+
# Convert all TjTime values into String with format %Y-%m-%d and nil
|
|
176
|
+
# objects into empty Strings.
|
|
177
|
+
@table.each do |line|
|
|
178
|
+
line.length.times do |i|
|
|
179
|
+
if line[i].nil?
|
|
180
|
+
line[i] = ''
|
|
181
|
+
elsif line[i].is_a?(TjTime)
|
|
182
|
+
line[i] = line[i].to_s('%Y-%m-%d')
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
@table
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
def generatePropertyListHeader(propertyList, query)
|
|
193
|
+
headers = []
|
|
194
|
+
query = query.dup
|
|
195
|
+
a('columns').each do |columnDescr|
|
|
196
|
+
query.attributeId = columnDescr.id
|
|
197
|
+
a('scenarios').each do |scenarioIdx|
|
|
198
|
+
query.scenarioIdx = scenarioIdx
|
|
199
|
+
propertyList.each do |property|
|
|
200
|
+
query.property = property
|
|
201
|
+
|
|
202
|
+
#adjustColumnPeriod(columnDescr, propertyList, a.get('scenarios'))
|
|
203
|
+
header = SimpleQueryExpander.new(columnDescr.title, query,
|
|
204
|
+
@report.sourceFileInfo).expand
|
|
205
|
+
|
|
206
|
+
if headers.include?(header)
|
|
207
|
+
error('trace_columns_not_uniq',
|
|
208
|
+
"The column title '#{header}' is already used " +
|
|
209
|
+
"by a previous column. Column titles must be " +
|
|
210
|
+
"unique!")
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
headers << header
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
headers
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def generatePropertyListValues(idx, propertyList, query)
|
|
221
|
+
@report.get('columns').each do |columnDescr|
|
|
222
|
+
query.attributeId = columnDescr.id
|
|
223
|
+
|
|
224
|
+
a('scenarios').each do |scenarioIdx|
|
|
225
|
+
query.scenarioIdx = scenarioIdx
|
|
226
|
+
|
|
227
|
+
propertyList.each do |property|
|
|
228
|
+
query.property = property
|
|
229
|
+
|
|
230
|
+
query.process
|
|
231
|
+
@table[idx] << query.result
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def columnTitle(property, scenarioIdx, columnDescr)
|
|
238
|
+
title = columnDescr.title.dup
|
|
239
|
+
# The title can be parameterized by including mini-queries for the ID
|
|
240
|
+
# or the name of the property, the scenario id or the attribute ID.
|
|
241
|
+
title.gsub!(/<-id->/, property.fullId)
|
|
242
|
+
title.gsub!(/<-scenario->/, @project.scenario(scenarioIdx).id)
|
|
243
|
+
title.gsub!(/<-name->/, property.name)
|
|
244
|
+
title.gsub!(/<-attribute->/, columnDescr.id)
|
|
245
|
+
title
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
end
|
|
251
|
+
|