taskjuggler 3.0.0 → 3.1.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 +61 -0
- data/README.rdoc +43 -27
- data/data/css/tjreport.css +30 -0
- data/data/tjp.vim +100 -89
- data/examples/ProjectTemplate/template.tjp +338 -0
- data/examples/ToDo-List/todolist.tjp +84 -0
- data/examples/{tutorial.tjp → Tutorial/tutorial.tjp} +9 -7
- data/lib/header.tmpl +1 -1
- data/lib/taskjuggler/Account.rb +2 -2
- data/lib/taskjuggler/AccountCredit.rb +29 -0
- data/lib/taskjuggler/AccountScenario.rb +73 -7
- data/lib/taskjuggler/AlertLevelDefinitions.rb +104 -0
- data/lib/taskjuggler/AlgorithmDiff.rb +2 -2
- data/lib/taskjuggler/Allocation.rb +1 -1
- data/lib/taskjuggler/AppConfig.rb +1 -1
- data/lib/taskjuggler/AttributeBase.rb +1 -1
- data/lib/taskjuggler/AttributeDefinition.rb +1 -1
- data/lib/taskjuggler/Attributes.rb +40 -3
- data/lib/taskjuggler/BatchProcessor.rb +15 -14
- data/lib/taskjuggler/Booking.rb +1 -1
- data/lib/taskjuggler/Charge.rb +2 -2
- data/lib/taskjuggler/ChargeSet.rb +1 -1
- data/lib/taskjuggler/DataCache.rb +24 -12
- data/lib/taskjuggler/FileList.rb +1 -1
- data/lib/taskjuggler/HTMLDocument.rb +1 -1
- data/lib/taskjuggler/HTMLElements.rb +1 -1
- data/lib/taskjuggler/ICalendar.rb +1 -1
- data/lib/taskjuggler/Interval.rb +1 -1
- data/lib/taskjuggler/IntervalList.rb +1 -1
- data/lib/taskjuggler/Journal.rb +61 -41
- data/lib/taskjuggler/KeywordArray.rb +1 -1
- data/lib/taskjuggler/KeywordDocumentation.rb +121 -33
- data/lib/taskjuggler/LeaveList.rb +103 -0
- data/lib/taskjuggler/Limits.rb +1 -1
- data/lib/taskjuggler/Log.rb +6 -3
- data/lib/taskjuggler/LogFile.rb +1 -1
- data/lib/taskjuggler/LogicalExpression.rb +1 -1
- data/lib/taskjuggler/LogicalFunction.rb +16 -2
- data/lib/taskjuggler/LogicalOperation.rb +3 -1
- data/lib/taskjuggler/MessageHandler.rb +13 -4
- data/lib/taskjuggler/PTNProxy.rb +118 -0
- data/lib/taskjuggler/Project.rb +58 -67
- data/lib/taskjuggler/ProjectFileParser.rb +39 -5
- data/lib/taskjuggler/ProjectFileScanner.rb +1 -1
- data/lib/taskjuggler/PropertyList.rb +26 -2
- data/lib/taskjuggler/PropertySet.rb +8 -1
- data/lib/taskjuggler/PropertyTreeNode.rb +36 -32
- data/lib/taskjuggler/Query.rb +1 -1
- data/lib/taskjuggler/RealFormat.rb +4 -2
- data/lib/taskjuggler/Resource.rb +3 -3
- data/lib/taskjuggler/ResourceScenario.rb +219 -140
- data/lib/taskjuggler/RichText.rb +1 -1
- data/lib/taskjuggler/RichText/Document.rb +2 -2
- data/lib/taskjuggler/RichText/Element.rb +2 -2
- data/lib/taskjuggler/RichText/FunctionExample.rb +2 -2
- data/lib/taskjuggler/RichText/FunctionHandler.rb +2 -2
- data/lib/taskjuggler/RichText/Parser.rb +2 -2
- data/lib/taskjuggler/RichText/RTFHandlers.rb +1 -1
- data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
- data/lib/taskjuggler/RichText/RTFQuery.rb +1 -1
- data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
- data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -1
- data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
- data/lib/taskjuggler/RichText/Scanner.rb +18 -4
- data/lib/taskjuggler/RichText/Snip.rb +2 -2
- data/lib/taskjuggler/RichText/SyntaxRules.rb +6 -14
- data/lib/taskjuggler/RichText/TOCEntry.rb +16 -7
- data/lib/taskjuggler/RichText/TableOfContents.rb +3 -2
- data/lib/taskjuggler/RuntimeConfig.rb +1 -1
- data/lib/taskjuggler/Scenario.rb +1 -1
- data/lib/taskjuggler/ScenarioData.rb +1 -1
- data/lib/taskjuggler/Scoreboard.rb +1 -1
- data/lib/taskjuggler/SheetHandlerBase.rb +1 -1
- data/lib/taskjuggler/SheetReceiver.rb +1 -1
- data/lib/taskjuggler/SheetSender.rb +3 -3
- data/lib/taskjuggler/Shift.rb +2 -2
- data/lib/taskjuggler/ShiftAssignments.rb +24 -19
- data/lib/taskjuggler/ShiftScenario.rb +4 -4
- data/lib/taskjuggler/SimpleQueryExpander.rb +1 -1
- data/lib/taskjuggler/StatusSheetReceiver.rb +1 -1
- data/lib/taskjuggler/StatusSheetSender.rb +1 -1
- data/lib/taskjuggler/StdIoWrapper.rb +1 -1
- data/lib/taskjuggler/SyntaxReference.rb +5 -2
- data/lib/taskjuggler/TableColumnDefinition.rb +1 -1
- data/lib/taskjuggler/Task.rb +4 -8
- data/lib/taskjuggler/TaskDependency.rb +1 -1
- data/lib/taskjuggler/TaskJuggler.rb +1 -1
- data/lib/taskjuggler/TaskScenario.rb +131 -51
- data/lib/taskjuggler/TernarySearchTree.rb +6 -4
- data/lib/taskjuggler/TextFormatter.rb +9 -2
- data/lib/taskjuggler/TextParser.rb +13 -3
- data/lib/taskjuggler/TextParser/MacroTable.rb +1 -1
- data/lib/taskjuggler/TextParser/Pattern.rb +52 -8
- data/lib/taskjuggler/TextParser/Rule.rb +11 -5
- data/lib/taskjuggler/TextParser/Scanner.rb +1 -1
- data/lib/taskjuggler/TextParser/SourceFileInfo.rb +1 -1
- data/lib/taskjuggler/TextParser/StackElement.rb +1 -1
- data/lib/taskjuggler/TextParser/State.rb +2 -2
- data/lib/taskjuggler/TextParser/TokenDoc.rb +1 -1
- data/lib/taskjuggler/TimeSheetReceiver.rb +1 -1
- data/lib/taskjuggler/TimeSheetSender.rb +1 -1
- data/lib/taskjuggler/TimeSheetSummary.rb +1 -1
- data/lib/taskjuggler/TimeSheets.rb +4 -6
- data/lib/taskjuggler/Tj3AppBase.rb +18 -1
- data/lib/taskjuggler/Tj3Config.rb +4 -4
- data/lib/taskjuggler/Tj3SheetAppBase.rb +1 -1
- data/lib/taskjuggler/TjException.rb +1 -1
- data/lib/taskjuggler/TjTime.rb +1 -1
- data/lib/taskjuggler/TjpExample.rb +1 -1
- data/lib/taskjuggler/TjpSyntaxRules.rb +920 -392
- data/lib/taskjuggler/URLParameter.rb +1 -1
- data/lib/taskjuggler/UTF8String.rb +1 -1
- data/lib/taskjuggler/UserManual.rb +1 -1
- data/lib/taskjuggler/VimSyntax.rb +9 -6
- data/lib/taskjuggler/WorkingHours.rb +12 -1
- data/lib/taskjuggler/XMLDocument.rb +1 -1
- data/lib/taskjuggler/XMLElement.rb +1 -1
- data/lib/taskjuggler/apps/Tj3.rb +8 -3
- data/lib/taskjuggler/apps/Tj3Client.rb +1 -1
- data/lib/taskjuggler/apps/Tj3Daemon.rb +1 -1
- data/lib/taskjuggler/apps/Tj3Man.rb +1 -1
- data/lib/taskjuggler/apps/Tj3SsReceiver.rb +2 -2
- data/lib/taskjuggler/apps/Tj3SsSender.rb +1 -1
- data/lib/taskjuggler/apps/Tj3TsReceiver.rb +1 -1
- data/lib/taskjuggler/apps/Tj3TsSender.rb +1 -1
- data/lib/taskjuggler/apps/Tj3TsSummary.rb +1 -1
- data/lib/taskjuggler/daemon/Daemon.rb +1 -1
- data/lib/taskjuggler/daemon/ProcessIntercom.rb +1 -1
- data/lib/taskjuggler/daemon/ProjectBroker.rb +1 -1
- data/lib/taskjuggler/daemon/ProjectServer.rb +1 -1
- data/lib/taskjuggler/daemon/ReportServer.rb +2 -2
- data/lib/taskjuggler/daemon/ReportServlet.rb +1 -1
- data/lib/taskjuggler/daemon/WebServer.rb +1 -1
- data/lib/taskjuggler/daemon/WelcomePage.rb +1 -1
- data/lib/taskjuggler/deep_copy.rb +1 -1
- data/lib/taskjuggler/reports/AccountListRE.rb +115 -0
- data/lib/taskjuggler/reports/CSVFile.rb +1 -1
- data/lib/taskjuggler/reports/CollisionDetector.rb +1 -1
- data/lib/taskjuggler/reports/ColumnTable.rb +1 -1
- data/lib/taskjuggler/reports/GanttChart.rb +1 -1
- data/lib/taskjuggler/reports/GanttContainer.rb +1 -3
- data/lib/taskjuggler/reports/GanttHeader.rb +1 -1
- data/lib/taskjuggler/reports/GanttHeaderScaleItem.rb +1 -1
- data/lib/taskjuggler/reports/GanttLine.rb +23 -12
- data/lib/taskjuggler/reports/GanttLoadStack.rb +1 -1
- data/lib/taskjuggler/reports/GanttMilestone.rb +1 -1
- data/lib/taskjuggler/reports/GanttRouter.rb +1 -1
- data/lib/taskjuggler/reports/GanttTaskBar.rb +1 -1
- data/lib/taskjuggler/reports/HTMLGraphics.rb +1 -1
- data/lib/taskjuggler/reports/ICalReport.rb +5 -2
- data/lib/taskjuggler/reports/Navigator.rb +1 -1
- data/lib/taskjuggler/reports/NikuReport.rb +1 -1
- data/lib/taskjuggler/reports/Report.rb +29 -4
- data/lib/taskjuggler/reports/ReportBase.rb +15 -1
- data/lib/taskjuggler/reports/ReportContext.rb +1 -1
- data/lib/taskjuggler/reports/ReportTable.rb +1 -1
- data/lib/taskjuggler/reports/ReportTableCell.rb +1 -1
- data/lib/taskjuggler/reports/ReportTableColumn.rb +1 -1
- data/lib/taskjuggler/reports/ReportTableLegend.rb +1 -1
- data/lib/taskjuggler/reports/ReportTableLine.rb +1 -1
- data/lib/taskjuggler/reports/ResourceListRE.rb +3 -5
- data/lib/taskjuggler/reports/StatusSheetReport.rb +2 -2
- data/lib/taskjuggler/reports/TableReport.rb +336 -204
- data/lib/taskjuggler/reports/TableReportColumn.rb +30 -0
- data/lib/taskjuggler/reports/TagFile.rb +2 -2
- data/lib/taskjuggler/reports/TaskListRE.rb +3 -6
- data/lib/taskjuggler/reports/TextReport.rb +1 -1
- data/lib/taskjuggler/reports/TimeSheetReport.rb +3 -3
- data/lib/taskjuggler/reports/TjpExportRE.rb +4 -1
- data/lib/tj3.rb +1 -1
- data/lib/tj3client.rb +1 -1
- data/lib/tj3d.rb +1 -1
- data/lib/tj3man.rb +1 -1
- data/lib/tj3ss_receiver.rb +1 -1
- data/lib/tj3ss_sender.rb +1 -1
- data/lib/tj3ts_receiver.rb +1 -1
- data/lib/tj3ts_sender.rb +1 -1
- data/lib/tj3ts_summary.rb +1 -1
- data/lib/updateheader.sh +4 -1
- data/manual/Getting_Started +7 -4
- data/manual/How_To_Contribute +26 -5
- data/manual/Installation +26 -18
- data/manual/Intro +55 -33
- data/manual/Reporting_Bugs +18 -8
- data/manual/Rich_Text_Attributes +16 -3
- data/manual/Software +2 -2
- data/manual/TaskJuggler_2x_Migration +2 -2
- data/manual/The_TaskJuggler_Syntax +10 -0
- data/manual/Tutorial +2 -2
- data/manual/html/Day_To_Day_Juggling.html +16 -12
- data/manual/html/Getting_Started.html +9 -7
- data/manual/html/How_To_Contribute.html +18 -10
- data/manual/html/Installation.html +18 -15
- data/manual/html/Intro.html +44 -28
- data/manual/html/Reporting_Bugs.html +9 -7
- data/manual/html/Rich_Text_Attributes.html +11 -8
- data/manual/html/Software.html +5 -5
- data/manual/html/TaskJuggler_2x_Migration.html +4 -4
- data/manual/html/TaskJuggler_Internals.html +3 -3
- data/manual/html/The_TaskJuggler_Syntax.html +6 -3
- data/manual/html/Tutorial.html +12 -12
- data/manual/html/account.html +19 -10
- data/manual/html/account.task.html +5 -28
- data/manual/html/accountprefix.html +5 -5
- data/manual/html/{report.html → accountreport.html} +140 -23
- data/manual/html/accountroot.html +142 -0
- data/manual/html/active.html +5 -5
- data/manual/html/adopt.task.html +7 -8
- data/manual/html/aggregate.html +145 -0
- data/manual/html/alert.html +12 -11
- data/manual/html/alertlevels.html +102 -0
- data/manual/html/allocate.html +6 -6
- data/manual/html/alphabet.html +1 -1
- data/manual/html/alternative.html +3 -3
- data/manual/html/author.html +3 -3
- data/manual/html/balance.html +84 -11
- data/manual/html/booking.resource.html +3 -3
- data/manual/html/booking.task.html +3 -3
- data/manual/html/caption.html +6 -4
- data/manual/html/cellcolor.column.html +3 -3
- data/manual/html/celltext.column.html +3 -3
- data/manual/html/center.html +28 -4
- data/manual/html/charge.html +3 -3
- data/manual/html/chargeset.html +5 -5
- data/manual/html/columnid.html +40 -9
- data/manual/html/columns.html +6 -4
- data/manual/html/complete.html +15 -9
- data/manual/html/copyright.html +5 -5
- data/manual/html/{credit.html → credits.html} +15 -12
- data/manual/html/css/tjreport.css +30 -0
- data/manual/html/currency.html +28 -15
- data/manual/html/currencyformat.html +4 -4
- data/manual/html/dailymax.html +3 -3
- data/manual/html/dailymin.html +3 -3
- data/manual/html/dailyworkinghours.html +3 -3
- data/manual/html/date.extend.html +3 -3
- data/manual/html/date.html +3 -3
- data/manual/html/definitions.html +3 -3
- data/manual/html/depends.html +3 -3
- data/manual/html/details.html +3 -3
- data/manual/html/disabled.html +9 -3
- data/manual/html/duration.html +3 -3
- data/manual/html/efficiency.html +3 -3
- data/manual/html/effort.html +3 -3
- data/manual/html/email.html +3 -3
- data/manual/html/enabled.html +9 -3
- data/manual/html/end.column.html +3 -3
- data/manual/html/end.html +3 -3
- data/manual/html/end.limit.html +3 -3
- data/manual/html/end.report.html +4 -4
- data/manual/html/end.timesheet.html +3 -3
- data/manual/html/endcredit.html +18 -9
- data/manual/html/epilog.html +6 -4
- data/manual/html/export.html +10 -6
- data/manual/html/extend.html +3 -3
- data/manual/html/fail.html +3 -3
- data/manual/html/fdl.html +3 -3
- data/manual/html/flags.account.html +3 -3
- data/manual/html/flags.html +3 -3
- data/manual/html/flags.journalentry.html +3 -3
- data/manual/html/flags.report.html +6 -4
- data/manual/html/flags.resource.html +3 -3
- data/manual/html/flags.statussheet.html +3 -3
- data/manual/html/flags.task.html +3 -3
- data/manual/html/flags.timesheet.html +3 -3
- data/manual/html/fontcolor.column.html +3 -3
- data/manual/html/footer.html +28 -4
- data/manual/html/formats.html +4 -4
- data/manual/html/functions.html +4 -4
- data/manual/html/gapduration.html +3 -3
- data/manual/html/gaplength.html +4 -4
- data/manual/html/halign.center.html +3 -3
- data/manual/html/halign.column.html +3 -3
- data/manual/html/halign.left.html +3 -3
- data/manual/html/halign.right.html +3 -3
- data/manual/html/hasalert.html +3 -3
- data/manual/html/header.html +28 -4
- data/manual/html/headline.html +6 -6
- data/manual/html/hideaccount.html +73 -0
- data/manual/html/hidejournalentry.html +6 -6
- data/manual/html/hidereport.html +3 -3
- data/manual/html/hideresource.html +4 -4
- data/manual/html/hidetask.html +4 -4
- data/manual/html/icalreport.html +3 -3
- data/manual/html/include.macro.html +4 -4
- data/manual/html/include.project.html +5 -6
- data/manual/html/include.properties.html +5 -97
- data/manual/html/index.html +2 -2
- data/manual/html/inherit.extend.html +3 -3
- data/manual/html/interval1.html +3 -3
- data/manual/html/interval2.html +3 -3
- data/manual/html/interval3.html +3 -3
- data/manual/html/interval4.html +3 -3
- data/manual/html/isactive.html +3 -3
- data/manual/html/ischildof.html +3 -3
- data/manual/html/isdependencyof.html +3 -3
- data/manual/html/isdutyof.html +3 -3
- data/manual/html/isfeatureof.html +3 -3
- data/manual/html/isleaf.html +3 -3
- data/manual/html/ismilestone.html +3 -3
- data/manual/html/isongoing.html +3 -3
- data/manual/html/isresource.html +5 -5
- data/manual/html/{alert level.html → isresponsibilityof.html} +19 -14
- data/manual/html/istask.html +5 -5
- data/manual/html/journalattributes.html +6 -4
- data/manual/html/journalentry.html +3 -3
- data/manual/html/journalmode.html +8 -6
- data/manual/html/leaveallowance.html +139 -0
- data/manual/html/leaves.html +140 -0
- data/manual/html/left.html +30 -6
- data/manual/html/length.html +4 -4
- data/manual/html/limits.allocate.html +5 -32
- data/manual/html/limits.html +3 -3
- data/manual/html/limits.resource.html +3 -3
- data/manual/html/limits.task.html +3 -3
- data/manual/html/listitem.column.html +3 -3
- data/manual/html/listtype.column.html +3 -3
- data/manual/html/loadunit.html +6 -4
- data/manual/html/logicalexpression.html +3 -3
- data/manual/html/logicalflagexpression.html +3 -3
- data/manual/html/macro.html +3 -3
- data/manual/html/managers.html +3 -3
- data/manual/html/mandatory.html +3 -3
- data/manual/html/maxend.html +3 -3
- data/manual/html/maximum.html +3 -3
- data/manual/html/maxstart.html +3 -3
- data/manual/html/milestone.html +3 -3
- data/manual/html/minend.html +3 -3
- data/manual/html/minimum.html +3 -3
- data/manual/html/minstart.html +3 -3
- data/manual/html/monthlymax.html +3 -3
- data/manual/html/monthlymin.html +3 -3
- data/manual/html/navbar.html +23 -5
- data/manual/html/navigator.html +34 -3
- data/manual/html/newtask.html +3 -3
- data/manual/html/nikureport.html +3 -3
- data/manual/html/note.task.html +3 -3
- data/manual/html/now.html +3 -3
- data/manual/html/numberformat.html +4 -4
- data/manual/html/onend.html +3 -3
- data/manual/html/onstart.html +3 -3
- data/manual/html/opennodes.html +6 -4
- data/manual/html/overtime.booking.html +4 -4
- data/manual/html/period.column.html +3 -3
- data/manual/html/period.limit.html +3 -3
- data/manual/html/period.report.html +4 -4
- data/manual/html/period.task.html +3 -3
- data/manual/html/persistent.html +3 -3
- data/manual/html/precedes.html +3 -3
- data/manual/html/priority.html +3 -3
- data/manual/html/priority.timesheet.html +3 -3
- data/manual/html/project.html +4 -4
- data/manual/html/projectid.html +3 -3
- data/manual/html/projectid.task.html +3 -3
- data/manual/html/projectids.html +3 -3
- data/manual/html/projection.html +9 -3
- data/manual/html/prolog.html +6 -4
- data/manual/html/properties.html +193 -9
- data/manual/html/purge.html +5 -5
- data/manual/html/rate.html +3 -3
- data/manual/html/rate.resource.html +3 -3
- data/manual/html/reference.extend.html +3 -3
- data/manual/html/remaining.html +3 -3
- data/manual/html/replace.html +9 -6
- data/manual/html/reportprefix.html +5 -5
- data/manual/html/resource.html +22 -4
- data/manual/html/resourceattributes.html +6 -6
- data/manual/html/resourceprefix.html +3 -3
- data/manual/html/resourcereport.html +311 -8
- data/manual/html/resourceroot.html +6 -4
- data/manual/html/resources.limit.html +4 -4
- data/manual/html/responsible.html +3 -3
- data/manual/html/richtext.extend.html +3 -3
- data/manual/html/right.html +30 -6
- data/manual/html/rollupaccount.html +69 -0
- data/manual/html/rollupresource.html +6 -6
- data/manual/html/rolluptask.html +4 -4
- data/manual/html/scale.column.html +3 -3
- data/manual/html/scenario.html +3 -3
- data/manual/html/scenario.ical.html +3 -3
- data/manual/html/scenarios.export.html +3 -3
- data/manual/html/scenarios.html +6 -4
- data/manual/html/scenariospecific.extend.html +3 -3
- data/manual/html/scheduled.html +3 -3
- data/manual/html/scheduling.html +3 -3
- data/manual/html/select.html +3 -3
- data/manual/html/selfcontained.html +6 -4
- data/manual/html/shift.allocate.html +77 -0
- data/manual/html/shift.html +13 -7
- data/manual/html/shift.resource.html +11 -5
- data/manual/html/shift.task.html +9 -3
- data/manual/html/shift.timesheet.html +4 -4
- data/manual/html/shifts.allocate.html +6 -6
- data/manual/html/shifts.resource.html +3 -3
- data/manual/html/shifts.task.html +3 -3
- data/manual/html/shorttimeformat.html +3 -3
- data/manual/html/sloppy.booking.html +4 -4
- data/manual/html/sloppy.projection.html +12 -6
- data/manual/html/sortaccounts.html +73 -0
- data/manual/html/sortjournalentries.html +8 -6
- data/manual/html/sortresources.html +4 -4
- data/manual/html/sorttasks.html +4 -4
- data/manual/html/start.column.html +3 -3
- data/manual/html/start.html +3 -3
- data/manual/html/start.limit.html +3 -3
- data/manual/html/start.report.html +4 -4
- data/manual/html/startcredit.html +10 -4
- data/manual/html/status.statussheet.html +5 -5
- data/manual/html/status.timesheet.html +5 -5
- data/manual/html/statussheet.html +3 -3
- data/manual/html/statussheetreport.html +10 -6
- data/manual/html/strict.projection.html +10 -4
- data/manual/html/summary.html +3 -3
- data/manual/html/supplement.html +5 -5
- data/manual/html/supplement.resource.html +22 -4
- data/manual/html/supplement.task.html +4 -4
- data/manual/html/tagfile.html +3 -3
- data/manual/html/task.html +3 -3
- data/manual/html/task.statussheet.html +3 -3
- data/manual/html/task.timesheet.html +3 -3
- data/manual/html/taskattributes.html +3 -3
- data/manual/html/taskprefix.html +3 -3
- data/manual/html/taskreport.html +347 -8
- data/manual/html/taskroot.html +6 -4
- data/manual/html/text.extend.html +3 -3
- data/manual/html/textreport.html +333 -8
- data/manual/html/timeformat.html +4 -4
- data/manual/html/timeoff.nikureport.html +3 -3
- data/manual/html/timesheet.html +3 -3
- data/manual/html/timesheetreport.html +10 -6
- data/manual/html/timezone.export.html +3 -3
- data/manual/html/timezone.html +3 -3
- data/manual/html/timezone.report.html +6 -4
- data/manual/html/timezone.shift.html +3 -3
- data/manual/html/timingresolution.html +3 -3
- data/manual/html/title.column.html +3 -3
- data/manual/html/title.html +4 -4
- data/manual/html/toc.html +1705 -658
- data/manual/html/tooltip.column.html +3 -3
- data/manual/html/trackingscenario.html +3 -3
- data/manual/html/treelevel.html +3 -3
- data/manual/html/vacation.html +3 -3
- data/manual/html/vacation.resource.html +4 -4
- data/manual/html/vacation.shift.html +4 -4
- data/manual/html/warn.html +3 -3
- data/manual/html/weeklymax.html +3 -3
- data/manual/html/weeklymin.html +3 -3
- data/manual/html/weekstartsmonday.html +3 -3
- data/manual/html/weekstartssunday.html +3 -3
- data/manual/html/width.column.html +3 -3
- data/manual/html/work.html +3 -3
- data/manual/html/workinghours.project.html +3 -3
- data/manual/html/workinghours.resource.html +3 -3
- data/manual/html/workinghours.shift.html +3 -3
- data/manual/html/yearlyworkingdays.html +4 -4
- data/spec/ICalendar_spec.rb +4 -2
- data/spec/IntervalList_spec.rb +1 -1
- data/spec/ProjectBroker_spec.rb +2 -6
- data/spec/StatusSheets_spec.rb +1 -1
- data/spec/TernarySearchTree_spec.rb +2 -2
- data/spec/TimeSheets_spec.rb +1 -1
- data/spec/Tj3Daemon_spec.rb +1 -1
- data/spec/Tj3_spec.rb +1 -1
- data/spec/support/DaemonControl.rb +1 -1
- data/spec/support/spec_helper.rb +19 -0
- data/taskjuggler.gemspec +1 -0
- data/test/MessageChecker.rb +1 -1
- data/test/ReferenceGenerator.rb +1 -1
- data/test/TestSuite/CSV-Reports/Leave.tjp +37 -0
- data/test/TestSuite/CSV-Reports/celltext.tjp +1 -1
- data/test/TestSuite/CSV-Reports/efficiency.tjp +20 -0
- data/test/TestSuite/CSV-Reports/headcount.tjp +31 -0
- data/test/TestSuite/CSV-Reports/refs/Leave.csv +5 -0
- data/test/TestSuite/CSV-Reports/refs/alert.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/celltext.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/efficiency.csv +5 -0
- data/test/TestSuite/CSV-Reports/refs/headcount.csv +4 -0
- data/test/TestSuite/CSV-Reports/refs/sortByTree.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/sortBy_duration.down.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/sortBy_effort.up.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/sortBy_plan.start.down.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/taskreport.csv +6 -0
- data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +14 -0
- data/test/TestSuite/CSV-Reports/resourcereport.tjp +1 -1
- data/test/TestSuite/CSV-Reports/resourcereport_with_tasks.tjp +1 -1
- data/test/TestSuite/CSV-Reports/sortByTree.tjp +1 -1
- data/test/TestSuite/CSV-Reports/sortBy_plan.start.down.tjp +1 -1
- data/test/TestSuite/CSV-Reports/taskreport.tjp +1 -1
- data/test/TestSuite/CSV-Reports/taskreport_with_resources.tjp +1 -1
- data/test/TestSuite/Export-Reports/refs/AccountReport.tjp +1089 -0
- data/test/TestSuite/Export-Reports/refs/AlertLevels.tjp +24 -0
- data/test/TestSuite/Export-Reports/refs/Complete.tjp +5 -25
- data/test/TestSuite/Export-Reports/refs/navigator.tjp +58 -0
- data/test/TestSuite/Export-Reports/refs/template.tjp +142 -0
- data/test/TestSuite/Export-Reports/refs/textreport.tjp +19 -0
- data/test/TestSuite/ReportGenerator/Correct/Alerts.tjp +26 -7
- data/test/TestSuite/ReportGenerator/Correct/refs/Alerts-1.csv +177 -141
- data/test/TestSuite/ReportGenerator/Correct/refs/FTE-1.csv +1 -1
- data/test/TestSuite/Scheduler/Correct/Allocate.tjp +2 -2
- data/test/TestSuite/Scheduler/Correct/Shift2.tjp +4 -4
- data/test/TestSuite/Syntax/Correct/Account.tjp +23 -10
- data/test/TestSuite/Syntax/Correct/AccountReport.tjp +74 -0
- data/test/TestSuite/Syntax/Correct/AdoptedTasks.tjp +4 -0
- data/test/TestSuite/Syntax/Correct/AlertLevels.tjp +25 -0
- data/test/TestSuite/Syntax/Correct/Celltext.tjp +3 -3
- data/test/TestSuite/Syntax/Correct/Complete.tjp +8 -5
- data/test/TestSuite/Syntax/Correct/Leave.tjp +37 -0
- data/test/TestSuite/Syntax/Correct/Reports.tjp +4 -4
- data/test/TestSuite/Syntax/Correct/Shift.tjp +4 -4
- data/test/TestSuite/Syntax/Correct/manual2example.rb +4 -3
- data/test/TestSuite/Syntax/Correct/navigator.tjp +31 -0
- data/test/TestSuite/Syntax/Correct/template.tjp +338 -0
- data/test/TestSuite/Syntax/Correct/textreport.tjp +21 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +12 -10
- data/test/TestSuite/Syntax/Errors/{adopt_duplicate_child.tjp → adopt_duplicate_child-1.tjp} +0 -0
- data/test/TestSuite/Syntax/Errors/{adopt_common_root.tjp → adopt_duplicate_child-2.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/{adopt_duplicate_parent.tjp → adopt_duplicate_child-3.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/adopt_self.tjp +7 -0
- data/test/TestSuite/Syntax/Errors/alert_level_redef.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/alert_name_redef.tjp +8 -0
- data/test/TestSuite/Syntax/Errors/too_few_alert_levels.tjp +5 -0
- data/test/TjpGen.rb +1 -1
- data/test/all.rb +1 -1
- data/test/test_AlgorithmDiff.rb +1 -1
- data/test/test_BatchProcessor.rb +23 -10
- data/test/test_CSV-Reports.rb +1 -1
- data/test/test_CSVFile.rb +1 -1
- data/test/test_CollisionDetector.rb +1 -1
- data/test/test_Export-Reports.rb +1 -1
- data/test/test_Journal.rb +42 -15
- data/test/test_Limits.rb +1 -1
- data/test/test_LogicalExpression.rb +1 -1
- data/test/test_MacroTable.rb +8 -3
- data/test/test_Project.rb +1 -1
- data/test/test_ProjectFileScanner.rb +1 -1
- data/test/test_PropertySet.rb +1 -1
- data/test/test_Query.rb +1 -1
- data/test/test_RealFormat.rb +1 -1
- data/test/test_ReportGenerator.rb +1 -1
- data/test/test_RichText.rb +1 -1
- data/test/test_Scheduler.rb +1 -1
- data/test/test_ShiftAssignments.rb +1 -1
- data/test/test_SimpleQueryExpander.rb +1 -1
- data/test/test_Syntax.rb +1 -1
- data/test/test_TextFormatter.rb +1 -1
- data/test/test_TjTime.rb +1 -1
- data/test/test_TjpExample.rb +1 -1
- data/test/test_URLParameter.rb +1 -1
- data/test/test_UTF8String.rb +1 -1
- data/test/test_WorkingHours.rb +1 -1
- data/test/test_deep_copy.rb +1 -1
- metadata +318 -248
- data/test/TestSuite/Syntax/Errors/purge_no_list.tjp +0 -8
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = ProjectFileParser.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -237,20 +237,37 @@ class TaskJuggler
|
|
|
237
237
|
# type. +sourceFileInfo+ is a SourceFileInfo of the report definition. The
|
|
238
238
|
# method returns the newly created Report.
|
|
239
239
|
def newReport(id, name, type, sourceFileInfo)
|
|
240
|
+
# If there is no parent property and the report prefix is not empty, the
|
|
241
|
+
# reportprefix defines the parent property.
|
|
242
|
+
if @property.nil? && !@reportprefix.empty?
|
|
243
|
+
@property = @project.report(@reportprefix)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# Report IDs must be unique. If an ID was provided, check if it exists
|
|
247
|
+
# already.
|
|
248
|
+
if id
|
|
249
|
+
# If we have a scope property, we need to prepend the ID of the scope
|
|
250
|
+
# property to the provided ID.
|
|
251
|
+
id = (@property ? @property.fullId + '.' : '') + @val[1]
|
|
252
|
+
|
|
253
|
+
if @project.report(id)
|
|
254
|
+
error('report_exists', "report #{id} has already been defined.",
|
|
255
|
+
sourceFileInfo, @property)
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
240
259
|
@reportCounter += 1
|
|
241
|
-
if name != '.'
|
|
260
|
+
if name != '.' && name != ''
|
|
242
261
|
if @project.reportByName(name)
|
|
243
262
|
error('report_redefinition',
|
|
244
263
|
"A report with the name #{name} has already been defined.")
|
|
245
264
|
end
|
|
246
265
|
end
|
|
247
266
|
@property = Report.new(@project, id || "report#{@reportCounter}",
|
|
248
|
-
name,
|
|
267
|
+
name, @property)
|
|
249
268
|
@property.typeSpec = type
|
|
250
269
|
@property.sourceFileInfo = sourceFileInfo
|
|
251
|
-
@property.set('formats', [ :tjp ])
|
|
252
270
|
@property.inheritAttributes
|
|
253
|
-
@property
|
|
254
271
|
end
|
|
255
272
|
|
|
256
273
|
# If the @limitResources list is not empty, we have to create a Limits
|
|
@@ -394,6 +411,11 @@ class TaskJuggler
|
|
|
394
411
|
@cr.setLastSyntaxToken(idx)
|
|
395
412
|
end
|
|
396
413
|
|
|
414
|
+
# Specify the support level for the current pattern.
|
|
415
|
+
def level(level)
|
|
416
|
+
@cr.setSupportLevel(level)
|
|
417
|
+
end
|
|
418
|
+
|
|
397
419
|
# Add a reference to another pattern. This information is only used to
|
|
398
420
|
# generate the documentation for the patterns of this rule.
|
|
399
421
|
def also(seeAlso)
|
|
@@ -454,6 +476,18 @@ class TaskJuggler
|
|
|
454
476
|
@property = nil
|
|
455
477
|
end
|
|
456
478
|
|
|
479
|
+
# This method most be used instead of the += operator for all list
|
|
480
|
+
# attributes. += will always return an Array object. This will cause
|
|
481
|
+
# trouble with the list attributes that are not plain Arrays.
|
|
482
|
+
def appendScListAttribute(attrId, list)
|
|
483
|
+
list.each do |v|
|
|
484
|
+
@property[attrId, @scenarioIdx] << v
|
|
485
|
+
end
|
|
486
|
+
# The << operator does not set the 'provided' flag. Just do a self
|
|
487
|
+
# assignment to trigget the flag to get set.
|
|
488
|
+
@property[attrId, @scenarioIdx] = @property[attrId, @scenarioIdx]
|
|
489
|
+
end
|
|
490
|
+
|
|
457
491
|
end
|
|
458
492
|
|
|
459
493
|
end
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = ProjectFileScanner.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = PropertyList.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
# published by the Free Software Foundation.
|
|
12
12
|
#
|
|
13
13
|
|
|
14
|
+
require 'taskjuggler/PTNProxy'
|
|
15
|
+
|
|
14
16
|
class TaskJuggler
|
|
15
17
|
|
|
16
18
|
# The PropertyList is a utility class that can be used to hold a list of
|
|
@@ -60,6 +62,16 @@ class TaskJuggler
|
|
|
60
62
|
@items.method(func).call(*args, &block)
|
|
61
63
|
end
|
|
62
64
|
|
|
65
|
+
def includeAdopted
|
|
66
|
+
adopted = []
|
|
67
|
+
@items.each do |p|
|
|
68
|
+
p.adoptees.each do |ap|
|
|
69
|
+
adopted += includeAdoptedR(ap, p)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
append(adopted)
|
|
73
|
+
end
|
|
74
|
+
|
|
63
75
|
def to_ary
|
|
64
76
|
@items.dup
|
|
65
77
|
end
|
|
@@ -165,6 +177,18 @@ class TaskJuggler
|
|
|
165
177
|
|
|
166
178
|
private
|
|
167
179
|
|
|
180
|
+
def includeAdoptedR(property, parent)
|
|
181
|
+
# Create a proxy for the current PropertyTreeNode and add it to a list.
|
|
182
|
+
adopted = [ parentProxy = PTNProxy.new(property, parent) ]
|
|
183
|
+
|
|
184
|
+
# Add proxies for all children (adopted or not) and their children.
|
|
185
|
+
property.kids.each do |p|
|
|
186
|
+
adopted += includeAdoptedR(p, parentProxy)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
adopted
|
|
190
|
+
end
|
|
191
|
+
|
|
168
192
|
# Append a new sorting level to the existing levels.
|
|
169
193
|
def addSortingCriteria(criteria, up, scIdx)
|
|
170
194
|
unless @propertySet.knownAttribute?(criteria) ||
|
|
@@ -214,7 +238,7 @@ class TaskJuggler
|
|
|
214
238
|
@items.sort! do |a, b|
|
|
215
239
|
res = 0
|
|
216
240
|
@sortingLevels.times do |i|
|
|
217
|
-
if @query
|
|
241
|
+
if @query && @sortingCriteria[i] != 'tree'
|
|
218
242
|
# In case we have a Query reference, we get the two values with this
|
|
219
243
|
# query.
|
|
220
244
|
@query.scenarioIdx = @scenarioIdx[i] < 0 ? nil : @scenarioIdx[i]
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = PropertySet.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -193,6 +193,12 @@ class TaskJuggler
|
|
|
193
193
|
property = prop
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
+
# Iterate over all properties and eliminate references to this the
|
|
197
|
+
# PropertyTreeNode to be removed.
|
|
198
|
+
@properties.each do |p|
|
|
199
|
+
p.removeReferences(p)
|
|
200
|
+
end
|
|
201
|
+
|
|
196
202
|
# Recursively remove all sub-nodes. The children list is modified during
|
|
197
203
|
# the call, so we can't use an iterator here.
|
|
198
204
|
until property.children.empty? do
|
|
@@ -205,6 +211,7 @@ class TaskJuggler
|
|
|
205
211
|
# Remove this node from the child list of the parent node.
|
|
206
212
|
property.parent.children.delete(property) if property.parent
|
|
207
213
|
|
|
214
|
+
|
|
208
215
|
property
|
|
209
216
|
end
|
|
210
217
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = PropertyTreeNode.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -135,34 +135,30 @@ class TaskJuggler
|
|
|
135
135
|
self
|
|
136
136
|
end
|
|
137
137
|
|
|
138
|
+
# We often use PTNProxy objects to represent PropertyTreeNode objects. The
|
|
139
|
+
# proxy usually does a good job acting like a PropertyTreeNode. But in
|
|
140
|
+
# some situations, we want to make sure to operate on the PropertyTreeNode
|
|
141
|
+
# and not the PTNProxy. Both classes provide a ptn() method that always
|
|
142
|
+
# return the PropertyTreeNode.
|
|
143
|
+
def ptn
|
|
144
|
+
self
|
|
145
|
+
end
|
|
146
|
+
|
|
138
147
|
# Adopt _property_ as a step child. Also register the new relationship
|
|
139
148
|
# with the child.
|
|
140
149
|
def adopt(property)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
# ancestors.
|
|
145
|
-
if root == property.root
|
|
146
|
-
error('adopt_common_root',
|
|
147
|
-
"The adoptee #{property.fullId} and the parent #{fullId} " +
|
|
148
|
-
"may not share common ancestors.")
|
|
150
|
+
# A property cannot adopt itself.
|
|
151
|
+
if self == property
|
|
152
|
+
error('adopt_self', 'A property cannot adopt itself')
|
|
149
153
|
end
|
|
150
154
|
|
|
151
|
-
#
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if adoptee.ancestors.include?(property)
|
|
155
|
+
# A top level task must never contain the same leaf task more then once!
|
|
156
|
+
allOfRoot = root.all
|
|
157
|
+
property.allLeaves.each do |adoptee|
|
|
158
|
+
if allOfRoot.include?(adoptee)
|
|
156
159
|
error('adopt_duplicate_child',
|
|
157
|
-
"The
|
|
158
|
-
"
|
|
159
|
-
end
|
|
160
|
-
# Check if the already adopted nodes are an ancestor of the to be
|
|
161
|
-
# adopted node.
|
|
162
|
-
if property.ancestors.include?(adoptee)
|
|
163
|
-
error('adopt_duplicate_parent',
|
|
164
|
-
"The parent #{adoptee.fullId} of #{property.fullId} " +
|
|
165
|
-
"has already been adopted by #{fullId}.")
|
|
160
|
+
"The task '#{adoptee.fullId}' has already been adopted by " +
|
|
161
|
+
"property '#{root.fullId}' or any of its sub-properties.")
|
|
166
162
|
end
|
|
167
163
|
end
|
|
168
164
|
|
|
@@ -177,7 +173,6 @@ class TaskJuggler
|
|
|
177
173
|
return if @stepParents.include?(property)
|
|
178
174
|
|
|
179
175
|
@stepParents << property
|
|
180
|
-
property.adopt(self)
|
|
181
176
|
end
|
|
182
177
|
|
|
183
178
|
# Return a list of all children including adopted kids.
|
|
@@ -202,6 +197,13 @@ class TaskJuggler
|
|
|
202
197
|
@attributes, @scenarioAttributes = backup
|
|
203
198
|
end
|
|
204
199
|
|
|
200
|
+
# Remove any references in the stored data that references the _property_.
|
|
201
|
+
def removeReferences(property)
|
|
202
|
+
@children.delete(property)
|
|
203
|
+
@adoptees.delete(property)
|
|
204
|
+
@stepParents.delete(property)
|
|
205
|
+
end
|
|
206
|
+
|
|
205
207
|
# Return the index of the child _node_.
|
|
206
208
|
def levelSeqNo(node)
|
|
207
209
|
@children.index(node) + 1
|
|
@@ -258,7 +260,7 @@ class TaskJuggler
|
|
|
258
260
|
# Returns a list of this node and all transient sub nodes.
|
|
259
261
|
def all
|
|
260
262
|
res = [ self ]
|
|
261
|
-
|
|
263
|
+
kids.each do |c|
|
|
262
264
|
res = res.concat(c.all)
|
|
263
265
|
end
|
|
264
266
|
res
|
|
@@ -266,11 +268,11 @@ class TaskJuggler
|
|
|
266
268
|
|
|
267
269
|
# Return a list of all leaf nodes of this node.
|
|
268
270
|
def allLeaves(withoutSelf = false)
|
|
271
|
+
res = []
|
|
269
272
|
if leaf?
|
|
270
|
-
res
|
|
273
|
+
res << self unless withoutSelf
|
|
271
274
|
else
|
|
272
|
-
|
|
273
|
-
@children.each do |c|
|
|
275
|
+
kids.each do |c|
|
|
274
276
|
res += c.allLeaves
|
|
275
277
|
end
|
|
276
278
|
end
|
|
@@ -553,8 +555,10 @@ class TaskJuggler
|
|
|
553
555
|
journal = @project['journal']
|
|
554
556
|
query.sortable = query.numerical = alert =
|
|
555
557
|
journal.alertLevel(query.end, self, query.hideJournalEntry)
|
|
556
|
-
|
|
557
|
-
|
|
558
|
+
alertLevel = @project['alertLevels'][alert]
|
|
559
|
+
query.string = alertLevel.name
|
|
560
|
+
rText = "<fcol:#{alertLevel.color}><nowiki>#{alertLevel.name}" +
|
|
561
|
+
"</nowiki></fcol>"
|
|
558
562
|
unless (rti = RichText.new(rText, RTFHandlers.create(@project),
|
|
559
563
|
@project.messageHandler).
|
|
560
564
|
generateIntermediateFormat)
|
|
@@ -645,8 +649,8 @@ class TaskJuggler
|
|
|
645
649
|
# provided by the class *Scenario classes. In case we can't find a function
|
|
646
650
|
# called for the base class we try to find it in corresponding *Scenario
|
|
647
651
|
# class.
|
|
648
|
-
def method_missing(func, scenarioIdx, *args)
|
|
649
|
-
@data[scenarioIdx].
|
|
652
|
+
def method_missing(func, scenarioIdx, *args, &block)
|
|
653
|
+
@data[scenarioIdx].send(func, *args, &block)
|
|
650
654
|
end
|
|
651
655
|
|
|
652
656
|
def error(id, text)
|
data/lib/taskjuggler/Query.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = Query.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = RealFormat.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -63,8 +63,10 @@ class TaskJuggler
|
|
|
63
63
|
intNumber = '0' * (@fractionDigits - intNumber.length + 1) + intNumber
|
|
64
64
|
end
|
|
65
65
|
intPart = intNumber[0..-(@fractionDigits + 1)]
|
|
66
|
+
# Determinate the fractional part
|
|
66
67
|
fracPart =
|
|
67
|
-
@fractionDigits > 0 ?
|
|
68
|
+
@fractionDigits > 0 ? @fractionSeparator +
|
|
69
|
+
intNumber[-(@fractionDigits)..-1] : ''
|
|
68
70
|
|
|
69
71
|
if @thousandsSeparator.empty?
|
|
70
72
|
out = intPart
|
data/lib/taskjuggler/Resource.rb
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = Resource.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -37,8 +37,8 @@ class TaskJuggler
|
|
|
37
37
|
# provided by the class ResourceScenario. In case we can't find a
|
|
38
38
|
# function called for the Resource class we try to find it in
|
|
39
39
|
# ResourceScenario.
|
|
40
|
-
def method_missing(func, scenarioIdx, *args)
|
|
41
|
-
@data[scenarioIdx].method(func).call(*args)
|
|
40
|
+
def method_missing(func, scenarioIdx, *args, &block)
|
|
41
|
+
@data[scenarioIdx].method(func).call(*args, &block)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def query_dashboard(query)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
#
|
|
4
4
|
# = ResourceScenario.rb -- The TaskJuggler III Project Management Software
|
|
5
5
|
#
|
|
6
|
-
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
7
|
# by Chris Schlaeger <chris@linux.com>
|
|
8
8
|
#
|
|
9
9
|
# This program is free software; you can redistribute it and/or modify
|
|
@@ -24,13 +24,18 @@ class TaskJuggler
|
|
|
24
24
|
# nil: Value has not been determined yet.
|
|
25
25
|
# Task: A reference to a Task object
|
|
26
26
|
# Bit 0: Reserved
|
|
27
|
-
# Bit 1: 0: Work time
|
|
28
|
-
# 1:
|
|
29
|
-
# Bit 2 - 5: 0: No
|
|
30
|
-
# 1:
|
|
31
|
-
# 2
|
|
32
|
-
#
|
|
33
|
-
#
|
|
27
|
+
# Bit 1: 0: Work time (as defined by working hours)
|
|
28
|
+
# 1: No work time (as defined by working hours)
|
|
29
|
+
# Bit 2 - 5: 0: No holiday or leave time
|
|
30
|
+
# 1: Public holiday (holiday)
|
|
31
|
+
# 2: Annual leave
|
|
32
|
+
# 3: Special leave
|
|
33
|
+
# 4: Sick leave
|
|
34
|
+
# 5: unpaid leave
|
|
35
|
+
# 6: blocked for other projects
|
|
36
|
+
# 7 - 15: Reserved
|
|
37
|
+
# Bit 6 - 7: Reserved
|
|
38
|
+
# Bit 8: 0: No global override
|
|
34
39
|
# 1: Override global setting
|
|
35
40
|
# The scoreboard is only created when needed to save memory for projects
|
|
36
41
|
# which read-in the coporate employee database but only need a small
|
|
@@ -49,9 +54,9 @@ class TaskJuggler
|
|
|
49
54
|
# Attributed are only really created when they are accessed the first
|
|
50
55
|
# time. So make sure some needed attributes really exist so we don't
|
|
51
56
|
# have to check for existance each time we access them.
|
|
52
|
-
%w( alloctdeffort criticalness directreports duties efficiency
|
|
57
|
+
%w( alloctdeffort chargeset criticalness directreports duties efficiency
|
|
53
58
|
effort limits managers rate reports shifts
|
|
54
|
-
|
|
59
|
+
leaves leaveallowances workinghours ).each do |attr|
|
|
55
60
|
@property[attr, @scenarioIdx]
|
|
56
61
|
end
|
|
57
62
|
|
|
@@ -241,6 +246,26 @@ class TaskJuggler
|
|
|
241
246
|
book(sbIdx, booking.task, true)
|
|
242
247
|
end
|
|
243
248
|
|
|
249
|
+
# Compute the annual leave days within the period specified by the
|
|
250
|
+
# _query_. The result is in days.
|
|
251
|
+
def query_annualleave(query)
|
|
252
|
+
query.sortable = query.numerical = val =
|
|
253
|
+
getLeave(query.startIdx, query.endIdx, :annual)
|
|
254
|
+
query.string = query.scaleLoad(val)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def query_annualleavebalance(query)
|
|
258
|
+
if @property.leaf?
|
|
259
|
+
leave = getLeave(query.startIdx, query.endIdx, :annual)
|
|
260
|
+
allowanceSlots = @leaveallowances.balance(:annual, query.start,
|
|
261
|
+
query.end)
|
|
262
|
+
allowance = @project.slotsToDays(allowanceSlots)
|
|
263
|
+
query.sortable = query.numerical = val = allowance - leave
|
|
264
|
+
query.string = query.scaleLoad(val)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
|
|
244
269
|
# Compute the cost generated by this Resource for a given Account during a
|
|
245
270
|
# given interval. If a Task is provided as scopeProperty only the turnover
|
|
246
271
|
# directly assiciated with the Task is taken into account.
|
|
@@ -248,7 +273,7 @@ class TaskJuggler
|
|
|
248
273
|
if query.costAccount
|
|
249
274
|
query.sortable = query.numerical = cost =
|
|
250
275
|
turnover(query.startIdx, query.endIdx, query.costAccount,
|
|
251
|
-
query.scopeProperty)
|
|
276
|
+
query.scopeProperty, true)
|
|
252
277
|
query.string = query.currencyFormat.format(cost)
|
|
253
278
|
else
|
|
254
279
|
query.string = 'No \'balance\' defined!'
|
|
@@ -292,13 +317,31 @@ class TaskJuggler
|
|
|
292
317
|
# probably don't need to compute this for every resource.
|
|
293
318
|
globalWorkSlots = @project.getWorkSlots(query.startIdx, query.endIdx)
|
|
294
319
|
workSlots = getWorkSlots(query.startIdx, query.endIdx)
|
|
295
|
-
|
|
320
|
+
if globalWorkSlots > 0
|
|
321
|
+
fte = (workSlots.to_f / globalWorkSlots) * @efficiency
|
|
322
|
+
end
|
|
296
323
|
end
|
|
297
324
|
|
|
298
325
|
query.sortable = query.numerical = fte
|
|
299
326
|
query.string = query.numberFormat.format(fte)
|
|
300
327
|
end
|
|
301
328
|
|
|
329
|
+
# The headcount of the resource or group.
|
|
330
|
+
def query_headcount(query)
|
|
331
|
+
headcount = 0
|
|
332
|
+
if @property.container?
|
|
333
|
+
@property.kids.each do |resource|
|
|
334
|
+
resource.query_headcount(@scenarioIdx, query)
|
|
335
|
+
headcount += query.to_num
|
|
336
|
+
end
|
|
337
|
+
else
|
|
338
|
+
headcount += @efficiency.round
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
query.sortable = query.numerical = headcount
|
|
342
|
+
query.string = query.numberFormat.format(headcount)
|
|
343
|
+
end
|
|
344
|
+
|
|
302
345
|
# Get the rate of the resource.
|
|
303
346
|
def query_rate(query)
|
|
304
347
|
query.sortable = query.numerical = r = rate
|
|
@@ -319,14 +362,77 @@ class TaskJuggler
|
|
|
319
362
|
end
|
|
320
363
|
end
|
|
321
364
|
|
|
322
|
-
#
|
|
365
|
+
# Compute the sick leave days within the period specified by the
|
|
366
|
+
# _query_. The result is in days.
|
|
367
|
+
def query_sickleave(query)
|
|
368
|
+
query.sortable = query.numerical = val =
|
|
369
|
+
getLeave(query.startIdx, query.endIdx, :sick)
|
|
370
|
+
query.string = query.scaleLoad(val)
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
# Compute the special leave days within the period specified by the
|
|
374
|
+
# _query_. The result is in days.
|
|
375
|
+
def query_specialleave(query)
|
|
376
|
+
query.sortable = query.numerical = val =
|
|
377
|
+
getLeave(query.startIdx, query.endIdx, :special)
|
|
378
|
+
query.string = query.scaleLoad(val)
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# The work time of the Resource that was blocked by leaves during the
|
|
323
382
|
# specified TimeInterval. The result is in working days (effort).
|
|
324
|
-
def
|
|
383
|
+
def query_timeoffdays(query)
|
|
325
384
|
query.sortable = query.numerical = time =
|
|
326
|
-
|
|
385
|
+
getTimeOffDays(query.startIdx, query.endIdx)
|
|
327
386
|
query.string = query.scaleLoad(time)
|
|
328
387
|
end
|
|
329
388
|
|
|
389
|
+
# Compute the unpaid leave days within the period specified by the
|
|
390
|
+
# _query_. The result is in days.
|
|
391
|
+
def query_unpaidleave(query)
|
|
392
|
+
query.sortable = query.numerical = val =
|
|
393
|
+
getLeave(query.startIdx, query.endIdx, :unpaid)
|
|
394
|
+
query.string = query.scaleLoad(val)
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# A generic tree iterator that recursively accumulates the result of the
|
|
398
|
+
# block for each leaf object.
|
|
399
|
+
def treeSum(startIdx, endIdx, *args, &block)
|
|
400
|
+
cacheTag = "#{self.class}.#{caller[0][/`.*'/][1..-2]}"
|
|
401
|
+
treeSumR(cacheTag, startIdx, endIdx, *args, &block)
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
# Recursing method for treeSum.
|
|
405
|
+
def treeSumR(cacheTag, startIdx, endIdx, *args, &block)
|
|
406
|
+
# Check if the value to be computed is already in the data cache. If so,
|
|
407
|
+
# return it. Otherwise we have to compute it first and then store it in
|
|
408
|
+
# the cache. We use the signature of the method that called treeSum()
|
|
409
|
+
# and its arguments together with 'self' as index to the cache.
|
|
410
|
+
@dCache.cached(self, cacheTag, startIdx, endIdx, *args) do
|
|
411
|
+
if @property.container?
|
|
412
|
+
sum = 0.0
|
|
413
|
+
# Iterate over all the kids and accumulate the result of the
|
|
414
|
+
# recursively called method.
|
|
415
|
+
@property.kids.each do |resource|
|
|
416
|
+
sum += resource.treeSumR(@scenarioIdx, cacheTag, startIdx, endIdx,
|
|
417
|
+
*args, &block)
|
|
418
|
+
end
|
|
419
|
+
sum
|
|
420
|
+
else
|
|
421
|
+
instance_eval(&block)
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
# Returns the number of leave days for the period described by _startIdx_
|
|
427
|
+
# and _endIdx_ for the given _type_ of leave.
|
|
428
|
+
def getLeave(startIdx, endIdx, type)
|
|
429
|
+
treeSum(startIdx, endIdx, type) do
|
|
430
|
+
@project.convertToDailyLoad(@project['scheduleGranularity'] *
|
|
431
|
+
getLeaveSlots(startIdx, endIdx, type))
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
|
|
330
436
|
# Returns the work of the resource (and its children) weighted by their
|
|
331
437
|
# efficiency.
|
|
332
438
|
def getEffectiveWork(startIdx, endIdx, task = nil)
|
|
@@ -337,10 +443,6 @@ class TaskJuggler
|
|
|
337
443
|
# The unique key we use to address the result in the cache.
|
|
338
444
|
@dCache.cached(self, :ResourceScenarioEffectiveWork, startIdx, endIdx,
|
|
339
445
|
task) do
|
|
340
|
-
# Convert the interval dates to indexes if needed.
|
|
341
|
-
startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
|
|
342
|
-
endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
|
|
343
|
-
|
|
344
446
|
work = 0.0
|
|
345
447
|
if @property.container?
|
|
346
448
|
@property.kids.each do |resource|
|
|
@@ -360,96 +462,66 @@ class TaskJuggler
|
|
|
360
462
|
|
|
361
463
|
# Returns the allocated accumulated time of this resource and its children.
|
|
362
464
|
def getAllocatedTime(startIdx, endIdx, task = nil)
|
|
363
|
-
|
|
364
|
-
startIdx = @project.dateToIdx(startIdx) if startIdx.is_a?(TjTime)
|
|
365
|
-
endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
|
|
366
|
-
|
|
367
|
-
time = 0
|
|
368
|
-
if @property.container?
|
|
369
|
-
@property.kids.each do |resource|
|
|
370
|
-
time += resource.getAllocatedTime(@scenarioIdx, startIdx, endIdx, task)
|
|
371
|
-
end
|
|
372
|
-
else
|
|
465
|
+
treeSum(startIdx, endIdx, task) do
|
|
373
466
|
return 0 if @scoreboard.nil?
|
|
374
467
|
|
|
375
|
-
|
|
468
|
+
@project.convertToDailyLoad(@project['scheduleGranularity'] *
|
|
376
469
|
getAllocatedSlots(startIdx, endIdx, task))
|
|
377
470
|
end
|
|
378
|
-
time
|
|
379
471
|
end
|
|
380
472
|
|
|
381
473
|
# Return the unallocated work time (in seconds) of the resource and its
|
|
382
474
|
# children.
|
|
383
475
|
def getEffectiveFreeTime(startIdx, endIdx)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
endIdx = @project.dateToIdx(endIdx) if endIdx.is_a?(TjTime)
|
|
387
|
-
|
|
388
|
-
freeTime = 0
|
|
389
|
-
if @property.container?
|
|
390
|
-
@property.kids.each do |resource|
|
|
391
|
-
freeTime += resource.getEffectiveFreeTime(@scenarioIdx, startIdx,
|
|
392
|
-
endIdx)
|
|
393
|
-
end
|
|
394
|
-
else
|
|
395
|
-
freeTime = getFreeSlots(startIdx, endIdx) *
|
|
396
|
-
@project['scheduleGranularity']
|
|
476
|
+
treeSum(startIdx, endIdx) do
|
|
477
|
+
getFreeSlots(startIdx, endIdx) * @project['scheduleGranularity']
|
|
397
478
|
end
|
|
398
|
-
freeTime
|
|
399
479
|
end
|
|
400
480
|
|
|
401
481
|
# Return the unallocated work of the resource and its children weighted by
|
|
402
482
|
# their efficiency.
|
|
403
483
|
def getEffectiveFreeWork(startIdx, endIdx)
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
work = 0.0
|
|
409
|
-
if @property.container?
|
|
410
|
-
@property.kids.each do |resource|
|
|
411
|
-
work += resource.getEffectiveFreeWork(@scenarioIdx, startIdx, endIdx)
|
|
412
|
-
end
|
|
413
|
-
else
|
|
414
|
-
work = @project.convertToDailyLoad(
|
|
415
|
-
getFreeSlots(startIdx, endIdx) *
|
|
416
|
-
@project['scheduleGranularity']) * @efficiency
|
|
484
|
+
treeSum(startIdx, endIdx) do
|
|
485
|
+
@project.convertToDailyLoad(getFreeSlots(startIdx, endIdx) *
|
|
486
|
+
@project['scheduleGranularity']) *
|
|
487
|
+
@efficiency
|
|
417
488
|
end
|
|
418
|
-
work
|
|
419
489
|
end
|
|
420
490
|
|
|
421
|
-
# Return the number of working days that are blocked by
|
|
422
|
-
def
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
vacationDays = 0.0
|
|
428
|
-
if @property.container?
|
|
429
|
-
@property.kids.each do |resource|
|
|
430
|
-
vacationDays += resource.getVacationDays(@scenarioIdx,
|
|
431
|
-
startIdx, endIdx)
|
|
432
|
-
end
|
|
433
|
-
else
|
|
434
|
-
initScoreboard if @scoreboard.nil?
|
|
435
|
-
|
|
436
|
-
vacationDays = @project.convertToDailyLoad(
|
|
437
|
-
getVacationSlots(startIdx, endIdx) *
|
|
438
|
-
@project['scheduleGranularity']) * @efficiency
|
|
491
|
+
# Return the number of working days that are blocked by leaves.
|
|
492
|
+
def getTimeOffDays(startIdx, endIdx)
|
|
493
|
+
treeSum(startIdx, endIdx) do
|
|
494
|
+
@project.convertToDailyLoad(getTimeOffSlots(startIdx, endIdx) *
|
|
495
|
+
@project['scheduleGranularity']) *
|
|
496
|
+
@efficiency
|
|
439
497
|
end
|
|
440
|
-
vacationDays
|
|
441
498
|
end
|
|
442
499
|
|
|
443
|
-
def turnover(startIdx, endIdx, account, task = nil)
|
|
500
|
+
def turnover(startIdx, endIdx, account, task = nil, includeKids = false)
|
|
444
501
|
amount = 0.0
|
|
445
|
-
if @property.container?
|
|
502
|
+
if @property.container? && includeKids
|
|
446
503
|
@property.kids.each do |child|
|
|
447
|
-
amount += child.turnover(@scenarioIdx, startIdx, endIdx, account,
|
|
504
|
+
amount += child.turnover(@scenarioIdx, startIdx, endIdx, account,
|
|
505
|
+
task)
|
|
448
506
|
end
|
|
449
507
|
else
|
|
450
|
-
|
|
451
|
-
|
|
508
|
+
if task
|
|
509
|
+
# If we have a know task, we only include the amount that is
|
|
510
|
+
# specific to this resource, this task and the chargeset of the
|
|
511
|
+
# task.
|
|
512
|
+
amount += task.turnover(@scenarioIdx, startIdx, endIdx, account,
|
|
452
513
|
@property)
|
|
514
|
+
elsif !@chargeset.empty?
|
|
515
|
+
# If no tasks was provided, we include the amount of this resource,
|
|
516
|
+
# weighted by the charset of this resource.
|
|
517
|
+
totalResourceCost = cost(startIdx, endIdx)
|
|
518
|
+
@chargeset.each do |set|
|
|
519
|
+
set.each do |accnt, share|
|
|
520
|
+
if share > 0.0 && (accnt == account || accnt.isChildOf?(account))
|
|
521
|
+
amount += totalResourceCost * share
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
end
|
|
453
525
|
end
|
|
454
526
|
end
|
|
455
527
|
|
|
@@ -545,7 +617,7 @@ class TaskJuggler
|
|
|
545
617
|
end
|
|
546
618
|
|
|
547
619
|
# Return a list of scoreboard intervals that are at least _minDuration_ long
|
|
548
|
-
# and contain only off-duty and
|
|
620
|
+
# and contain only off-duty and leave slots. The result is an Array of
|
|
549
621
|
# [ start, end ] TjTime values.
|
|
550
622
|
def collectTimeOffIntervals(iv, minDuration)
|
|
551
623
|
# Time-off intervals are only useful for leaf resources. Group resources
|
|
@@ -581,107 +653,114 @@ class TaskJuggler
|
|
|
581
653
|
# Count the number of slots betweend the _startIdx_ and _endIdx_ that can
|
|
582
654
|
# be used for work
|
|
583
655
|
def getWorkSlots(startIdx, endIdx)
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
initScoreboard unless @scoreboard
|
|
587
|
-
|
|
588
|
-
workSlots = 0
|
|
589
|
-
startIdx.upto(endIdx - 1) do |idx|
|
|
590
|
-
slot = @scoreboard[idx]
|
|
656
|
+
countSlots(startIdx, endIdx) do |val|
|
|
591
657
|
# We count free slots and assigned slots.
|
|
592
|
-
|
|
658
|
+
val.nil? || val.is_a?(Task)
|
|
593
659
|
end
|
|
660
|
+
end
|
|
594
661
|
|
|
595
|
-
|
|
662
|
+
# Count the number of slots that are work time slots but marked as annual
|
|
663
|
+
# leave.
|
|
664
|
+
def getLeaveSlots(startIdx, endIdx, type)
|
|
665
|
+
countSlots(startIdx, endIdx) do |val|
|
|
666
|
+
val.is_a?(Fixnum) && (val & 0x3E) == (Leave::Types[type] << 2)
|
|
667
|
+
end
|
|
596
668
|
end
|
|
597
669
|
|
|
598
670
|
# Count the free slots between the start and end index.
|
|
599
671
|
def getFreeSlots(startIdx, endIdx)
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
initScoreboard unless @scoreboard
|
|
603
|
-
|
|
604
|
-
freeSlots = 0
|
|
605
|
-
startIdx.upto(endIdx - 1) do |idx|
|
|
606
|
-
freeSlots += 1 if @scoreboard[idx].nil?
|
|
672
|
+
countSlots(startIdx, endIdx) do |val|
|
|
673
|
+
val.nil?
|
|
607
674
|
end
|
|
608
|
-
|
|
609
|
-
freeSlots
|
|
610
675
|
end
|
|
611
676
|
|
|
612
677
|
# Count the regular work time slots between the start and end index that
|
|
613
|
-
# have been blocked by
|
|
614
|
-
def
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
vacationSlots = 0
|
|
620
|
-
startIdx.upto(endIdx - 1) do |idx|
|
|
621
|
-
val = @scoreboard[idx]
|
|
622
|
-
# Bit 1 needs to be unset and the vacation bits must not be 0.
|
|
623
|
-
vacationSlots += 1 if val.is_a?(Fixnum) && (val & 0x2) == 0 &&
|
|
624
|
-
(val & 0x3C) != 0
|
|
678
|
+
# have been blocked by leaves.
|
|
679
|
+
def getTimeOffSlots(startIdx, endIdx)
|
|
680
|
+
countSlots(startIdx, endIdx) do |val|
|
|
681
|
+
# Bit 1 needs to be unset and the leave bits must not be 0.
|
|
682
|
+
val.is_a?(Fixnum) && (val & 0x2) == 0 && (val & 0x3C) != 0
|
|
625
683
|
end
|
|
626
|
-
vacationSlots
|
|
627
684
|
end
|
|
628
685
|
|
|
629
686
|
private
|
|
630
687
|
|
|
631
688
|
def initScoreboard
|
|
632
|
-
# Create scoreboard and mark all slots as
|
|
689
|
+
# Create scoreboard and mark all slots as non-working-time.
|
|
633
690
|
@scoreboard = Scoreboard.new(@project['start'], @project['end'],
|
|
634
691
|
@project['scheduleGranularity'], 2)
|
|
635
692
|
|
|
636
|
-
# We'll need this frequently and can savely cache it here.
|
|
637
|
-
@shifts = @shifts
|
|
638
|
-
@workinghours = @workinghours
|
|
639
|
-
|
|
640
693
|
# Change all work time slots to nil (available) again.
|
|
641
694
|
@project.scoreboardSize.times do |i|
|
|
642
695
|
@scoreboard[i] = nil if onShift?(i)
|
|
643
696
|
end
|
|
644
697
|
|
|
645
|
-
# Mark all
|
|
646
|
-
@
|
|
647
|
-
startIdx = @scoreboard.dateToIdx(
|
|
648
|
-
endIdx = @scoreboard.dateToIdx(
|
|
698
|
+
# Mark all global leave slots as such
|
|
699
|
+
@project['leaves'].each do |leave|
|
|
700
|
+
startIdx = @scoreboard.dateToIdx(leave.interval.start)
|
|
701
|
+
endIdx = @scoreboard.dateToIdx(leave.interval.end)
|
|
649
702
|
startIdx.upto(endIdx - 1) do |i|
|
|
650
|
-
|
|
651
|
-
|
|
703
|
+
sb = @scoreboard[i]
|
|
704
|
+
# We preseve the work-time bit (#1).
|
|
705
|
+
@scoreboard[i] = (sb.nil? ? 0 : 2) | (leave.typeIdx << 2)
|
|
652
706
|
end
|
|
653
707
|
end
|
|
654
708
|
|
|
655
|
-
# Mark all
|
|
656
|
-
@
|
|
657
|
-
startIdx = @scoreboard.dateToIdx(
|
|
658
|
-
endIdx = @scoreboard.dateToIdx(
|
|
709
|
+
# Mark all resource specific leave slots as such
|
|
710
|
+
@leaves.each do |leave|
|
|
711
|
+
startIdx = @scoreboard.dateToIdx(leave.interval.start)
|
|
712
|
+
endIdx = @scoreboard.dateToIdx(leave.interval.end)
|
|
659
713
|
startIdx.upto(endIdx - 1) do |i|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
714
|
+
if (sb = @scoreboard[i])
|
|
715
|
+
# The slot is already marked as non-working slot. We override the
|
|
716
|
+
# leave type if the new type is larger than the old one.
|
|
717
|
+
leaveIdx = (sb & 0x3C) >> 2
|
|
718
|
+
if leave.typeIdx > leaveIdx
|
|
719
|
+
# The work-time bit (#1) is preserved.
|
|
720
|
+
@scoreboard[i] = (sb & 0x2) | (leave.typeIdx << 2)
|
|
721
|
+
end
|
|
722
|
+
else
|
|
723
|
+
# This marks a working time slot as a leave slot. Since bit 1 is
|
|
724
|
+
# not set, we still know that this could be a working slot.
|
|
725
|
+
@scoreboard[i] = leave.typeIdx << 2
|
|
726
|
+
end
|
|
663
727
|
end
|
|
664
728
|
end
|
|
665
729
|
|
|
666
730
|
unless @shifts.nil?
|
|
667
|
-
# Mark the
|
|
731
|
+
# Mark the leaves from all the shifts the resource is assigned to.
|
|
668
732
|
@project.scoreboardSize.times do |i|
|
|
669
733
|
v = @shifts.getSbSlot(i)
|
|
670
|
-
#
|
|
671
|
-
|
|
672
|
-
|
|
734
|
+
# Make sure a shift is actually assigned.
|
|
735
|
+
next unless v
|
|
736
|
+
|
|
673
737
|
if (v & (1 << 8)) != 0
|
|
738
|
+
# Check if the leave replacement bit (#8) is set. In that case we
|
|
739
|
+
# copy the whole interval over to the resource scoreboard
|
|
740
|
+
# overriding any global leaves.
|
|
674
741
|
@scoreboard[i] = (v & 0x3E == 0) ? nil : (v & 0x3D)
|
|
675
|
-
elsif ((
|
|
742
|
+
elsif ((sb = @scoreboard[i]).nil? || ((sb & 0x3C) < (v & 0x3C))) &&
|
|
676
743
|
(v & 0x3C) != 0
|
|
677
|
-
#
|
|
678
|
-
#
|
|
744
|
+
# In merge mode, we only add the shift leaves with higher type
|
|
745
|
+
# index or unassigned slots.
|
|
679
746
|
@scoreboard[i] = v & 0x3E
|
|
680
747
|
end
|
|
681
748
|
end
|
|
682
749
|
end
|
|
683
750
|
end
|
|
684
751
|
|
|
752
|
+
def countSlots(startIdx, endIdx)
|
|
753
|
+
return 0 if startIdx >= endIdx
|
|
754
|
+
|
|
755
|
+
initScoreboard unless @scoreboard
|
|
756
|
+
|
|
757
|
+
slots = 0
|
|
758
|
+
startIdx.upto(endIdx - 1) do |idx|
|
|
759
|
+
slots += 1 if yield(@scoreboard[idx])
|
|
760
|
+
end
|
|
761
|
+
slots
|
|
762
|
+
end
|
|
763
|
+
|
|
685
764
|
# Limit the _startIdx_ and _endIdx_ to the actually assigned interval.
|
|
686
765
|
# If _task_ is provided, fit it for the bookings of this particular task.
|
|
687
766
|
def fitIndicies(startIdx, endIdx, task = nil)
|