taskjuggler 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2086 -0
- data/benchmarks/666tasks.tjp +3183 -0
- data/benchmarks/booking.tjp +14 -10
- data/doc/AppConfig.html +95 -73
- data/doc/Arguments.html +22 -2
- data/doc/CHANGELOG.html +2587 -0
- data/doc/COPYING.html +21 -1
- data/doc/Object.html +161 -122
- data/doc/README.html +21 -1
- data/doc/RuntimeConfig.html +26 -6
- data/doc/String.html +38 -18
- data/doc/StringIO.html +579 -0
- data/doc/TaskJuggler.html +251 -143
- data/doc/TaskJuggler/Account.html +26 -6
- data/doc/TaskJuggler/AccountAttribute.html +28 -8
- data/doc/TaskJuggler/AccountScenario.html +24 -4
- data/doc/TaskJuggler/Allocation.html +30 -10
- data/doc/TaskJuggler/AllocationAttribute.html +28 -8
- data/doc/TaskJuggler/AttributeBase.html +46 -26
- data/doc/TaskJuggler/AttributeDefinition.html +22 -2
- data/doc/TaskJuggler/BatchProcessor.html +40 -20
- data/doc/TaskJuggler/Booking.html +26 -6
- data/doc/TaskJuggler/BookingListAttribute.html +28 -8
- data/doc/TaskJuggler/BooleanAttribute.html +28 -8
- data/doc/TaskJuggler/CSVFile.html +308 -146
- data/doc/TaskJuggler/CellSettingPattern.html +22 -2
- data/doc/TaskJuggler/CellSettingPatternList.html +26 -6
- data/doc/TaskJuggler/Charge.html +26 -6
- data/doc/TaskJuggler/ChargeListAttribute.html +26 -6
- data/doc/TaskJuggler/ChargeSet.html +33 -13
- data/doc/TaskJuggler/ChargeSetListAttribute.html +28 -8
- data/doc/TaskJuggler/ColumnListAttribute.html +26 -6
- data/doc/TaskJuggler/ColumnTable.html +24 -4
- data/doc/TaskJuggler/Daemon.html +26 -6
- data/doc/TaskJuggler/DateAttribute.html +26 -6
- data/doc/TaskJuggler/DefinitionListAttribute.html +22 -2
- data/doc/TaskJuggler/DependencyListAttribute.html +28 -8
- data/doc/TaskJuggler/DurationAttribute.html +28 -8
- data/doc/TaskJuggler/FixnumAttribute.html +24 -4
- data/doc/TaskJuggler/FlagListAttribute.html +28 -8
- data/doc/TaskJuggler/FloatAttribute.html +26 -6
- data/doc/TaskJuggler/FormatListAttribute.html +24 -4
- data/doc/TaskJuggler/GanttChart.html +147 -126
- data/doc/TaskJuggler/GanttContainer.html +34 -14
- data/doc/TaskJuggler/GanttHeader.html +28 -8
- data/doc/TaskJuggler/GanttHeaderScaleItem.html +24 -4
- data/doc/TaskJuggler/GanttLine.html +38 -18
- data/doc/TaskJuggler/GanttLoadStack.html +26 -6
- data/doc/TaskJuggler/GanttMilestone.html +34 -14
- data/doc/TaskJuggler/GanttRouter.html +50 -30
- data/doc/TaskJuggler/GanttTaskBar.html +34 -14
- data/doc/TaskJuggler/HTMLDocument.html +26 -6
- data/doc/TaskJuggler/HTMLGraphics.html +30 -10
- data/doc/TaskJuggler/Interval.html +40 -22
- data/doc/TaskJuggler/IntervalListAttribute.html +28 -8
- data/doc/TaskJuggler/JobInfo.html +24 -4
- data/doc/TaskJuggler/Journal.html +226 -147
- data/doc/TaskJuggler/JournalEntry.html +22 -2
- data/doc/TaskJuggler/JournalEntryList.html +129 -112
- data/doc/TaskJuggler/KeywordArray.html +26 -6
- data/doc/TaskJuggler/KeywordDocumentation.html +46 -26
- data/doc/TaskJuggler/Limits.html +152 -123
- data/doc/TaskJuggler/Limits/Limit.html +149 -70
- data/doc/TaskJuggler/LimitsAttribute.html +36 -51
- data/doc/TaskJuggler/ListAttributeBase.html +24 -4
- data/doc/TaskJuggler/Log.html +50 -32
- data/doc/TaskJuggler/LogFile.html +37 -17
- data/doc/TaskJuggler/LogicalAttribute.html +53 -33
- data/doc/TaskJuggler/LogicalExpression.html +26 -6
- data/doc/TaskJuggler/LogicalExpressionAttribute.html +32 -12
- data/doc/TaskJuggler/LogicalFlag.html +42 -22
- data/doc/TaskJuggler/LogicalFunction.html +204 -140
- data/doc/TaskJuggler/LogicalOperation.html +135 -111
- data/doc/TaskJuggler/Macro.html +22 -2
- data/doc/TaskJuggler/MacroParser.html +32 -12
- data/doc/TaskJuggler/MacroTable.html +32 -12
- data/doc/TaskJuggler/ManagerResponsibilities.html +24 -4
- data/doc/TaskJuggler/ManagerStatusRecord.html +24 -4
- data/doc/TaskJuggler/Message.html +24 -4
- data/doc/TaskJuggler/MessageHandler.html +24 -4
- data/doc/TaskJuggler/Navigator.html +104 -71
- data/doc/TaskJuggler/NavigatorElement.html +32 -12
- data/doc/TaskJuggler/NikuProject.html +22 -2
- data/doc/TaskJuggler/NikuReport.html +310 -228
- data/doc/TaskJuggler/NikuResource.html +22 -2
- data/doc/TaskJuggler/NodeListAttribute.html +615 -0
- data/doc/TaskJuggler/OnShiftCache.html +32 -12
- data/doc/TaskJuggler/ProcessIntercom.html +205 -78
- data/doc/TaskJuggler/ProcessIntercomIface.html +26 -6
- data/doc/TaskJuggler/Project.html +708 -660
- data/doc/TaskJuggler/ProjectBroker.html +506 -304
- data/doc/TaskJuggler/ProjectBrokerIface.html +61 -41
- data/doc/TaskJuggler/ProjectFileParser.html +429 -373
- data/doc/TaskJuggler/ProjectFileScanner.html +1790 -0
- data/doc/TaskJuggler/ProjectRecord.html +80 -60
- data/doc/TaskJuggler/ProjectServer.html +312 -237
- data/doc/TaskJuggler/ProjectServerIface.html +101 -43
- data/doc/TaskJuggler/PropertyAttribute.html +32 -12
- data/doc/TaskJuggler/PropertyList.html +166 -145
- data/doc/TaskJuggler/PropertySet.html +254 -224
- data/doc/TaskJuggler/PropertyTreeNode.html +670 -536
- data/doc/TaskJuggler/Query.html +169 -148
- data/doc/TaskJuggler/RTFHandlers.html +622 -0
- data/doc/TaskJuggler/RTFNavigator.html +28 -8
- data/doc/TaskJuggler/RTFQuery.html +40 -20
- data/doc/TaskJuggler/RTFReport.html +62 -25
- data/doc/TaskJuggler/RTFReportLink.html +765 -0
- data/doc/TaskJuggler/RealFormat.html +26 -6
- data/doc/TaskJuggler/RealFormatAttribute.html +26 -6
- data/doc/TaskJuggler/ReferenceAttribute.html +59 -39
- data/doc/TaskJuggler/Report.html +402 -251
- data/doc/TaskJuggler/ReportBase.html +162 -137
- data/doc/TaskJuggler/ReportContext.html +112 -29
- data/doc/TaskJuggler/ReportServer.html +89 -64
- data/doc/TaskJuggler/ReportServerIface.html +75 -55
- data/doc/TaskJuggler/ReportServerRecord.html +54 -31
- data/doc/TaskJuggler/ReportServlet.html +980 -0
- data/doc/TaskJuggler/ReportTable.html +41 -21
- data/doc/TaskJuggler/ReportTableCell.html +214 -170
- data/doc/TaskJuggler/ReportTableColumn.html +30 -10
- data/doc/TaskJuggler/ReportTableLegend.html +36 -16
- data/doc/TaskJuggler/ReportTableLine.html +32 -12
- data/doc/TaskJuggler/Resource.html +99 -87
- data/doc/TaskJuggler/ResourceListAttribute.html +59 -39
- data/doc/TaskJuggler/ResourceListRE.html +47 -26
- data/doc/TaskJuggler/ResourceScenario.html +403 -437
- data/doc/TaskJuggler/RichText.html +26 -6
- data/doc/TaskJuggler/RichTextAttribute.html +50 -30
- data/doc/TaskJuggler/RichTextDocument.html +37 -17
- data/doc/TaskJuggler/RichTextElement.html +475 -413
- data/doc/TaskJuggler/RichTextException.html +22 -2
- data/doc/TaskJuggler/RichTextFunctionExample.html +28 -8
- data/doc/TaskJuggler/RichTextFunctionHandler.html +24 -4
- data/doc/TaskJuggler/RichTextImage.html +22 -2
- data/doc/TaskJuggler/RichTextIntermediate.html +38 -18
- data/doc/TaskJuggler/RichTextParser.html +56 -34
- data/doc/TaskJuggler/RichTextScanner.html +82 -61
- data/doc/TaskJuggler/RichTextSnip.html +34 -14
- data/doc/TaskJuggler/RichTextSyntaxRules.html +507 -353
- data/doc/TaskJuggler/Scenario.html +22 -2
- data/doc/TaskJuggler/ScenarioData.html +30 -46
- data/doc/TaskJuggler/ScenarioListAttribute.html +38 -18
- data/doc/TaskJuggler/Scoreboard.html +42 -22
- data/doc/TaskJuggler/SheetHandlerBase.html +40 -20
- data/doc/TaskJuggler/SheetReceiver.html +333 -295
- data/doc/TaskJuggler/SheetSender.html +253 -230
- data/doc/TaskJuggler/Shift.html +26 -6
- data/doc/TaskJuggler/ShiftAssignment.html +89 -73
- data/doc/TaskJuggler/ShiftAssignments.html +226 -234
- data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +39 -54
- data/doc/TaskJuggler/ShiftScenario.html +28 -8
- data/doc/TaskJuggler/SortListAttribute.html +34 -14
- data/doc/TaskJuggler/SourceFileInfo.html +24 -4
- data/doc/TaskJuggler/StatusSheetReceiver.html +24 -3
- data/doc/TaskJuggler/StatusSheetReport.html +168 -153
- data/doc/TaskJuggler/StatusSheetSender.html +24 -3
- data/doc/TaskJuggler/StringAttribute.html +38 -18
- data/doc/TaskJuggler/SymbolAttribute.html +32 -12
- data/doc/TaskJuggler/SyntaxReference.html +40 -20
- data/doc/TaskJuggler/TOCEntry.html +26 -6
- data/doc/TaskJuggler/TSResourceRecord.html +22 -2
- data/doc/TaskJuggler/TSTaskRecord.html +22 -2
- data/doc/TaskJuggler/TableColumnDefinition.html +59 -22
- data/doc/TaskJuggler/TableOfContents.html +26 -6
- data/doc/TaskJuggler/TableReport.html +937 -904
- data/doc/TaskJuggler/Task.html +55 -36
- data/doc/TaskJuggler/TaskDependency.html +24 -4
- data/doc/TaskJuggler/TaskListAttribute.html +50 -30
- data/doc/TaskJuggler/TaskListRE.html +27 -7
- data/doc/TaskJuggler/TaskScenario.html +1273 -1153
- data/doc/TaskJuggler/TextFormatter.html +28 -8
- data/doc/TaskJuggler/TextParser.html +585 -338
- data/doc/TaskJuggler/TextParser/Pattern.html +54 -34
- data/doc/TaskJuggler/TextParser/Rule.html +95 -73
- data/doc/TaskJuggler/TextParser/StackElement.html +39 -17
- data/doc/TaskJuggler/TextParser/TextParserResultArray.html +24 -4
- data/doc/TaskJuggler/TextParser/TokenDoc.html +22 -2
- data/doc/TaskJuggler/TextReport.html +28 -8
- data/doc/TaskJuggler/TextScanner.html +400 -1404
- data/doc/TaskJuggler/TextScanner/BufferStreamHandle.html +28 -240
- data/doc/TaskJuggler/TextScanner/FileStreamHandle.html +37 -184
- data/doc/TaskJuggler/TextScanner/MacroStackEntry.html +682 -0
- data/doc/TaskJuggler/TextScanner/StreamHandle.html +342 -67
- data/doc/TaskJuggler/TimeSheet.html +48 -28
- data/doc/TaskJuggler/TimeSheetReceiver.html +24 -3
- data/doc/TaskJuggler/TimeSheetRecord.html +47 -27
- data/doc/TaskJuggler/TimeSheetReport.html +154 -133
- data/doc/TaskJuggler/TimeSheetSender.html +24 -3
- data/doc/TaskJuggler/TimeSheetSummary.html +137 -91
- data/doc/TaskJuggler/TimeSheets.html +26 -6
- data/doc/TaskJuggler/Tj3AppBase.html +85 -58
- data/doc/TaskJuggler/Tj3Client.html +292 -238
- data/doc/TaskJuggler/Tj3Daemon.html +159 -74
- data/doc/TaskJuggler/Tj3SheetAppBase.html +26 -6
- data/doc/TaskJuggler/Tj3SsReceiver.html +26 -6
- data/doc/TaskJuggler/Tj3SsSender.html +53 -26
- data/doc/TaskJuggler/Tj3TsReceiver.html +28 -7
- data/doc/TaskJuggler/Tj3TsSender.html +26 -6
- data/doc/TaskJuggler/Tj3TsSummary.html +26 -6
- data/doc/TaskJuggler/TjException.html +22 -2
- data/doc/TaskJuggler/TjTime.html +216 -160
- data/doc/TaskJuggler/TjpExample.html +34 -14
- data/doc/TaskJuggler/TjpExportRE.html +403 -407
- data/doc/TaskJuggler/TjpSyntaxRules.html +4805 -4408
- data/doc/TaskJuggler/URLParameter.html +649 -0
- data/doc/TaskJuggler/UserManual.html +42 -22
- data/doc/TaskJuggler/WebServer.html +702 -0
- data/doc/TaskJuggler/WorkingHours.html +38 -18
- data/doc/TaskJuggler/WorkingHoursAttribute.html +61 -41
- data/doc/TaskJuggler/XMLBlob.html +24 -4
- data/doc/TaskJuggler/XMLComment.html +24 -4
- data/doc/TaskJuggler/XMLDocument.html +30 -10
- data/doc/TaskJuggler/XMLElement.html +34 -14
- data/doc/TaskJuggler/XMLNamedText.html +22 -2
- data/doc/TaskJuggler/XMLText.html +24 -4
- data/doc/index.html +1841 -1666
- data/doc/lib/AccountScenario_rb.html +1 -1
- data/doc/lib/Account_rb.html +1 -1
- data/doc/lib/Allocation_rb.html +1 -1
- data/doc/lib/AppConfig_rb.html +2 -2
- data/doc/lib/AttributeBase_rb.html +1 -1
- data/doc/lib/AttributeDefinition_rb.html +1 -1
- data/doc/lib/Attributes_rb.html +2 -2
- data/doc/lib/BatchProcessor_rb.html +1 -1
- data/doc/lib/Booking_rb.html +1 -1
- data/doc/lib/ChargeSet_rb.html +1 -1
- data/doc/lib/Charge_rb.html +1 -1
- data/doc/lib/HTMLDocument_rb.html +1 -1
- data/doc/lib/Interval_rb.html +1 -1
- data/doc/lib/Journal_rb.html +2 -2
- data/doc/lib/KeywordArray_rb.html +1 -1
- data/doc/lib/KeywordDocumentation_rb.html +1 -1
- data/doc/lib/Limits_rb.html +2 -2
- data/doc/lib/LogFile_rb.html +2 -2
- data/doc/lib/Log_rb.html +1 -1
- data/doc/lib/LogicalExpression_rb.html +1 -1
- data/doc/lib/LogicalFunction_rb.html +2 -2
- data/doc/lib/LogicalOperation_rb.html +2 -2
- data/doc/lib/MacroParser_rb.html +1 -1
- data/doc/lib/MacroTable_rb.html +1 -1
- data/doc/lib/MessageHandler_rb.html +1 -1
- data/doc/lib/Message_rb.html +1 -1
- data/doc/lib/ProjectFileParser_rb.html +4 -8
- data/doc/lib/ProjectFileScanner_rb.html +67 -0
- data/doc/lib/Project_rb.html +2 -2
- data/doc/lib/PropertyList_rb.html +2 -2
- data/doc/lib/PropertySet_rb.html +2 -2
- data/doc/lib/PropertyTreeNode_rb.html +2 -2
- data/doc/lib/Query_rb.html +2 -2
- data/doc/lib/RTFHandlers_rb.html +73 -0
- data/doc/lib/RTFNavigator_rb.html +1 -1
- data/doc/lib/RTFQuery_rb.html +1 -1
- data/doc/lib/RTFReportLink_rb.html +71 -0
- data/doc/lib/RTFReport_rb.html +2 -2
- data/doc/lib/RealFormat_rb.html +1 -1
- data/doc/lib/ResourceScenario_rb.html +2 -2
- data/doc/lib/Resource_rb.html +2 -2
- data/doc/lib/RichTextDocument_rb.html +1 -1
- data/doc/lib/RichTextElement_rb.html +2 -2
- data/doc/lib/RichTextFunctionExample_rb.html +1 -1
- data/doc/lib/RichTextFunctionHandler_rb.html +1 -1
- data/doc/lib/RichTextParser_rb.html +2 -2
- data/doc/lib/RichTextScanner_rb.html +2 -2
- data/doc/lib/RichTextSnip_rb.html +1 -1
- data/doc/lib/RichTextSyntaxRules_rb.html +2 -2
- data/doc/lib/RichText_rb.html +1 -1
- data/doc/lib/RuntimeConfig_rb.html +1 -1
- data/doc/lib/ScenarioData_rb.html +2 -2
- data/doc/lib/Scenario_rb.html +1 -1
- data/doc/lib/Scoreboard_rb.html +1 -1
- data/doc/lib/SheetHandlerBase_rb.html +1 -1
- data/doc/lib/SheetReceiver_rb.html +2 -2
- data/doc/lib/SheetSender_rb.html +4 -2
- data/doc/lib/ShiftAssignments_rb.html +4 -2
- data/doc/lib/ShiftScenario_rb.html +1 -1
- data/doc/lib/Shift_rb.html +1 -1
- data/doc/lib/SourceFileInfo_rb.html +1 -1
- data/doc/lib/StatusSheetReceiver_rb.html +2 -2
- data/doc/lib/StatusSheetSender_rb.html +2 -2
- data/doc/lib/SyntaxReference_rb.html +1 -1
- data/doc/lib/TOCEntry_rb.html +1 -1
- data/doc/lib/TableColumnDefinition_rb.html +2 -2
- data/doc/lib/TableOfContents_rb.html +1 -1
- data/doc/lib/TaskDependency_rb.html +1 -1
- data/doc/lib/TaskJuggler_rb.html +2 -2
- data/doc/lib/TaskScenario_rb.html +2 -2
- data/doc/lib/Task_rb.html +2 -2
- data/doc/lib/TextFormatter_rb.html +1 -1
- data/doc/lib/TextParser/Pattern_rb.html +1 -1
- data/doc/lib/TextParser/Rule_rb.html +2 -2
- data/doc/lib/TextParser/StackElement_rb.html +2 -2
- data/doc/lib/TextParser/TokenDoc_rb.html +1 -1
- data/doc/lib/TextParser_rb.html +2 -2
- data/doc/lib/TextScanner_rb.html +6 -2
- data/doc/lib/TimeSheetReceiver_rb.html +2 -2
- data/doc/lib/TimeSheetSender_rb.html +2 -2
- data/doc/lib/TimeSheetSummary_rb.html +2 -2
- data/doc/lib/TimeSheets_rb.html +2 -2
- data/doc/lib/Tj3AppBase_rb.html +2 -2
- data/doc/lib/Tj3Config_rb.html +2 -2
- data/doc/lib/Tj3SheetAppBase_rb.html +2 -2
- data/doc/lib/TjException_rb.html +1 -1
- data/doc/lib/TjTime_rb.html +2 -2
- data/doc/lib/TjpExample_rb.html +1 -1
- data/doc/lib/TjpSyntaxRules_rb.html +2 -2
- data/doc/lib/URLParameter_rb.html +67 -0
- data/doc/lib/UTF8String_rb.html +1 -1
- data/doc/lib/UserManual_rb.html +1 -1
- data/doc/lib/WorkingHours_rb.html +1 -1
- data/doc/lib/XMLDocument_rb.html +2 -2
- data/doc/lib/XMLElement_rb.html +1 -1
- data/doc/lib/daemon/Daemon_rb.html +1 -1
- data/doc/lib/daemon/ProcessIntercom_rb.html +2 -2
- data/doc/lib/daemon/ProjectBroker_rb.html +4 -2
- data/doc/lib/daemon/ProjectServer_rb.html +2 -2
- data/doc/lib/daemon/ReportServer_rb.html +2 -2
- data/doc/lib/daemon/WebServer_rb.html +75 -0
- data/doc/lib/deep_copy_rb.html +2 -2
- data/doc/lib/reports/CSVFile_rb.html +2 -2
- data/doc/lib/reports/ColumnTable_rb.html +1 -1
- data/doc/lib/reports/GanttChart_rb.html +2 -2
- data/doc/lib/reports/GanttContainer_rb.html +1 -1
- data/doc/lib/reports/GanttHeaderScaleItem_rb.html +1 -1
- data/doc/lib/reports/GanttHeader_rb.html +1 -1
- data/doc/lib/reports/GanttLine_rb.html +1 -1
- data/doc/lib/reports/GanttLoadStack_rb.html +1 -1
- data/doc/lib/reports/GanttMilestone_rb.html +1 -1
- data/doc/lib/reports/GanttRouter_rb.html +1 -1
- data/doc/lib/reports/GanttTaskBar_rb.html +1 -1
- data/doc/lib/reports/HTMLGraphics_rb.html +1 -1
- data/doc/lib/reports/Navigator_rb.html +2 -2
- data/doc/lib/reports/NikuReport_rb.html +2 -2
- data/doc/lib/reports/ReportBase_rb.html +2 -2
- data/doc/lib/reports/ReportContext_rb.html +2 -2
- data/doc/lib/reports/ReportTableCell_rb.html +2 -2
- data/doc/lib/reports/ReportTableColumn_rb.html +1 -1
- data/doc/lib/reports/ReportTableLegend_rb.html +1 -1
- data/doc/lib/reports/ReportTableLine_rb.html +1 -1
- data/doc/lib/reports/ReportTable_rb.html +2 -2
- data/doc/lib/reports/Report_rb.html +2 -2
- data/doc/lib/reports/ResourceListRE_rb.html +2 -2
- data/doc/lib/reports/StatusSheetReport_rb.html +2 -2
- data/doc/lib/reports/TableReport_rb.html +2 -2
- data/doc/lib/reports/TaskListRE_rb.html +2 -2
- data/doc/lib/reports/TextReport_rb.html +1 -1
- data/doc/lib/reports/TimeSheetReport_rb.html +2 -2
- data/doc/lib/reports/TjpExportRE_rb.html +2 -2
- data/doc/lib/ruby-signal-bug_rb.html +1 -1
- data/doc/lib/taskjuggler3_rb.html +2 -2
- data/doc/lib/tj3client_rb.html +2 -2
- data/doc/lib/tj3d_rb.html +2 -2
- data/doc/lib/tj3man_rb.html +1 -1
- data/doc/lib/tj3ss_receiver_rb.html +1 -1
- data/doc/lib/tj3ss_sender_rb.html +2 -2
- data/doc/lib/tj3ts_receiver_rb.html +2 -2
- data/doc/lib/tj3ts_sender_rb.html +1 -1
- data/doc/lib/tj3ts_summary_rb.html +1 -1
- data/doc/rdoc.css +9 -4
- data/examples/tutorial.tjp +17 -15
- data/gem_spec.rb +3 -0
- data/lib/AppConfig.rb +3 -1
- data/lib/Attributes.rb +10 -8
- data/lib/Journal.rb +55 -20
- data/lib/Limits.rb +72 -46
- data/lib/LogFile.rb +3 -3
- data/lib/LogicalFunction.rb +19 -6
- data/lib/LogicalOperation.rb +5 -1
- data/lib/Project.rb +37 -9
- data/lib/ProjectFileParser.rb +25 -22
- data/lib/ProjectFileScanner.rb +365 -0
- data/lib/PropertyList.rb +2 -1
- data/lib/PropertySet.rb +14 -4
- data/lib/PropertyTreeNode.rb +42 -29
- data/lib/Query.rb +3 -1
- data/lib/RTFHandlers.rb +35 -0
- data/lib/RTFReport.rb +23 -6
- data/lib/RTFReportLink.rb +72 -0
- data/lib/Resource.rb +8 -16
- data/lib/ResourceScenario.rb +1 -22
- data/lib/RichTextElement.rb +42 -0
- data/lib/RichTextParser.rb +6 -4
- data/lib/RichTextScanner.rb +5 -5
- data/lib/RichTextSyntaxRules.rb +48 -10
- data/lib/ScenarioData.rb +5 -3
- data/lib/SheetReceiver.rb +24 -6
- data/lib/SheetSender.rb +17 -13
- data/lib/ShiftAssignments.rb +56 -52
- data/lib/StatusSheetReceiver.rb +1 -0
- data/lib/StatusSheetSender.rb +1 -0
- data/lib/TableColumnDefinition.rb +4 -2
- data/lib/Task.rb +8 -9
- data/lib/TaskJuggler.rb +21 -11
- data/lib/TaskScenario.rb +61 -26
- data/lib/TextParser.rb +268 -106
- data/lib/TextParser/Rule.rb +4 -2
- data/lib/TextParser/StackElement.rb +6 -4
- data/lib/TextScanner.rb +283 -700
- data/lib/TimeSheetReceiver.rb +1 -0
- data/lib/TimeSheetSender.rb +1 -0
- data/lib/TimeSheetSummary.rb +51 -26
- data/lib/TimeSheets.rb +1 -1
- data/lib/Tj3AppBase.rb +8 -1
- data/lib/Tj3Config.rb +1 -1
- data/lib/TjTime.rb +5 -0
- data/lib/TjpSyntaxRules.rb +360 -144
- data/lib/URLParameter.rb +30 -0
- data/lib/XMLDocument.rb +2 -2
- data/lib/daemon/ProcessIntercom.rb +50 -9
- data/lib/daemon/ProjectBroker.rb +63 -10
- data/lib/daemon/ProjectServer.rb +47 -16
- data/lib/daemon/ReportServer.rb +9 -4
- data/lib/daemon/WebServer.rb +204 -0
- data/lib/deep_copy.rb +4 -1
- data/lib/reports/CSVFile.rb +150 -66
- data/lib/reports/GanttChart.rb +2 -1
- data/lib/reports/Navigator.rb +18 -5
- data/lib/reports/NikuReport.rb +32 -2
- data/lib/reports/Report.rb +65 -37
- data/lib/reports/ReportBase.rb +14 -9
- data/lib/reports/ReportContext.rb +19 -4
- data/lib/reports/ReportTable.rb +2 -2
- data/lib/reports/ReportTableCell.rb +54 -30
- data/lib/reports/ResourceListRE.rb +4 -3
- data/lib/reports/StatusSheetReport.rb +8 -13
- data/lib/reports/TableReport.rb +47 -32
- data/lib/reports/TaskListRE.rb +3 -3
- data/lib/reports/TimeSheetReport.rb +14 -5
- data/lib/reports/TjpExportRE.rb +14 -19
- data/lib/taskjuggler3.rb +15 -0
- data/lib/tj3client.rb +9 -7
- data/lib/tj3d.rb +38 -10
- data/lib/tj3ss_sender.rb +7 -0
- data/lib/tj3ts_receiver.rb +1 -0
- data/manual/Day_To_Day_Juggling +1 -1
- data/manual/Rich_Text_Attributes +8 -0
- data/manual/TaskJuggler_2x_Migration +7 -0
- data/manual/The_TaskJuggler_Syntax +20 -6
- data/prj_cfg.rb +3 -2
- data/tasks/changelog.rake +36 -0
- data/tasks/csts.rake +2 -3
- data/tasks/gem.rake +10 -0
- data/tasks/missing.rake +0 -17
- data/test/TestSuite/ReportGenerator/Correct/Journal.html +63 -0
- data/test/TestSuite/ReportGenerator/Correct/Journal.tjp +14 -0
- data/test/TestSuite/{HTML-Reports/LogicalFunctions.tjp → ReportGenerator/Correct/LogicalFunctions1.tjp} +2 -2
- data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.csv +3 -0
- data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.tjp +19 -0
- data/test/TestSuite/ReportGenerator/Correct/css/tjmanual.css +66 -0
- data/test/TestSuite/ReportGenerator/Correct/css/tjreport.css +407 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/details.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-green.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-red.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-yellow.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/resource.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/resourcegroup.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/task.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/taskgroup.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-down.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-flat.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-up.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/opennodes.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/opennodes.tjp +26 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/Journal-1.csv +6 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions1-1.csv +7 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions2-1.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/opennodes-1.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/scripts/wz_tooltip.js +1301 -0
- data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.tjp +20 -0
- data/test/TestSuite/Scheduler/Correct/Container.html +349 -0
- data/test/TestSuite/Scheduler/Correct/Limits.tjp +11 -4
- data/test/TestSuite/Scheduler/Correct/Shift2.html +464 -150
- data/test/TestSuite/Scheduler/Correct/TimeSheet2.html +108 -0
- data/test/TestSuite/Scheduler/Correct/TimeSheet2.tjp +7 -0
- data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +14 -0
- data/test/TestSuite/Scheduler/Correct/css/tjreport.css +233 -21
- data/test/TestSuite/Scheduler/Correct/scripts/wz_tooltip.js +20 -20
- data/test/TestSuite/StatusSheetTemplates/project.tji +35 -0
- data/test/TestSuite/StatusSheetTemplates/project.tjp +56 -0
- data/test/TestSuite/StatusSheets/run +3 -2
- data/test/TestSuite/Syntax/Correct/Include.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/Macro-1.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/Macro-2.tjp +6 -0
- data/test/TestSuite/Syntax/Correct/Macro-3.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/ResourcePrefix.html +32 -0
- data/test/TestSuite/Syntax/Correct/css/tjmanual.css +66 -0
- data/test/TestSuite/Syntax/Correct/css/tjreport.css +407 -0
- data/test/TestSuite/Syntax/Correct/icons/details.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-green.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-red.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-yellow.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/resource.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/resourcegroup.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/task.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/taskgroup.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-down.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-flat.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-up.png +0 -0
- data/test/TestSuite/Syntax/Correct/include/dir1/file2.tji +3 -0
- data/test/TestSuite/Syntax/Correct/include/dir1/file5.tji +2 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/all.tji +3 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/file1.tji +2 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/file2.tji +1 -0
- data/test/TestSuite/Syntax/Correct/scripts/wz_tooltip.js +1301 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +13 -13
- data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
- data/test/TestSuite/Syntax/Errors/include_recursion.tjp +1 -0
- data/test/TestSuite/Syntax/Errors/macro_stack_overflow.tjp +2 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring1.tjp → no_token_match1.tjp} +2 -2
- data/test/TestSuite/Syntax/Errors/{eof_in_istring2.tjp → no_token_match2.tjp} +2 -2
- data/test/TestSuite/Syntax/Errors/{eof_in_istring3.tjp → no_token_match3.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring4.tjp → no_token_match4.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring5.tjp → no_token_match5.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/not_scheduled.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/unsupported_token.tjp +1 -1
- data/test/TestSuite/TimeSheets/run +5 -5
- data/test/test_CSVFile.rb +75 -0
- data/test/test_Limits.rb +63 -5
- data/test/test_ProjectFileScanner.rb +163 -0
- data/test/test_ReportGenerator.rb +81 -0
- data/test/test_RichText.rb +21 -3
- data/test/test_Scheduler.rb +1 -1
- data/test/test_ShiftAssignments.rb +4 -4
- data/test/test_Syntax.rb +1 -1
- data/test/test_URLParameter.rb +30 -0
- metadata +126 -32
- data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +0 -8
- data/test/TestSuite/Syntax/Errors/bad_comment.tjp +0 -7
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/boss_2002-03-01.tji +0 -36
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev1_2002-03-01.tji +0 -48
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev2_2002-03-01.tji +0 -67
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev3_2002-03-01.tji +0 -67
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/doc_2002-03-01.tji +0 -48
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/resources.yml +0 -31
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/test_2002-03-01.tji +0 -36
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/acceptable_intervals +0 -1
- data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/all.tji +0 -1
- data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/dev2_2002-03-01.tji +0 -54
- data/test/TestSuite/TimeSheets/TimeSheets/all.tji +0 -2
- data/test/TestSuite/TimeSheets/receiver.log +0 -102
- data/test/TestSuite/TimeSheets/sender.log +0 -794
- data/test/TestSuite/TimeSheets/summary.log +0 -884
- data/test/TestSuite/TimeSheets/timesheets.log +0 -45
- data/test/TestSuite/TimeSheets/tj3d.log +0 -292
- data/test/test_TextScanner.rb +0 -95
data/lib/TimeSheetReceiver.rb
CHANGED
@@ -34,6 +34,7 @@ class TaskJuggler
|
|
34
34
|
@sheetHeader = /^[ ]*timesheet\s([a-z][a-z0-9_]*)\s[0-9\-:+]*\s-\s([0-9]*-[0-9]*-[0-9]*)/
|
35
35
|
# Regular expression to extract the sheet signature (time period).
|
36
36
|
@signatureFilter = /^[ ]*timesheet\s[a-z][a-z0-9_]*\s([0-9:\-+]*\s-\s[0-9:\-+]*)/
|
37
|
+
@emailSubject = "Report from %s for %s"
|
37
38
|
end
|
38
39
|
|
39
40
|
end
|
data/lib/TimeSheetSender.rb
CHANGED
data/lib/TimeSheetSummary.rb
CHANGED
@@ -27,7 +27,7 @@ class TaskJuggler
|
|
27
27
|
super('tj3ts_summary', 'summary')
|
28
28
|
|
29
29
|
# This is a LogicalExpression string that controls what resources should
|
30
|
-
# not be
|
30
|
+
# not be considered in the summary.
|
31
31
|
@hideResource = '0'
|
32
32
|
# The base directory of the time sheet templates.
|
33
33
|
@templateDir = 'TimeSheetTemplates'
|
@@ -44,22 +44,23 @@ class TaskJuggler
|
|
44
44
|
@resourceIntro = " Weekly Report from %s\n\n"
|
45
45
|
@resourceSheetSubject = "Weekly report %s"
|
46
46
|
@summarySubject = "Weekly staff reports %s"
|
47
|
-
@reminderSubject = "Your
|
47
|
+
@reminderSubject = "Your time sheet for the period ending %s is overdue!"
|
48
48
|
@reminderText = <<'EOT'
|
49
|
-
The deadline for your
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
report.
|
49
|
+
The deadline for your time sheet submission has passed but we haven't received
|
50
|
+
it yet. Please submit your time sheet immediately so the content can still be
|
51
|
+
included in the management reports. Please send a copy of your submission
|
52
|
+
notification email to your manager. If possible, your manager will still try
|
53
|
+
to include your report data in his/her report.
|
55
54
|
|
56
|
-
Please be aware that post deadline submissions must be processed
|
57
|
-
|
58
|
-
|
55
|
+
Please be aware that post deadline submissions must be processed manually and
|
56
|
+
create an additional load for your manager and/or project manager. Please try
|
57
|
+
to submit in time in the future.
|
59
58
|
|
60
59
|
Thanks for your cooperation!
|
61
60
|
|
62
61
|
EOT
|
62
|
+
@defaulterHeader = "The following %d person(s) have not yet submitted " +
|
63
|
+
"their time sheets:\n\n"
|
63
64
|
end
|
64
65
|
|
65
66
|
def sendSummary(resourceIds)
|
@@ -77,37 +78,61 @@ EOT
|
|
77
78
|
sheetFile = "#{@sheetDir}/#{@date}/#{resourceId}_#{@date}.tji"
|
78
79
|
if File.exist?(templateFile)
|
79
80
|
if File.exists?(sheetFile)
|
80
|
-
#
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
# If there are no recipients specified, we don't need to compile
|
82
|
+
# the summary.
|
83
|
+
unless @digestRecipients.empty? && @sheetRecipients.empty?
|
84
|
+
# Resource has submitted a time sheet
|
85
|
+
sheet = getResourceJournal(sheetFile)
|
86
|
+
summary += sprintf(@resourceIntro, resourceName)
|
87
|
+
summary += sheet + "\n#{'-' * 74}\n\n"
|
88
|
+
info("Adding report from #{resourceName} to summary")
|
89
|
+
|
90
|
+
@sheetRecipients.each do |to|
|
91
|
+
sendEmail(to, sprintf(@resourceSheetSubject, @date), sheet,
|
92
|
+
nil, "#{resourceName} <#{resourceEmail}>")
|
93
|
+
end
|
89
94
|
end
|
90
95
|
else
|
91
96
|
defaulterList << resource
|
92
97
|
# Resource did not submit a time sheet
|
93
|
-
summary += "\n Report from #{resourceName} is missing\n\n"
|
94
98
|
info("Report from #{resourceId} is missing")
|
95
99
|
end
|
96
|
-
summary += "\n#{'-' * 74}\n\n"
|
97
100
|
end
|
98
101
|
end
|
99
102
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
+
unless defaulterList.empty?
|
104
|
+
# Prepend the defaulter list to the summary.
|
105
|
+
text = sprintf(@defaulterHeader, defaulterList.length)
|
103
106
|
defaulterList.each do |resource|
|
104
|
-
|
107
|
+
text += " * #{resource[1]}\n"
|
108
|
+
end
|
109
|
+
text += "\n#{'-' * 74}\n\n"
|
110
|
+
summary = text + summary
|
111
|
+
|
112
|
+
# Create a file with the IDs of the resources who's reports are
|
113
|
+
# missing.
|
114
|
+
missingFile = "#{@sheetDir}/#{@date}/missing-reports"
|
115
|
+
begin
|
116
|
+
File.open(missingFile, 'w') do |f|
|
117
|
+
defaulterList.each { |resource| f.puts resource[0] }
|
118
|
+
end
|
119
|
+
rescue
|
120
|
+
error("Cannot write file with missing reports (#missingFile): #{$!}")
|
105
121
|
end
|
106
122
|
end
|
107
123
|
|
124
|
+
# Send out the summary text to the list of digest recipients.
|
108
125
|
@digestRecipients.each do |to|
|
109
126
|
sendEmail(to, sprintf(@summarySubject, @date), summary)
|
110
127
|
end
|
128
|
+
|
129
|
+
# If there is a reminder text defined, resend the template to those
|
130
|
+
# individuals that have not yet submitted their report yet.
|
131
|
+
if @reminderText && !@reminderText.empty?
|
132
|
+
defaulterList.each do |resource|
|
133
|
+
sendReminder(resource[0], resource[1], resource[2])
|
134
|
+
end
|
135
|
+
end
|
111
136
|
end
|
112
137
|
|
113
138
|
private
|
data/lib/TimeSheets.rb
CHANGED
@@ -212,7 +212,7 @@ class TaskJuggler
|
|
212
212
|
resource = @timeSheet.resource
|
213
213
|
project = resource.project
|
214
214
|
scenarioIdx = @timeSheet.scenarioIdx
|
215
|
-
startIdx = project.dateToIdx(project['now'])
|
215
|
+
startIdx = project.dateToIdx(project['now'], true)
|
216
216
|
endIdx = project.dateToIdx(@task['end', scenarioIdx])
|
217
217
|
remainingWork = @task.getEffectiveWork(scenarioIdx, startIdx, endIdx,
|
218
218
|
resource)
|
data/lib/Tj3AppBase.rb
CHANGED
@@ -55,6 +55,9 @@ class TaskJuggler
|
|
55
55
|
format("Don't show program and progress information")) do
|
56
56
|
@silent = true
|
57
57
|
end
|
58
|
+
@opts.on('--debug', format('Enable Ruby debug mode')) do
|
59
|
+
$DEBUG = true
|
60
|
+
end
|
58
61
|
|
59
62
|
yield
|
60
63
|
|
@@ -81,13 +84,17 @@ class TaskJuggler
|
|
81
84
|
|
82
85
|
def main
|
83
86
|
# Install signal handler to exit gracefully on CTRL-C.
|
84
|
-
Kernel.trap('INT') do
|
87
|
+
intHandler = Kernel.trap('INT') do
|
85
88
|
puts "\nAborting on user request!"
|
86
89
|
exit 1
|
87
90
|
end
|
88
91
|
|
89
92
|
args = processArguments(ARGV)
|
90
93
|
|
94
|
+
# If DEBUG mode has been enabled, we restore the INT trap handler again
|
95
|
+
# to get Ruby backtrackes.
|
96
|
+
Kernel.trap('INT', intHandler) if $DEBUG
|
97
|
+
|
91
98
|
unless @silent
|
92
99
|
puts "#{AppConfig.softwareName} v#{AppConfig.version} - " +
|
93
100
|
"#{AppConfig.packageInfo}\n\n" +
|
data/lib/Tj3Config.rb
CHANGED
data/lib/TjTime.rb
CHANGED
data/lib/TjpSyntaxRules.rb
CHANGED
@@ -56,10 +56,11 @@ EOT
|
|
56
56
|
@property = @project.accout(@accountprefix)
|
57
57
|
end
|
58
58
|
if @val[1] && @project.account(@val[1])
|
59
|
-
error('account_exists', "Account #{@val[1]} has already been defined."
|
59
|
+
error('account_exists', "Account #{@val[1]} has already been defined.",
|
60
|
+
@property, @sourceFileInfo[1])
|
60
61
|
end
|
61
62
|
@property = Account.new(@project, @val[1], @val[2], @property)
|
62
|
-
@property.sourceFileInfo = @
|
63
|
+
@property.sourceFileInfo = @sourceFileInfo[0]
|
63
64
|
@property.inheritAttributes
|
64
65
|
@scenarioIdx = 0
|
65
66
|
})
|
@@ -73,7 +74,8 @@ EOT
|
|
73
74
|
# In case we have a nested supplement, we need to prepend the parent ID.
|
74
75
|
id = @property.fullId + '.' + id if @property && @property.is_a?(Account)
|
75
76
|
if (account = @project.account(id)).nil?
|
76
|
-
error('unknown_account', "Unknown account #{id}"
|
77
|
+
error('unknown_account', "Unknown account #{id}", nil,
|
78
|
+
@sourceFileInfo[0])
|
77
79
|
end
|
78
80
|
account
|
79
81
|
})
|
@@ -107,7 +109,7 @@ EOT
|
|
107
109
|
level = @project.alertLevelIndex(@val[0])
|
108
110
|
unless level
|
109
111
|
error('bad_alert', "Unknown alert level #{@val[1]}. Must be " +
|
110
|
-
'green, yellow or red')
|
112
|
+
'green, yellow or red', nil, @sourceFileInfo[0])
|
111
113
|
end
|
112
114
|
level
|
113
115
|
})
|
@@ -171,7 +173,7 @@ EOT
|
|
171
173
|
pattern(%w( !limits ), lambda {
|
172
174
|
limits = @property['limits', @scenarioIdx] = @val[0]
|
173
175
|
@allocate.candidates.each do |resource|
|
174
|
-
limits.limits.
|
176
|
+
limits.limits.each do |l|
|
175
177
|
l.resource = resource if resource.leaf?
|
176
178
|
end
|
177
179
|
end
|
@@ -257,7 +259,7 @@ EOT
|
|
257
259
|
# Make sure we have a ShiftAssignment for the allocation.
|
258
260
|
if @allocate.shift.nil?
|
259
261
|
@allocate.shift = ShiftAssignments.new
|
260
|
-
@allocate.shift.
|
262
|
+
@allocate.shift.project = @project
|
261
263
|
end
|
262
264
|
|
263
265
|
if @val[1].nil?
|
@@ -270,7 +272,7 @@ EOT
|
|
270
272
|
addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
|
271
273
|
interval))
|
272
274
|
error('shift_assignment_overlap',
|
273
|
-
'Shifts may not overlap each other.')
|
275
|
+
'Shifts may not overlap each other.', nil, @sourceFileInfo[0])
|
274
276
|
end
|
275
277
|
end
|
276
278
|
})
|
@@ -313,16 +315,18 @@ EOT
|
|
313
315
|
pattern(%w( _balance !accountId !accountId ), lambda {
|
314
316
|
if @val[1].parent
|
315
317
|
error('cost_acct_no_top',
|
316
|
-
"The cost account #{@val[1].fullId} is not a top-level account."
|
318
|
+
"The cost account #{@val[1].fullId} is not a top-level account.",
|
319
|
+
nil, @sourceFileInfo[1])
|
317
320
|
end
|
318
321
|
if @val[2].parent
|
319
322
|
error('rev_acct_no_top',
|
320
323
|
"The revenue account #{@val[2].fullId} is not a top-level " +
|
321
|
-
"account.")
|
324
|
+
"account.", nil, @sourceFileInfo[2])
|
322
325
|
end
|
323
326
|
if @val[1] == @val[2]
|
324
327
|
error('cost_rev_same',
|
325
|
-
'The cost and revenue accounts may not be the same.'
|
328
|
+
'The cost and revenue accounts may not be the same.', nil,
|
329
|
+
@sourceFileInfo[1])
|
326
330
|
end
|
327
331
|
[ @val[1], @val[2] ]
|
328
332
|
})
|
@@ -347,7 +351,8 @@ EOT
|
|
347
351
|
pattern(%w( _overtime $INTEGER ), lambda {
|
348
352
|
if @val[1] < 0 || @val[1] > 2
|
349
353
|
error('overtime_range',
|
350
|
-
"Overtime value #{@val[1]} out of range (0 - 2).", @property
|
354
|
+
"Overtime value #{@val[1]} out of range (0 - 2).", @property,
|
355
|
+
@sourceFileInfo[1])
|
351
356
|
end
|
352
357
|
@booking.overtime = @val[1]
|
353
358
|
})
|
@@ -368,7 +373,8 @@ EOT
|
|
368
373
|
pattern(%w( _sloppy $INTEGER ), lambda {
|
369
374
|
if @val[1] < 0 || @val[1] > 2
|
370
375
|
error('sloppy_range',
|
371
|
-
"Sloppyness value #{@val[1]} out of range (0 - 2).", @property
|
376
|
+
"Sloppyness value #{@val[1]} out of range (0 - 2).", @property,
|
377
|
+
@sourceFileInfo[1])
|
372
378
|
end
|
373
379
|
@booking.sloppy = @val[1]
|
374
380
|
})
|
@@ -422,7 +428,7 @@ EOT
|
|
422
428
|
end
|
423
429
|
chargeSet.complete
|
424
430
|
rescue TjException
|
425
|
-
error('chargeset', $!.message)
|
431
|
+
error('chargeset', $!.message, @property, @sourceFileInfo[0])
|
426
432
|
end
|
427
433
|
masterAccounts = []
|
428
434
|
@property['chargeset', @scenarioIdx].each do |set|
|
@@ -431,7 +437,7 @@ EOT
|
|
431
437
|
if masterAccounts.include?(chargeSet.master)
|
432
438
|
error('chargeset_master',
|
433
439
|
"All charge sets for this task must have different top-level " +
|
434
|
-
"accounts.")
|
440
|
+
"accounts.", @property, @sourceFileInfo[0])
|
435
441
|
end
|
436
442
|
@property['chargeset', @scenarioIdx] =
|
437
443
|
@property['chargeset', @scenarioIdx] + [ chargeSet ]
|
@@ -499,7 +505,8 @@ EOT
|
|
499
505
|
col = @val[0]
|
500
506
|
unless /#[0-9A-Fa-f]{3}/ =~ col || /#[0-9A-Fa-f]{3}/ =~ col
|
501
507
|
error('bad_color',
|
502
|
-
"Color values must be specified as '#RGB' or '#RRGGBB' values"
|
508
|
+
"Color values must be specified as '#RGB' or '#RRGGBB' values",
|
509
|
+
nil, @sourceFileInfo[0])
|
503
510
|
end
|
504
511
|
col
|
505
512
|
})
|
@@ -586,6 +593,18 @@ Specifies an alternative font color for the cells of this column. The
|
|
586
593
|
logical expression specifies for which cells the color should be used. If
|
587
594
|
multiple fontcolor patterns are provided for a column, the first
|
588
595
|
matching one is used for each cell.
|
596
|
+
EOT
|
597
|
+
)
|
598
|
+
|
599
|
+
pattern(%w( _halign !logicalExpression !hAlignment ), lambda {
|
600
|
+
@column.hAlign.addPattern(
|
601
|
+
CellSettingPattern.new(@val[2], @val[1]))
|
602
|
+
})
|
603
|
+
doc('halign.column', <<'EOT'
|
604
|
+
Specifies the horizontal alignment of the cell content. The logical expression
|
605
|
+
specifies for which cells the alignment setting should be used. If multiple
|
606
|
+
halign patterns are provided for a column, the first matching one is used for
|
607
|
+
each cell.
|
589
608
|
EOT
|
590
609
|
)
|
591
610
|
|
@@ -666,7 +685,8 @@ EOT
|
|
666
685
|
if @val[0] % resolution != 0
|
667
686
|
error('misaligned_date',
|
668
687
|
"The date must be aligned to the timing resolution (" +
|
669
|
-
"#{resolution / 60} min) of the project."
|
688
|
+
"#{resolution / 60} min) of the project.", nil,
|
689
|
+
@sourceFileInfo[0])
|
670
690
|
end
|
671
691
|
@val[0]
|
672
692
|
})
|
@@ -712,11 +732,12 @@ EOT
|
|
712
732
|
|
713
733
|
rtTokenSetMore =
|
714
734
|
%w( LINEBREAK SPACE WORD BOLD ITALIC CODE BOLDITALIC PRE HREF HREFEND
|
715
|
-
REF REFEND HLINE TITLE2 TITLE3 TITLE2END TITLE3END
|
716
|
-
BULLET3 NUMBER1 NUMBER2 NUMBER3 )
|
735
|
+
REF REFEND HLINE TITLE2 TITLE3 TITLE4 TITLE2END TITLE3END TITLE4END
|
736
|
+
BULLET1 BULLET2 BULLET3 BULLET4 NUMBER1 NUMBER2 NUMBER3 NUMBER4 )
|
717
737
|
if @val[1] == "Some more details\n"
|
718
738
|
error('ts_default_details',
|
719
|
-
"'Some more details' is not a valid value"
|
739
|
+
"'Some more details' is not a valid value", nil,
|
740
|
+
@sourceFileInfo[1])
|
720
741
|
end
|
721
742
|
@journalEntry.details = newRichText(@val[1], rtTokenSetMore)
|
722
743
|
})
|
@@ -773,23 +794,19 @@ EOT
|
|
773
794
|
@property = nil
|
774
795
|
})
|
775
796
|
doc('export', <<'EOT'
|
776
|
-
The export report looks like a regular TaskJuggler file
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
If specified the resource usage for the tasks is reported as well. But only
|
786
|
-
those allocations are listed that belong to tasks listed in the same export
|
787
|
-
report.
|
797
|
+
The export report looks like a regular TaskJuggler file with the provided
|
798
|
+
input data complemented by the results of the scheduling process. The content
|
799
|
+
of the report can be controlled with the [[definitions]] attribute. In case
|
800
|
+
the file contains the project header, a ''''.tjp'''' extension is added to the
|
801
|
+
file name. Otherwise, a ''''.tji'''' extension is used.
|
802
|
+
|
803
|
+
The [[resourceattributes]] and [[taskattributes]] attributes provide even more
|
804
|
+
control over the content of the file.
|
788
805
|
|
789
806
|
The export report can be used to share certain tasks or milestones with other
|
790
807
|
projects or to save past resource allocations as immutable part for future
|
791
808
|
scheduling runs. When an export report is included the project IDs of the
|
792
|
-
included tasks must be declared first with the project id property
|
809
|
+
included tasks must be declared first with the project id property.
|
793
810
|
EOT
|
794
811
|
)
|
795
812
|
example('Export')
|
@@ -817,6 +834,8 @@ EOT
|
|
817
834
|
This attributes controls what definitions will be contained in the report. If
|
818
835
|
the list includes ''project'', the generated file will have a ''''.tjp''''
|
819
836
|
extension. Otherwise it will have a ''''.tji'''' extension.
|
837
|
+
|
838
|
+
By default, the report contains everything and the generated files has a ''''.tjp'''' extension.
|
820
839
|
EOT
|
821
840
|
)
|
822
841
|
allOrNothingListRule('exportDefinitions',
|
@@ -946,7 +965,8 @@ EOT
|
|
946
965
|
pattern(%w( $ID ), lambda {
|
947
966
|
unless (?A..?Z) === @val[0][0]
|
948
967
|
error('extend_id_cap',
|
949
|
-
"User defined attributes IDs must start with a capital letter"
|
968
|
+
"User defined attributes IDs must start with a capital letter",
|
969
|
+
nil, @sourceFileInfo[0])
|
950
970
|
end
|
951
971
|
@val[0]
|
952
972
|
})
|
@@ -1005,7 +1025,7 @@ EOT
|
|
1005
1025
|
The fail attribute adds a logical expression to the property. The condition
|
1006
1026
|
described by the logical expression is checked after the scheduling and an
|
1007
1027
|
error is raised if the condition evaluates to true. This attribute is
|
1008
|
-
primarily intended for testing
|
1028
|
+
primarily intended for testing purposes.
|
1009
1029
|
EOT
|
1010
1030
|
)
|
1011
1031
|
end
|
@@ -1013,7 +1033,8 @@ EOT
|
|
1013
1033
|
def rule_flag
|
1014
1034
|
pattern(%w( $ID ), lambda {
|
1015
1035
|
unless @project['flags'].include?(@val[0])
|
1016
|
-
error('undecl_flag', "Undeclared flag '#{@val[0]}'"
|
1036
|
+
error('undecl_flag', "Undeclared flag '#{@val[0]}'", nil,
|
1037
|
+
@sourceFileInfo[0])
|
1017
1038
|
end
|
1018
1039
|
@val[0]
|
1019
1040
|
})
|
@@ -1133,6 +1154,15 @@ EOT
|
|
1133
1154
|
arg(2, 'Resource ID', 'The ID of a defined resource')
|
1134
1155
|
arg(4, 'Scenario ID', 'A scenario ID')
|
1135
1156
|
|
1157
|
+
pattern(%w( _isfeatureof _( $ID _, $ID _) ))
|
1158
|
+
doc('isfeatureof', <<'EOT'
|
1159
|
+
If the provided task or any of its sub-tasks depend on this task or any of its
|
1160
|
+
sub-tasks, we call this task a feature of the provided task.
|
1161
|
+
EOT
|
1162
|
+
)
|
1163
|
+
arg(2, 'Task ID', 'The ID of a defined task')
|
1164
|
+
arg(4, 'Scenario ID', 'A scenario ID')
|
1165
|
+
|
1136
1166
|
pattern(['_isleaf', '_(', '_)' ])
|
1137
1167
|
doc('isleaf', 'The result is true if the property is not a container.')
|
1138
1168
|
|
@@ -1158,6 +1188,23 @@ EOT
|
|
1158
1188
|
)
|
1159
1189
|
end
|
1160
1190
|
|
1191
|
+
def rule_hAlignment
|
1192
|
+
pattern(%w( _center ), lambda {
|
1193
|
+
:center
|
1194
|
+
})
|
1195
|
+
doc('halign.center', 'Center the cell content')
|
1196
|
+
|
1197
|
+
pattern(%w( _left ), lambda {
|
1198
|
+
:left
|
1199
|
+
})
|
1200
|
+
doc('halign.left', 'Left align the cell content')
|
1201
|
+
|
1202
|
+
pattern(%w( _right ), lambda {
|
1203
|
+
:right
|
1204
|
+
})
|
1205
|
+
doc('halign.right', 'Right align the cell content')
|
1206
|
+
end
|
1207
|
+
|
1161
1208
|
def rule_headline
|
1162
1209
|
pattern(%w( _headline $STRING ), lambda {
|
1163
1210
|
@property.set('headline', newRichText(@val[1]))
|
@@ -1183,6 +1230,7 @@ report is sorted in tree mode (default) then enclosing resources are listed
|
|
1183
1230
|
even if the expression matches the resource.
|
1184
1231
|
EOT
|
1185
1232
|
)
|
1233
|
+
also(%w( sortresources ))
|
1186
1234
|
end
|
1187
1235
|
|
1188
1236
|
def rule_hidetask
|
@@ -1195,6 +1243,7 @@ report is sorted in tree mode (default) then enclosing tasks are listed even
|
|
1195
1243
|
if the expression matches the task.
|
1196
1244
|
EOT
|
1197
1245
|
)
|
1246
|
+
also(%w( sorttasks ))
|
1198
1247
|
end
|
1199
1248
|
|
1200
1249
|
def rule_idOrAbsoluteId
|
@@ -1256,7 +1305,7 @@ EOT
|
|
1256
1305
|
|
1257
1306
|
def rule_includeFile
|
1258
1307
|
pattern(%w( !includeFileName ), lambda {
|
1259
|
-
@scanner.include(@val[0])
|
1308
|
+
@scanner.include(@val[0], @sourceFileInfo[0])
|
1260
1309
|
})
|
1261
1310
|
end
|
1262
1311
|
|
@@ -1264,7 +1313,8 @@ EOT
|
|
1264
1313
|
pattern(%w( $STRING ), lambda {
|
1265
1314
|
unless @val[0][-4, 4] == '.tji'
|
1266
1315
|
error('bad_include_suffix', "Included files must have a '.tji'" +
|
1267
|
-
"extension: '#{@val[0]}'"
|
1316
|
+
"extension: '#{@val[0]}'",
|
1317
|
+
nil, @sourceFileInfo[0])
|
1268
1318
|
end
|
1269
1319
|
@val[0]
|
1270
1320
|
})
|
@@ -1279,7 +1329,7 @@ EOT
|
|
1279
1329
|
def rule_includeProperties
|
1280
1330
|
pattern(%w( !includeFileName !includeAttributes ), lambda {
|
1281
1331
|
pushFileStack
|
1282
|
-
@scanner.include(@val[0])
|
1332
|
+
@scanner.include(@val[0], @sourceFileInfo[0])
|
1283
1333
|
})
|
1284
1334
|
end
|
1285
1335
|
|
@@ -1291,7 +1341,7 @@ EOT
|
|
1291
1341
|
if mode == 0
|
1292
1342
|
unless @val[0] < endSpec
|
1293
1343
|
error('start_before_end', "The end date (#{endSpec}) must be " +
|
1294
|
-
"after the start date (#{@val[0]}).")
|
1344
|
+
"after the start date (#{@val[0]}).", nil, @sourceFileInfo[0])
|
1295
1345
|
end
|
1296
1346
|
Interval.new(@val[0], endSpec)
|
1297
1347
|
else
|
@@ -1322,7 +1372,7 @@ EOT
|
|
1322
1372
|
if mode == 0
|
1323
1373
|
unless @val[0] < endSpec
|
1324
1374
|
error('start_before_end', "The end date (#{endSpec}) must be after " +
|
1325
|
-
"the start date (#{@val[0]}).")
|
1375
|
+
"the start date (#{@val[0]}).", nil, @sourceFileInfo[0])
|
1326
1376
|
end
|
1327
1377
|
Interval.new(@val[0], endSpec)
|
1328
1378
|
else
|
@@ -1352,7 +1402,8 @@ EOT
|
|
1352
1402
|
60 * 60 * 24 * 365 # years
|
1353
1403
|
]
|
1354
1404
|
if @val[0] == 0.0
|
1355
|
-
error('zero_duration', "The interval duration may not be 0."
|
1405
|
+
error('zero_duration', "The interval duration may not be 0.", nil,
|
1406
|
+
@sourceFileInfo[1])
|
1356
1407
|
end
|
1357
1408
|
duration = @val[0] * convFactors[@val[1]]
|
1358
1409
|
resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
|
@@ -1363,7 +1414,7 @@ EOT
|
|
1363
1414
|
end
|
1364
1415
|
|
1365
1416
|
def rule_intervalEnd
|
1366
|
-
pattern([ '_
|
1417
|
+
pattern([ '_-', '!date' ], lambda {
|
1367
1418
|
[ 0, @val[1] ]
|
1368
1419
|
})
|
1369
1420
|
|
@@ -1374,7 +1425,7 @@ EOT
|
|
1374
1425
|
|
1375
1426
|
def rule_intervalOptionalEnd
|
1376
1427
|
optional
|
1377
|
-
pattern([ '_
|
1428
|
+
pattern([ '_-', '!date' ], lambda {
|
1378
1429
|
[ 0, @val[1] ]
|
1379
1430
|
})
|
1380
1431
|
|
@@ -1421,7 +1472,7 @@ EOT
|
|
1421
1472
|
level = @project.alertLevelIndex(@val[1])
|
1422
1473
|
unless level
|
1423
1474
|
error('bad_alert', "Unknown alert level #{@val[1]}. Must be " +
|
1424
|
-
'green, yellow or red')
|
1475
|
+
'green, yellow or red', nil, @sourceFileInfo[0])
|
1425
1476
|
end
|
1426
1477
|
@journalEntry.alertLevel = level
|
1427
1478
|
})
|
@@ -1451,7 +1502,7 @@ EOT
|
|
1451
1502
|
def rule_journalEntryHeader
|
1452
1503
|
pattern(%w( _journalentry !valDate $STRING ), lambda {
|
1453
1504
|
@journalEntry = JournalEntry.new(@project['journal'], @val[1], @val[2],
|
1454
|
-
@property, @
|
1505
|
+
@property, @sourceFileInfo[0])
|
1455
1506
|
})
|
1456
1507
|
arg(2, 'headline', <<'EOT'
|
1457
1508
|
The headline of the journal entry. It will be interpreted as
|
@@ -1464,7 +1515,7 @@ EOT
|
|
1464
1515
|
resource = @val[0]
|
1465
1516
|
unless resource.leaf?
|
1466
1517
|
error('leaf_resource_id_expected',
|
1467
|
-
"#{resource.id} is not a leaf resource.")
|
1518
|
+
"#{resource.id} is not a leaf resource.", nil, @sourceFileInfo[0])
|
1468
1519
|
end
|
1469
1520
|
resource
|
1470
1521
|
})
|
@@ -1711,7 +1762,7 @@ EOT
|
|
1711
1762
|
if @scanner.macroDefined?(@val[1])
|
1712
1763
|
warning('marco_redefinition', "Redefining macro #{@val[1]}")
|
1713
1764
|
end
|
1714
|
-
@scanner.addMacro(Macro.new(@val[1], @val[2], @
|
1765
|
+
@scanner.addMacro(Macro.new(@val[1], @val[2], @sourceFileInfo[0]))
|
1715
1766
|
})
|
1716
1767
|
doc('macro', <<'EOT'
|
1717
1768
|
Defines a text fragment that can later be inserted by using the specified ID.
|
@@ -1730,14 +1781,17 @@ numbers as names. The number specifies the index of the argument.
|
|
1730
1781
|
macro FOO [ This ${1} text ]
|
1731
1782
|
|
1732
1783
|
will expand to ''''This stupid text'''' if called as ''''${FOO "stupid"}''''.
|
1733
|
-
Macros may call other macros.
|
1784
|
+
Macros may call other macros. All macro arguments must be enclosed by double
|
1785
|
+
quotes. In case the argument contains a double quote, it must be escaped by a
|
1786
|
+
slash (''''/'''').
|
1734
1787
|
|
1735
1788
|
User defined macro IDs must have at least one uppercase letter as all
|
1736
1789
|
lowercase letter IDs are reserved for built-in macros.
|
1737
1790
|
|
1738
|
-
|
1739
|
-
|
1740
|
-
''''<nowiki>
|
1791
|
+
To terminate the macro definition, the ''''<nowiki>]</nowiki>'''' must be the
|
1792
|
+
last character in the line. If there are any other characters trailing it
|
1793
|
+
(even spaces or comments) the ''''<nowiki>]</nowiki>'''' will not be
|
1794
|
+
considered the end of the macro definition.
|
1741
1795
|
|
1742
1796
|
In macro calls the macro names can be prefixed by a question mark. In this
|
1743
1797
|
case the macro will expand to nothing if the macro is not defined. Otherwise
|
@@ -1840,7 +1894,8 @@ EOT
|
|
1840
1894
|
pattern(%w( _navigator $ID ), lambda {
|
1841
1895
|
if @project['navigators'][@val[1]]
|
1842
1896
|
error('navigator_exists',
|
1843
|
-
"The navigator #{@val[1]} has already been defined."
|
1897
|
+
"The navigator #{@val[1]} has already been defined.", nil,
|
1898
|
+
@sourceFileInfo[0])
|
1844
1899
|
end
|
1845
1900
|
@navigator = Navigator.new(@val[1], @project)
|
1846
1901
|
})
|
@@ -1893,6 +1948,49 @@ EOT
|
|
1893
1948
|
example('Niku')
|
1894
1949
|
end
|
1895
1950
|
|
1951
|
+
def rule_nodeId
|
1952
|
+
pattern(%w( !idOrAbsoluteId !subNodeId ), lambda {
|
1953
|
+
case @property.typeSpec
|
1954
|
+
when :taskreport
|
1955
|
+
if (p1 = @project.task(@val[0])).nil?
|
1956
|
+
error('unknown_main_node',
|
1957
|
+
"Unknown task ID #{@val[0]}", nil, @sourceFileInfo[0])
|
1958
|
+
end
|
1959
|
+
if @val[1]
|
1960
|
+
if (p2 = @project.resource(@val[1])).nil?
|
1961
|
+
error('unknown_sub_node',
|
1962
|
+
"Unknown resource ID #{@val[0]}", nil, @sourceFileInfo[0])
|
1963
|
+
end
|
1964
|
+
return [ p2, p1 ]
|
1965
|
+
end
|
1966
|
+
return [ p1, nil ]
|
1967
|
+
when :resourcereport
|
1968
|
+
if (p1 = @project.task(@val[0])).nil?
|
1969
|
+
error('unknown_main_node',
|
1970
|
+
"Unknown task ID #{@val[0]}", nil, @sourceFileInfo[0])
|
1971
|
+
end
|
1972
|
+
if @val[1]
|
1973
|
+
if (p2 = @project.resource(@val[1])).nil?
|
1974
|
+
error('unknown_sub_node',
|
1975
|
+
"Unknown resource ID #{@val[0]}", nil, @sourceFileInfo[0])
|
1976
|
+
end
|
1977
|
+
return [ p2, p1 ]
|
1978
|
+
end
|
1979
|
+
return [ p1, nil ]
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
raise "Node list is not supported for this report type: " +
|
1983
|
+
"#{@property.typeSpec}"
|
1984
|
+
})
|
1985
|
+
end
|
1986
|
+
|
1987
|
+
def rule_nodeIdList
|
1988
|
+
listRule('moreNodeIdList', '!nodeId')
|
1989
|
+
pattern([ '_-' ], lambda {
|
1990
|
+
[]
|
1991
|
+
})
|
1992
|
+
end
|
1993
|
+
|
1896
1994
|
def rule_number
|
1897
1995
|
singlePattern('$INTEGER')
|
1898
1996
|
singlePattern('$FLOAT')
|
@@ -1911,12 +2009,13 @@ EOT
|
|
1911
2009
|
pattern(%w( $ABSOLUTE_ID ), lambda {
|
1912
2010
|
if @val[0].count('.') > 1
|
1913
2011
|
error('operand_attribute',
|
1914
|
-
'Attributes must be specified as <scenarioID>.<attribute>'
|
2012
|
+
'Attributes must be specified as <scenarioID>.<attribute>', nil,
|
2013
|
+
@sourceFileInfo[0])
|
1915
2014
|
end
|
1916
2015
|
scenario, attribute = @val[0].split('.')
|
1917
2016
|
if (scenarioIdx = @project.scenarioIdx(scenario)).nil?
|
1918
|
-
error('operand_unkn_scen',
|
1919
|
-
|
2017
|
+
error('operand_unkn_scen', "Unknown scenario ID #{scenario}", nil,
|
2018
|
+
@sourceFileInfo[0])
|
1920
2019
|
end
|
1921
2020
|
LogicalAttribute.new(attribute, scenarioIdx)
|
1922
2021
|
})
|
@@ -1926,7 +2025,8 @@ EOT
|
|
1926
2025
|
pattern(%w( $ID !argumentList ), lambda {
|
1927
2026
|
if @val[1].nil?
|
1928
2027
|
unless @project['flags'].include?(@val[0])
|
1929
|
-
error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'"
|
2028
|
+
error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'",
|
2029
|
+
nil, @sourceFileInfo[0])
|
1930
2030
|
end
|
1931
2031
|
LogicalFlag.new(@val[0])
|
1932
2032
|
else
|
@@ -1966,10 +2066,10 @@ EOT
|
|
1966
2066
|
arg(0, 'operand', <<'EOT'
|
1967
2067
|
An operand can consist of a date, a text string, a [[functions|function]], a
|
1968
2068
|
property attribute or a numerical value. It can also be the name of a declared
|
1969
|
-
flag. Use the
|
1970
|
-
evaluated property. The scenario ID always has to be specified, also
|
1971
|
-
non-scenario specific attributes. This is necessary to distinguish them
|
1972
|
-
flags.
|
2069
|
+
flag. Use the ''''scenario_id.attribute'''' notation to use an attribute of the
|
2070
|
+
currently evaluated property. The scenario ID always has to be specified, also
|
2071
|
+
for non-scenario specific attributes. This is necessary to distinguish them
|
2072
|
+
from flags.
|
1973
2073
|
|
1974
2074
|
An operand can be a negated operand by prefixing a ~ charater or it can be
|
1975
2075
|
another logical expression enclosed in braces.
|
@@ -2087,11 +2187,11 @@ EOT
|
|
2087
2187
|
|
2088
2188
|
def rule_plusOrMinus
|
2089
2189
|
singlePattern('_+')
|
2090
|
-
singlePattern('_
|
2190
|
+
singlePattern('_-')
|
2091
2191
|
end
|
2092
2192
|
|
2093
2193
|
def rule_project
|
2094
|
-
pattern(%w( !projectProlog !projectDeclaration !properties ), lambda {
|
2194
|
+
pattern(%w( !projectProlog !projectDeclaration !properties . ), lambda {
|
2095
2195
|
@val[1]
|
2096
2196
|
})
|
2097
2197
|
end
|
@@ -2132,8 +2232,9 @@ EOT
|
|
2132
2232
|
Set the average number of working hours per day. This is used as
|
2133
2233
|
the base to convert working hours into working days. This affects
|
2134
2234
|
for example the length task attribute. The default value is 8 hours
|
2135
|
-
and should work for most Western countries. The value you specify
|
2136
|
-
|
2235
|
+
and should work for most Western countries. The value you specify should match
|
2236
|
+
the settings you specified as your default [[workinghours.project|working
|
2237
|
+
hours]].
|
2137
2238
|
EOT
|
2138
2239
|
)
|
2139
2240
|
example('Project')
|
@@ -2161,9 +2262,9 @@ EOT
|
|
2161
2262
|
pattern(%w( _now !date ), lambda {
|
2162
2263
|
@project['now'] = @val[1]
|
2163
2264
|
@scanner.addMacro(Macro.new('now', @val[1].to_s,
|
2164
|
-
@
|
2265
|
+
@sourceFileInfo[0]))
|
2165
2266
|
@scanner.addMacro(Macro.new('today', @val[1].to_s(@project['timeFormat']),
|
2166
|
-
@
|
2267
|
+
@sourceFileInfo[0]))
|
2167
2268
|
})
|
2168
2269
|
doc('now', <<'EOT'
|
2169
2270
|
Specify the date that TaskJuggler uses for calculation as current
|
@@ -2208,12 +2309,14 @@ EOT
|
|
2208
2309
|
goodValues = [ 5, 10, 15, 20, 30, 60 ]
|
2209
2310
|
unless goodValues.include?(@val[1])
|
2210
2311
|
error('bad_timing_res',
|
2211
|
-
"Timing resolution must be one of #{goodValues.join(', ')} min."
|
2312
|
+
"Timing resolution must be one of #{goodValues.join(', ')} min.",
|
2313
|
+
nil, @sourceFileInfo[1])
|
2212
2314
|
end
|
2213
2315
|
if @val[1] > (Project.maxScheduleGranularity / 60)
|
2214
2316
|
error('too_large_timing_res',
|
2215
2317
|
'The maximum allowed timing resolution for the timezone is ' +
|
2216
|
-
"#{Project.maxScheduleGranularity / 60} minutes."
|
2318
|
+
"#{Project.maxScheduleGranularity / 60} minutes.", nil,
|
2319
|
+
@sourceFileInfo[1])
|
2217
2320
|
end
|
2218
2321
|
@project['scheduleGranularity'] = @val[1] * 60
|
2219
2322
|
})
|
@@ -2283,6 +2386,7 @@ EOT
|
|
2283
2386
|
@messageHandler)
|
2284
2387
|
@project['start'] = @val[4].start
|
2285
2388
|
@project['end'] = @val[4].end
|
2389
|
+
@projectId = @val[1]
|
2286
2390
|
setGlobalMacros
|
2287
2391
|
@property = nil
|
2288
2392
|
@reportCounter = 0
|
@@ -2381,10 +2485,12 @@ EOT
|
|
2381
2485
|
|
2382
2486
|
def rule_properties
|
2383
2487
|
pattern(%w( !propertiesBody . ))
|
2488
|
+
lastSyntaxToken(1)
|
2384
2489
|
end
|
2385
2490
|
|
2386
2491
|
def rule_propertiesBody
|
2387
2492
|
repeatable
|
2493
|
+
optional
|
2388
2494
|
|
2389
2495
|
pattern(%w( !account ))
|
2390
2496
|
|
@@ -2435,7 +2541,7 @@ EOT
|
|
2435
2541
|
pattern(%w( _projectid $ID ), lambda {
|
2436
2542
|
@project['projectids'] << @val[1]
|
2437
2543
|
@project['projectids'].uniq!
|
2438
|
-
@project['projectid'] = @val[1]
|
2544
|
+
@project['projectid'] = @projectId = @val[1]
|
2439
2545
|
})
|
2440
2546
|
doc('projectid', <<'EOT'
|
2441
2547
|
This declares a new project id and activates it. All subsequent
|
@@ -2511,7 +2617,6 @@ EOT
|
|
2511
2617
|
pattern(%w( _include !includeProperties !properties ), lambda {
|
2512
2618
|
popFileStack
|
2513
2619
|
})
|
2514
|
-
lastSyntaxToken(1)
|
2515
2620
|
doc('include.properties', <<'EOT'
|
2516
2621
|
Includes the specified file name as if its contents would be written
|
2517
2622
|
instead of the include property. The only exception is the include
|
@@ -2532,7 +2637,8 @@ EOT
|
|
2532
2637
|
pattern(%w( _purge $ID ), lambda {
|
2533
2638
|
if (attributeDefinition = @property.attributeDefinition(@val[1])).nil?
|
2534
2639
|
error('purge_unknown_id',
|
2535
|
-
"#{@val[1]} is not a known attribute for this property"
|
2640
|
+
"#{@val[1]} is not a known attribute for this property", nil,
|
2641
|
+
@sourceFileInfo[1])
|
2536
2642
|
end
|
2537
2643
|
if attributeDefinition.scenarioSpecific
|
2538
2644
|
attr = @property[@val[1], 0]
|
@@ -2541,7 +2647,8 @@ EOT
|
|
2541
2647
|
end
|
2542
2648
|
unless attr.is_a?(Array)
|
2543
2649
|
error('purge_no_list',
|
2544
|
-
"#{@val[1]} is not a list attribute. Only those can be purged."
|
2650
|
+
"#{@val[1]} is not a list attribute. Only those can be purged.",
|
2651
|
+
nil, @sourceFileInfo[1])
|
2545
2652
|
end
|
2546
2653
|
if attributeDefinition.scenarioSpecific
|
2547
2654
|
@property[@val[1], @scenarioIdx] = attributeDefinition.default.dup
|
@@ -2620,17 +2727,19 @@ properties.
|
|
2620
2727
|
EOT
|
2621
2728
|
)
|
2622
2729
|
|
2623
|
-
singlePattern('
|
2730
|
+
singlePattern('_alertmessages')
|
2624
2731
|
descr(<<'EOT'
|
2625
2732
|
The headlines, the summary and the details of the message from the journal
|
2626
|
-
entries that caused the current alert level
|
2733
|
+
entries that caused the current alert level to be larger than the defaul level
|
2734
|
+
for this task or any of its sub tasks.
|
2627
2735
|
EOT
|
2628
2736
|
)
|
2629
2737
|
|
2630
|
-
singlePattern('
|
2738
|
+
singlePattern('_alertsummaries')
|
2631
2739
|
descr(<<'EOT'
|
2632
2740
|
The headlines and the summary message from the journal entries that caused the
|
2633
|
-
current alert level for this task
|
2741
|
+
current alert level to be larger than the default for this task or any of its
|
2742
|
+
sub tasks.
|
2634
2743
|
EOT
|
2635
2744
|
)
|
2636
2745
|
|
@@ -2754,6 +2863,20 @@ EOT
|
|
2754
2863
|
singlePattern('_journal')
|
2755
2864
|
descr(<<'EOT'
|
2756
2865
|
The journal entries for the task or resource for the reported interval.
|
2866
|
+
EOT
|
2867
|
+
)
|
2868
|
+
|
2869
|
+
singlePattern('_journalmessages')
|
2870
|
+
descr(<<'EOT'
|
2871
|
+
The headlines, the summary and the details of the message from the journal
|
2872
|
+
entries that caused the current alert level for this task.
|
2873
|
+
EOT
|
2874
|
+
)
|
2875
|
+
|
2876
|
+
singlePattern('_journalsummaries')
|
2877
|
+
descr(<<'EOT'
|
2878
|
+
The headlines and the summary message from the journal entries that caused the
|
2879
|
+
current alert level for this task.
|
2757
2880
|
EOT
|
2758
2881
|
)
|
2759
2882
|
|
@@ -2788,7 +2911,7 @@ EOT
|
|
2788
2911
|
descr('The criticalness of the task with respect to all the paths that ' +
|
2789
2912
|
'it is a part of.')
|
2790
2913
|
|
2791
|
-
singlePattern('
|
2914
|
+
singlePattern('_precursors')
|
2792
2915
|
descr(<<EOT
|
2793
2916
|
A list of tasks the current task depends on. The list contains the names, the
|
2794
2917
|
IDs, the date and the type of dependency. For the type the following symbols
|
@@ -2979,6 +3102,11 @@ EOT
|
|
2979
3102
|
)
|
2980
3103
|
also(%w( epilog footer header ))
|
2981
3104
|
|
3105
|
+
pattern(%w( _opennodes !nodeIdList ), lambda {
|
3106
|
+
@property.set('openNodes', @val[1])
|
3107
|
+
})
|
3108
|
+
doc('opennods', 'For internal use only!')
|
3109
|
+
|
2982
3110
|
pattern(%w( !report ))
|
2983
3111
|
|
2984
3112
|
pattern(%w( _right $STRING ), lambda {
|
@@ -3046,7 +3174,8 @@ EOT
|
|
3046
3174
|
pattern(%w( _end !date ), lambda {
|
3047
3175
|
if @val[1] < @property.get('start')
|
3048
3176
|
error('report_end',
|
3049
|
-
"End date must be before start date #{@property.get('start')}"
|
3177
|
+
"End date must be before start date #{@property.get('start')}",
|
3178
|
+
nil, @sourceFileInfo[1])
|
3050
3179
|
end
|
3051
3180
|
@property.set('end', @val[1])
|
3052
3181
|
})
|
@@ -3067,7 +3196,8 @@ EOT
|
|
3067
3196
|
end
|
3068
3197
|
# In case we have a nested supplement, we need to prepend the parent ID.
|
3069
3198
|
if (report = @project.report(id)).nil?
|
3070
|
-
error('report_id_expected', "#{id} is not a defined report."
|
3199
|
+
error('report_id_expected', "#{id} is not a defined report.", nil,
|
3200
|
+
@sourceFileInfo[0])
|
3071
3201
|
end
|
3072
3202
|
report
|
3073
3203
|
})
|
@@ -3095,7 +3225,8 @@ EOT
|
|
3095
3225
|
pattern(%w( _start !date ), lambda {
|
3096
3226
|
if @val[1] > @property.get('end')
|
3097
3227
|
error('report_start',
|
3098
|
-
"Start date must be before end date #{@property.get('end')}"
|
3228
|
+
"Start date must be before end date #{@property.get('end')}",
|
3229
|
+
nil, @sourceFileInfo[1])
|
3099
3230
|
end
|
3100
3231
|
@property.set('start', @val[1])
|
3101
3232
|
})
|
@@ -3118,11 +3249,12 @@ EOT
|
|
3118
3249
|
if @val[1]
|
3119
3250
|
id = (@property ? @property.fullId + '.' : '') + @val[1]
|
3120
3251
|
if @project.report(id)
|
3121
|
-
error('report_exists', "report #{id} has already been defined."
|
3252
|
+
error('report_exists', "report #{id} has already been defined.",
|
3253
|
+
@property, @sourceFileInfo[1])
|
3122
3254
|
end
|
3123
3255
|
end
|
3124
3256
|
@property = Report.new(@project, @val[1], @val[2], @property)
|
3125
|
-
@property.sourceFileInfo = @
|
3257
|
+
@property.sourceFileInfo = @sourceFileInfo[0]
|
3126
3258
|
@property.inheritAttributes
|
3127
3259
|
case @val[0]
|
3128
3260
|
when 'taskreport'
|
@@ -3303,7 +3435,7 @@ EOT
|
|
3303
3435
|
pattern(%w( !taskId !valIntervals ), lambda {
|
3304
3436
|
checkBooking(@val[0], @property)
|
3305
3437
|
@booking = Booking.new(@property, @val[0], @val[1])
|
3306
|
-
@booking.sourceFileInfo = @
|
3438
|
+
@booking.sourceFileInfo = @sourceFileInfo[0]
|
3307
3439
|
@booking
|
3308
3440
|
})
|
3309
3441
|
arg(0, 'id', 'Absolute ID of a defined task')
|
@@ -3313,7 +3445,8 @@ EOT
|
|
3313
3445
|
pattern(%w( $ID ), lambda {
|
3314
3446
|
id = (@resourceprefix.empty? ? '' : @resourceprefix + '.') + @val[0]
|
3315
3447
|
if (resource = @project.resource(id)).nil?
|
3316
|
-
error('resource_id_expected', "#{id} is not a defined resource."
|
3448
|
+
error('resource_id_expected', "#{id} is not a defined resource.",
|
3449
|
+
nil, @sourceFileInfo[0])
|
3317
3450
|
end
|
3318
3451
|
resource
|
3319
3452
|
})
|
@@ -3326,10 +3459,12 @@ EOT
|
|
3326
3459
|
@property = @project.resource(@resourceprefix)
|
3327
3460
|
end
|
3328
3461
|
if @val[1] && @project.resource(@val[1])
|
3329
|
-
error('resource_exists',
|
3462
|
+
error('resource_exists',
|
3463
|
+
"Resource #{@val[1]} has already been defined.", @property,
|
3464
|
+
@sourceFileInfo[1])
|
3330
3465
|
end
|
3331
3466
|
@property = Resource.new(@project, @val[1], @val[2], @property)
|
3332
|
-
@property.sourceFileInfo = @
|
3467
|
+
@property.sourceFileInfo = @sourceFileInfo[0]
|
3333
3468
|
@property.inheritAttributes
|
3334
3469
|
@scenarioIdx = 0
|
3335
3470
|
})
|
@@ -3443,8 +3578,8 @@ EOT
|
|
3443
3578
|
doc('shifts.resource', <<'EOT'
|
3444
3579
|
Limits the working time of a resource to a defined shift during the specified
|
3445
3580
|
interval. Multiple shifts can be defined, but shift intervals may not overlap.
|
3446
|
-
|
3447
|
-
hours
|
3581
|
+
In case a shift is defined for a certain interval, the shift working hours
|
3582
|
+
replace the standard resource working hours for this interval.
|
3448
3583
|
EOT
|
3449
3584
|
)
|
3450
3585
|
|
@@ -3555,7 +3690,9 @@ EOT
|
|
3555
3690
|
# first.
|
3556
3691
|
@project.scenarios.clearProperties if @property.nil?
|
3557
3692
|
if @project.scenario(@val[1])
|
3558
|
-
error('scenario_exists',
|
3693
|
+
error('scenario_exists',
|
3694
|
+
"Scenario #{@val[1]} has already been defined.", nil,
|
3695
|
+
@sourceFileInfo[1])
|
3559
3696
|
end
|
3560
3697
|
@property = Scenario.new(@project, @val[1], @val[2], @property)
|
3561
3698
|
@property.inheritAttributes
|
@@ -3567,7 +3704,8 @@ EOT
|
|
3567
3704
|
def rule_scenarioId
|
3568
3705
|
pattern(%w( $ID ), lambda {
|
3569
3706
|
if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
|
3570
|
-
error('unknown_scenario_id', "Unknown scenario: #{@val[0]}"
|
3707
|
+
error('unknown_scenario_id', "Unknown scenario: #{@val[0]}", nil,
|
3708
|
+
@sourceFileInfo[0])
|
3571
3709
|
end
|
3572
3710
|
@scenarioIdx
|
3573
3711
|
})
|
@@ -3577,7 +3715,8 @@ EOT
|
|
3577
3715
|
def rule_scenarioIdCol
|
3578
3716
|
pattern(%w( $ID_WITH_COLON ), lambda {
|
3579
3717
|
if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
|
3580
|
-
error('unknown_scenario_id', "Unknown scenario: @val[0]"
|
3718
|
+
error('unknown_scenario_id', "Unknown scenario: @val[0]", nil,
|
3719
|
+
@sourceFileInfo[0])
|
3581
3720
|
end
|
3582
3721
|
})
|
3583
3722
|
end
|
@@ -3589,7 +3728,8 @@ EOT
|
|
3589
3728
|
def rule_scenarioIdx
|
3590
3729
|
pattern(%w( $ID ), lambda {
|
3591
3730
|
if (scenarioIdx = @project.scenarioIdx(@val[0])).nil?
|
3592
|
-
error('unknown_scenario_idx', "Unknown scenario #{@val[0]}"
|
3731
|
+
error('unknown_scenario_idx', "Unknown scenario #{@val[0]}", nil,
|
3732
|
+
@sourceFileInfo[0])
|
3593
3733
|
end
|
3594
3734
|
scenarioIdx
|
3595
3735
|
})
|
@@ -3613,6 +3753,7 @@ Shifts have a global name space. All IDs must be unique within the shifts of
|
|
3613
3753
|
the project.
|
3614
3754
|
EOT
|
3615
3755
|
)
|
3756
|
+
also(%w( shifts.task shifts.resource ))
|
3616
3757
|
end
|
3617
3758
|
|
3618
3759
|
def rule_shiftAssignment
|
@@ -3620,7 +3761,7 @@ EOT
|
|
3620
3761
|
# Make sure we have a ShiftAssignment for the property.
|
3621
3762
|
if @property['shifts', @scenarioIdx].nil?
|
3622
3763
|
@property['shifts', @scenarioIdx] = ShiftAssignments.new
|
3623
|
-
@property['shifts', @scenarioIdx].
|
3764
|
+
@property['shifts', @scenarioIdx].project = @project
|
3624
3765
|
end
|
3625
3766
|
|
3626
3767
|
if @val[1].nil?
|
@@ -3633,7 +3774,8 @@ EOT
|
|
3633
3774
|
addAssignment(ShiftAssignment.new(@val[0].scenario(@scenarioIdx),
|
3634
3775
|
interval))
|
3635
3776
|
error('shift_assignment_overlap',
|
3636
|
-
'Shifts may not overlap each other.'
|
3777
|
+
'Shifts may not overlap each other.', @property,
|
3778
|
+
@sourceFileInfo[0])
|
3637
3779
|
end
|
3638
3780
|
end
|
3639
3781
|
# Set same value again to set the 'provided' state for the attribute.
|
@@ -3663,10 +3805,11 @@ EOT
|
|
3663
3805
|
def rule_shiftHeader
|
3664
3806
|
pattern(%w( _shift !optionalID $STRING ), lambda {
|
3665
3807
|
if @val[1] && @project.shift(@val[1])
|
3666
|
-
error('shift_exists', "Shift #{@val[1]} has already been defined."
|
3808
|
+
error('shift_exists', "Shift #{@val[1]} has already been defined.",
|
3809
|
+
nil, @sourceFileInfo[1])
|
3667
3810
|
end
|
3668
3811
|
@property = Shift.new(@project, @val[1], @val[2], @property)
|
3669
|
-
@property.sourceFileInfo = @
|
3812
|
+
@property.sourceFileInfo = @sourceFileInfo[0]
|
3670
3813
|
@property.inheritAttributes
|
3671
3814
|
@scenarioIdx = 0
|
3672
3815
|
})
|
@@ -3676,7 +3819,8 @@ EOT
|
|
3676
3819
|
def rule_shiftId
|
3677
3820
|
pattern(%w( $ID ), lambda {
|
3678
3821
|
if (shift = @project.shift(@val[0])).nil?
|
3679
|
-
error('shift_id_expected', "#{@val[0]} is not a defined shift."
|
3822
|
+
error('shift_id_expected', "#{@val[0]} is not a defined shift.", nil,
|
3823
|
+
@sourceFileInfo[0])
|
3680
3824
|
end
|
3681
3825
|
shift
|
3682
3826
|
})
|
@@ -3746,33 +3890,38 @@ EOT
|
|
3746
3890
|
args = @val[0].split('.')
|
3747
3891
|
case args.length
|
3748
3892
|
when 2
|
3893
|
+
# <attribute>.<up|down>
|
3749
3894
|
scenario = -1
|
3750
3895
|
direction = args[1] == 'up'
|
3751
3896
|
attribute = args[0]
|
3752
3897
|
when 3
|
3898
|
+
# <scenario>.<attribute>.<up|down>
|
3753
3899
|
if (scenario = @project.scenarioIdx(args[0])).nil?
|
3754
3900
|
error('sort_unknown_scen',
|
3755
|
-
"Unknown scenario #{args[0]} in sorting criterium"
|
3901
|
+
"Unknown scenario #{args[0]} in sorting criterium", nil,
|
3902
|
+
@sourceFileInfo[0])
|
3756
3903
|
end
|
3757
3904
|
attribute = args[1]
|
3758
3905
|
if args[2] != 'up' && args[2] != 'down'
|
3759
|
-
error('sort_direction', "Sorting direction must be 'up' or 'down'"
|
3906
|
+
error('sort_direction', "Sorting direction must be 'up' or 'down'",
|
3907
|
+
nil, @sourceFileInfo[0])
|
3760
3908
|
end
|
3761
3909
|
direction = args[2] == 'up'
|
3762
3910
|
else
|
3763
3911
|
error('sorting_crit_exptd1',
|
3764
3912
|
"Sorting criterium expected (e.g. tree, start.up or " +
|
3765
|
-
"plan.end.down).")
|
3913
|
+
"plan.end.down).", nil, @sourceFileInfo[0])
|
3766
3914
|
end
|
3767
3915
|
if attribute == 'wbs'
|
3768
3916
|
error('sorting_wbs',
|
3769
3917
|
"Sorting by wbs is not supported. Please use 'tree' " +
|
3770
|
-
'(without appended .up or .down) instead.'
|
3918
|
+
'(without appended .up or .down) instead.', nil,
|
3919
|
+
@sourceFileInfo[0])
|
3771
3920
|
end
|
3772
3921
|
[ attribute, direction, scenario ]
|
3773
3922
|
})
|
3774
3923
|
arg(0, 'criteria', <<'EOT'
|
3775
|
-
The
|
3924
|
+
The sorting criteria must consist of a property attribute ID. See [[columnid]]
|
3776
3925
|
for a complete list of available attributes. The ID must be suffixed by '.up'
|
3777
3926
|
or '.down' to determine the sorting direction. Optionally the ID may be
|
3778
3927
|
prefixed with a scenario ID and a dot to determine the scenario that should be
|
@@ -3812,7 +3961,7 @@ EOT
|
|
3812
3961
|
if @val[0] != 'tree'
|
3813
3962
|
error('sorting_crit_exptd2',
|
3814
3963
|
"Sorting criterium expected (e.g. tree, start.up or " +
|
3815
|
-
"plan.end.down).")
|
3964
|
+
"plan.end.down).", nil, @sourceFileInfo[0])
|
3816
3965
|
end
|
3817
3966
|
[ 'tree', true, -1 ]
|
3818
3967
|
})
|
@@ -3825,7 +3974,7 @@ EOT
|
|
3825
3974
|
if @project.reports[fileName]
|
3826
3975
|
error('report_redefinition',
|
3827
3976
|
"A report with the name '#{fileName}' has already been " +
|
3828
|
-
"defined.")
|
3977
|
+
"defined.", nil, @sourceFileInfo[2])
|
3829
3978
|
end
|
3830
3979
|
else
|
3831
3980
|
fileName = "statusSheet#{@project.reports.length + 1}"
|
@@ -3883,7 +4032,7 @@ EOT
|
|
3883
4032
|
pattern(%w( _status !alertLevel $STRING ), lambda {
|
3884
4033
|
@journalEntry = JournalEntry.new(@project['journal'], @sheetEnd,
|
3885
4034
|
@val[2], @property,
|
3886
|
-
@
|
4035
|
+
@sourceFileInfo[0])
|
3887
4036
|
@journalEntry.alertLevel = @val[1]
|
3888
4037
|
@journalEntry.author = @sheetAuthor
|
3889
4038
|
|
@@ -3924,6 +4073,14 @@ EOT
|
|
3924
4073
|
optionsRule('statusSheetAttributes')
|
3925
4074
|
end
|
3926
4075
|
|
4076
|
+
def rule_statusSheetFile
|
4077
|
+
pattern(%w( !statusSheet . ), lambda {
|
4078
|
+
@val[0]
|
4079
|
+
})
|
4080
|
+
lastSyntaxToken(1)
|
4081
|
+
end
|
4082
|
+
|
4083
|
+
|
3927
4084
|
def rule_statusSheetHeader
|
3928
4085
|
pattern(%w( _statussheet !resourceId !valIntervalOrDate ), lambda {
|
3929
4086
|
@sheetAuthor = @val[1]
|
@@ -3985,6 +4142,14 @@ EOT
|
|
3985
4142
|
@property = @val[1]
|
3986
4143
|
})
|
3987
4144
|
end
|
4145
|
+
|
4146
|
+
def rule_subNodeId
|
4147
|
+
optional
|
4148
|
+
pattern(%w( _: !idOrAbsoluteId ), lambda {
|
4149
|
+
@val[1]
|
4150
|
+
})
|
4151
|
+
end
|
4152
|
+
|
3988
4153
|
def rule_summary
|
3989
4154
|
pattern(%w( _summary $STRING ), lambda {
|
3990
4155
|
return if @val[1].empty?
|
@@ -3992,11 +4157,13 @@ EOT
|
|
3992
4157
|
if @val[1].length > 480
|
3993
4158
|
error('ts_summary_too_long',
|
3994
4159
|
"The summary text must be 480 characters long or shorter. " +
|
3995
|
-
"This text has #{@val[1].length} characters."
|
4160
|
+
"This text has #{@val[1].length} characters.",
|
4161
|
+
nil, @sourceFileInfo[1])
|
3996
4162
|
end
|
3997
4163
|
if @val[1] == "A summary text\n"
|
3998
4164
|
error('ts_default_summary',
|
3999
|
-
"'A summary text' is not a valid summary"
|
4165
|
+
"'A summary text' is not a valid summary", nil,
|
4166
|
+
@sourceFileInfo[1])
|
4000
4167
|
end
|
4001
4168
|
rtTokenSetIntro =
|
4002
4169
|
%w( LINEBREAK SPACE WORD BOLD ITALIC CODE BOLDITALIC HREF HREFEND )
|
@@ -4130,7 +4297,7 @@ EOT
|
|
4130
4297
|
pattern(%w( !resourceId !valIntervals ), lambda {
|
4131
4298
|
checkBooking(@property, @val[0])
|
4132
4299
|
@booking = Booking.new(@val[0], @property, @val[1])
|
4133
|
-
@booking.sourceFileInfo = @
|
4300
|
+
@booking.sourceFileInfo = @sourceFileInfo[0]
|
4134
4301
|
@booking
|
4135
4302
|
})
|
4136
4303
|
end
|
@@ -4215,7 +4382,7 @@ EOT
|
|
4215
4382
|
end
|
4216
4383
|
error('too_many_bangs',
|
4217
4384
|
"Too many '!' for relative task in this context.",
|
4218
|
-
@property) if id[0] == ?!
|
4385
|
+
@property, @sourceFileInfo[0]) if id[0] == ?!
|
4219
4386
|
if task
|
4220
4387
|
task.fullId + '.' + id
|
4221
4388
|
else
|
@@ -4245,11 +4412,13 @@ EOT
|
|
4245
4412
|
if @val[1]
|
4246
4413
|
id = (@property ? @property.fullId + '.' : '') + @val[1]
|
4247
4414
|
if @project.task(id)
|
4248
|
-
error('task_exists', "Task #{id} has already been defined."
|
4415
|
+
error('task_exists', "Task #{id} has already been defined.", nil,
|
4416
|
+
@sourceFileInfo[1])
|
4249
4417
|
end
|
4250
4418
|
end
|
4251
4419
|
@property = Task.new(@project, @val[1], @val[2], @property)
|
4252
|
-
@property
|
4420
|
+
@property['projectid', 0] = @projectId
|
4421
|
+
@property.sourceFileInfo = @sourceFileInfo[0]
|
4253
4422
|
@property.inheritAttributes
|
4254
4423
|
@scenarioIdx = 0
|
4255
4424
|
})
|
@@ -4266,7 +4435,7 @@ EOT
|
|
4266
4435
|
id = @taskprefix + '.' + id unless @taskprefix.empty?
|
4267
4436
|
end
|
4268
4437
|
if (task = @project.task(id)).nil?
|
4269
|
-
error('unknown_task', "Unknown task #{id}")
|
4438
|
+
error('unknown_task', "Unknown task #{id}", nil, @sourceFileInfo[0])
|
4270
4439
|
end
|
4271
4440
|
task
|
4272
4441
|
})
|
@@ -4331,7 +4500,8 @@ EOT
|
|
4331
4500
|
|
4332
4501
|
if @property['chargeset', @scenarioIdx].empty?
|
4333
4502
|
error('task_without_chargeset',
|
4334
|
-
'The task does not have a chargeset defined.'
|
4503
|
+
'The task does not have a chargeset defined.', @property,
|
4504
|
+
@sourceFileInfo[0])
|
4335
4505
|
end
|
4336
4506
|
case @val[2]
|
4337
4507
|
when 'onstart'
|
@@ -4368,7 +4538,7 @@ EOT
|
|
4368
4538
|
pattern(%w( _complete !number), lambda {
|
4369
4539
|
if @val[1] < 0.0 || @val[1] > 100.0
|
4370
4540
|
error('task_complete', "Complete value must be between 0 and 100",
|
4371
|
-
@property)
|
4541
|
+
@property, @sourceFileInfo[1])
|
4372
4542
|
end
|
4373
4543
|
@property['complete', @scenarioIdx] = @val[1]
|
4374
4544
|
})
|
@@ -4418,7 +4588,8 @@ EOT
|
|
4418
4588
|
pattern(%w( _effort !workingDuration ), lambda {
|
4419
4589
|
checkContainer('effort')
|
4420
4590
|
if @val[1] <= 0.0
|
4421
|
-
error('effort_zero', "Effort value must be larger than 0", @property
|
4591
|
+
error('effort_zero', "Effort value must be larger than 0", @property,
|
4592
|
+
@sourceFileInfo[1])
|
4422
4593
|
end
|
4423
4594
|
@property['effort', @scenarioIdx] = @val[1]
|
4424
4595
|
})
|
@@ -4595,7 +4766,7 @@ EOT
|
|
4595
4766
|
pattern(%w( _priority $INTEGER ), lambda {
|
4596
4767
|
if @val[1] < 0 || @val[1] > 1000
|
4597
4768
|
error('task_priority', "Priority must have a value between 0 and 1000",
|
4598
|
-
@property)
|
4769
|
+
@property, @sourceFileInfo[1])
|
4599
4770
|
end
|
4600
4771
|
@property['priority', @scenarioIdx] = @val[1]
|
4601
4772
|
})
|
@@ -4620,7 +4791,8 @@ EOT
|
|
4620
4791
|
|
4621
4792
|
pattern(%w( _projectid $ID ), lambda {
|
4622
4793
|
unless @project['projectids'].include?(@val[1])
|
4623
|
-
error('unknown_projectid', "Unknown project ID #{@val[1]}"
|
4794
|
+
error('unknown_projectid', "Unknown project ID #{@val[1]}", nil,
|
4795
|
+
@sourceFileInfo[1])
|
4624
4796
|
end
|
4625
4797
|
@property['projectid', @scenarioIdx] = @val[1]
|
4626
4798
|
})
|
@@ -4642,6 +4814,17 @@ EOT
|
|
4642
4814
|
)
|
4643
4815
|
|
4644
4816
|
pattern(%w( _scheduled ), lambda {
|
4817
|
+
if (@property['milestone', @scenarioIdx] &&
|
4818
|
+
@property['start', @scenarioIdx].nil? &&
|
4819
|
+
@property['end', @scenarioIdx].nil?) ||
|
4820
|
+
(!@property['milestone', @scenarioIdx] &&
|
4821
|
+
(@property['start', @scenarioIdx].nil? ||
|
4822
|
+
@property['end', @scenarioIdx].nil?))
|
4823
|
+
error('not_scheduled',
|
4824
|
+
"Task #{@property.fullId} is marked as scheduled but does not " +
|
4825
|
+
'have a fixed start and end date.', @property,
|
4826
|
+
@sourceFileInfo[0])
|
4827
|
+
end
|
4645
4828
|
@property['scheduled', @scenarioIdx] = true
|
4646
4829
|
})
|
4647
4830
|
doc('scheduled', <<'EOT'
|
@@ -4875,10 +5058,11 @@ EOT
|
|
4875
5058
|
end
|
4876
5059
|
|
4877
5060
|
def rule_timeInterval
|
4878
|
-
pattern([ '$TIME', '_
|
5061
|
+
pattern([ '$TIME', '_-', '$TIME' ], lambda {
|
4879
5062
|
if @val[0] >= @val[2]
|
4880
5063
|
error('time_interval',
|
4881
|
-
"End time of interval must be larger than start time"
|
5064
|
+
"End time of interval must be larger than start time", nil,
|
5065
|
+
@sourceFileInfo[0])
|
4882
5066
|
end
|
4883
5067
|
[ @val[0], @val[2] ]
|
4884
5068
|
})
|
@@ -4931,7 +5115,10 @@ EOT
|
|
4931
5115
|
optional
|
4932
5116
|
repeatable
|
4933
5117
|
|
4934
|
-
pattern(%w( !tsNewTaskHeader !tsTaskBody )
|
5118
|
+
pattern(%w( !tsNewTaskHeader !tsTaskBody ), lambda {
|
5119
|
+
@property = nil
|
5120
|
+
@timeSheetRecord = nil
|
5121
|
+
})
|
4935
5122
|
doc('newtask', <<'EOT'
|
4936
5123
|
The keyword can be used add a new task to the project. If the task ID requires
|
4937
5124
|
further parent task that don't exist yet, these tasks will be created as well.
|
@@ -4942,7 +5129,7 @@ EOT
|
|
4942
5129
|
example('TimeSheet1', '3')
|
4943
5130
|
|
4944
5131
|
pattern(%w( _shift !shiftId ), lambda {
|
4945
|
-
|
5132
|
+
#TODO
|
4946
5133
|
})
|
4947
5134
|
doc('shift.timesheet', <<'EOT'
|
4948
5135
|
Specifies an alternative [[shift]] for the time sheet period. This shift will
|
@@ -4968,6 +5155,13 @@ EOT
|
|
4968
5155
|
example('TimeSheet1', '4')
|
4969
5156
|
end
|
4970
5157
|
|
5158
|
+
def rule_timeSheetFile
|
5159
|
+
pattern(%w( !timeSheet . ), lambda {
|
5160
|
+
@val[0]
|
5161
|
+
})
|
5162
|
+
lastSyntaxToken(1)
|
5163
|
+
end
|
5164
|
+
|
4971
5165
|
def rule_timeSheetBody
|
4972
5166
|
pattern(%w( _{ !timeSheetAttributes _} ), lambda {
|
4973
5167
|
|
@@ -4976,16 +5170,17 @@ EOT
|
|
4976
5170
|
|
4977
5171
|
def rule_timeSheetHeader
|
4978
5172
|
pattern(%w( _timesheet !resourceId !valIntervalOrDate ), lambda {
|
4979
|
-
sheetAuthor = @val[1]
|
5173
|
+
@sheetAuthor = @val[1]
|
4980
5174
|
@property = nil
|
4981
|
-
unless sheetAuthor.leaf?
|
5175
|
+
unless @sheetAuthor.leaf?
|
4982
5176
|
error('ts_group_author',
|
4983
|
-
'A resource group cannot file a time sheet'
|
5177
|
+
'A resource group cannot file a time sheet', nil,
|
5178
|
+
@sourceFileInfo[1])
|
4984
5179
|
end
|
4985
5180
|
# Currently time sheets are hardcoded for scenario 0.
|
4986
|
-
@timeSheet = TimeSheet.new(sheetAuthor, @val[2],
|
5181
|
+
@timeSheet = TimeSheet.new(@sheetAuthor, @val[2],
|
4987
5182
|
@project['trackingScenarioIdx'])
|
4988
|
-
@timeSheet.sourceFileInfo = @
|
5183
|
+
@timeSheet.sourceFileInfo = @sourceFileInfo[0]
|
4989
5184
|
@project.timeSheets << @timeSheet
|
4990
5185
|
})
|
4991
5186
|
end
|
@@ -5039,7 +5234,7 @@ EOT
|
|
5039
5234
|
pattern(%w( _newtask !taskIdUnverifd $STRING ), lambda {
|
5040
5235
|
@timeSheetRecord = TimeSheetRecord.new(@timeSheet, @val[1])
|
5041
5236
|
@timeSheetRecord.name = @val[2]
|
5042
|
-
@timeSheetRecord.sourceFileInfo = @
|
5237
|
+
@timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
|
5043
5238
|
})
|
5044
5239
|
arg(1, 'task', 'ID of the new task')
|
5045
5240
|
end
|
@@ -5095,20 +5290,21 @@ EOT
|
|
5095
5290
|
if @val[2].length > 120
|
5096
5291
|
error('ts_headline_too_long',
|
5097
5292
|
"The headline must be 120 or less characters long. This one " +
|
5098
|
-
"has #{@val[2].length} characters.")
|
5293
|
+
"has #{@val[2].length} characters.", nil, @sourceFileInfo[2])
|
5099
5294
|
end
|
5100
5295
|
if @val[2] == 'Your headline here!'
|
5101
5296
|
error('ts_no_headline',
|
5102
|
-
"'Your headline here!' is not a valid headline"
|
5297
|
+
"'Your headline here!' is not a valid headline", nil,
|
5298
|
+
@sourceFileInfo[2])
|
5103
5299
|
end
|
5104
5300
|
@journalEntry = JournalEntry.new(@project['journal'],
|
5105
5301
|
@timeSheet.interval.end,
|
5106
5302
|
@val[2],
|
5107
5303
|
@property || @timeSheet.resource,
|
5108
|
-
@
|
5304
|
+
@sourceFileInfo[0])
|
5109
5305
|
@journalEntry.alertLevel = @val[1]
|
5110
5306
|
@journalEntry.timeSheetRecord = @timeSheetRecord
|
5111
|
-
@journalEntry.author = @
|
5307
|
+
@journalEntry.author = @sheetAuthor
|
5112
5308
|
@timeSheetRecord.status = @journalEntry if @timeSheetRecord
|
5113
5309
|
})
|
5114
5310
|
end
|
@@ -5135,7 +5331,7 @@ EOT
|
|
5135
5331
|
if @val[1] < @timeSheet.interval.start
|
5136
5332
|
error('ts_end_too_early',
|
5137
5333
|
"The expected task end date must be after the start date of " +
|
5138
|
-
"this time sheet report.")
|
5334
|
+
"this time sheet report.", nil, @sourceFileInfo[1])
|
5139
5335
|
end
|
5140
5336
|
@timeSheetRecord.expectedEnd = @val[1]
|
5141
5337
|
})
|
@@ -5150,7 +5346,8 @@ EOT
|
|
5150
5346
|
priority = @val[1]
|
5151
5347
|
if priority < 1 || priority > 1000
|
5152
5348
|
error('ts_bad_priority',
|
5153
|
-
"Priority value #{priority} must be between 1 and 1000."
|
5349
|
+
"Priority value #{priority} must be between 1 and 1000.", nil,
|
5350
|
+
@sourceFileInfo[1])
|
5154
5351
|
end
|
5155
5352
|
@timeSheetRecord.priority = priority
|
5156
5353
|
})
|
@@ -5213,14 +5410,15 @@ EOT
|
|
5213
5410
|
@property = @val[1]
|
5214
5411
|
unless @property.leaf?
|
5215
5412
|
error('ts_task_not_leaf',
|
5216
|
-
'You cannot specify a task that has sub tasks here.'
|
5413
|
+
'You cannot specify a task that has sub tasks here.',
|
5414
|
+
@property, @sourceFileInfo[1])
|
5217
5415
|
end
|
5218
5416
|
scenarioIdx = @timeSheet.scenarioIdx
|
5219
5417
|
taskStart = @property['start', scenarioIdx] || @project['start']
|
5220
5418
|
taskEnd = @property['end', scenarioIdx] || @project['end']
|
5221
5419
|
|
5222
5420
|
@timeSheetRecord = TimeSheetRecord.new(@timeSheet, @property)
|
5223
|
-
@timeSheetRecord.sourceFileInfo = @
|
5421
|
+
@timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
|
5224
5422
|
})
|
5225
5423
|
arg(1, 'task', 'ID of an already existing task')
|
5226
5424
|
end
|
@@ -5235,7 +5433,8 @@ EOT
|
|
5235
5433
|
pattern(%w( !date ), lambda {
|
5236
5434
|
if @val[0] < @project['start'] || @val[0] > @project['end']
|
5237
5435
|
error('date_in_range', "Date must be within the project time frame " +
|
5238
|
-
"#{@project['start']}
|
5436
|
+
"#{@project['start']} - #{@project['end']}", nil,
|
5437
|
+
@sourceFileInfo[0])
|
5239
5438
|
end
|
5240
5439
|
@val[0]
|
5241
5440
|
})
|
@@ -5244,7 +5443,8 @@ EOT
|
|
5244
5443
|
def rule_validTimeZone
|
5245
5444
|
pattern(%w( $STRING ), lambda {
|
5246
5445
|
unless TjTime.checkTimeZone(@val[0])
|
5247
|
-
error('bad_time_zone', "#{@val[0]} is not a known time zone"
|
5446
|
+
error('bad_time_zone', "#{@val[0]} is not a known time zone", nil,
|
5447
|
+
@sourceFileInfo[0])
|
5248
5448
|
end
|
5249
5449
|
@val[0]
|
5250
5450
|
})
|
@@ -5258,7 +5458,8 @@ EOT
|
|
5258
5458
|
if mode == 0
|
5259
5459
|
unless @val[0] < endSpec
|
5260
5460
|
error('start_before_end', "The end date (#{endSpec}) must be " +
|
5261
|
-
"after the start date (#{@val[0]})."
|
5461
|
+
"after the start date (#{@val[0]}).", nil,
|
5462
|
+
@sourceFileInfo[1])
|
5262
5463
|
end
|
5263
5464
|
iv = Interval.new(@val[0], endSpec)
|
5264
5465
|
else
|
@@ -5294,7 +5495,7 @@ EOT
|
|
5294
5495
|
if mode == 0
|
5295
5496
|
unless @val[0] < endSpec
|
5296
5497
|
error('start_before_end', "The end date (#{endSpec}) must be after " +
|
5297
|
-
"the start date (#{@val[0]}).")
|
5498
|
+
"the start date (#{@val[0]}).", nil, @sourceFileInfo[1])
|
5298
5499
|
end
|
5299
5500
|
iv = Interval.new(@val[0], endSpec)
|
5300
5501
|
else
|
@@ -5330,7 +5531,7 @@ EOT
|
|
5330
5531
|
The warn attribute adds a logical expression to the property. The condition
|
5331
5532
|
described by the logical expression is checked after the scheduling and an
|
5332
5533
|
warning is generated if the condition evaluates to true. This attribute is
|
5333
|
-
primarily intended for testing
|
5534
|
+
primarily intended for testing purposes.
|
5334
5535
|
EOT
|
5335
5536
|
)
|
5336
5537
|
end
|
@@ -5367,7 +5568,7 @@ EOT
|
|
5367
5568
|
|
5368
5569
|
def rule_weekDayIntervalEnd
|
5369
5570
|
optional
|
5370
|
-
pattern([ '_
|
5571
|
+
pattern([ '_-', '!weekday' ], lambda {
|
5371
5572
|
@val[1]
|
5372
5573
|
})
|
5373
5574
|
arg(1, 'end weekday',
|
@@ -5409,7 +5610,8 @@ EOT
|
|
5409
5610
|
# 1.0.
|
5410
5611
|
if @val[0] < 0.0 || @val[0] > 100.0
|
5411
5612
|
error('illegal_percentage',
|
5412
|
-
"Percentage values must be between 0 and 100%."
|
5613
|
+
"Percentage values must be between 0 and 100%.", nil,
|
5614
|
+
@sourceFileInfo[1])
|
5413
5615
|
end
|
5414
5616
|
@val[0] / 100.0
|
5415
5617
|
end
|
@@ -5441,8 +5643,12 @@ EOT
|
|
5441
5643
|
Set the default working hours for all subsequent resource definitions.
|
5442
5644
|
The working hours specification limits the availability of resources to
|
5443
5645
|
certain time slots of week days.
|
5646
|
+
|
5647
|
+
These default working hours can be replaced with other working hours for
|
5648
|
+
individual resources.
|
5444
5649
|
EOT
|
5445
5650
|
)
|
5651
|
+
also(%w( dailyworkinghours workinghours.resource workinghours.shift ))
|
5446
5652
|
end
|
5447
5653
|
|
5448
5654
|
def rule_workinghoursResource
|
@@ -5452,16 +5658,26 @@ Set the working hours for a specific resource. The working hours specification
|
|
5452
5658
|
limits the availability of resources to certain time slots of week days.
|
5453
5659
|
EOT
|
5454
5660
|
)
|
5661
|
+
also(%w( workinghours.project workinghours.shift ))
|
5455
5662
|
end
|
5456
5663
|
|
5457
5664
|
def rule_workinghoursShift
|
5458
5665
|
pattern(%w( !workinghours ))
|
5459
5666
|
doc('workinghours.shift', <<'EOT'
|
5460
|
-
Set the
|
5461
|
-
|
5667
|
+
Set the working hours for the shift. The working hours specification limits
|
5668
|
+
the availability of resources or the activity on a task to certain time
|
5462
5669
|
slots of week days.
|
5670
|
+
|
5671
|
+
The shift working hours will replace the default or resource working hours for
|
5672
|
+
the specified time frame when assigning the shift to a resource.
|
5673
|
+
|
5674
|
+
In case the shift is used for a task, resources are only assigned during the
|
5675
|
+
working hours of this shift and during the working hours of the allocated
|
5676
|
+
resource. Allocations only happen when both the task shift and the resource
|
5677
|
+
work hours allow work to happen.
|
5463
5678
|
EOT
|
5464
5679
|
)
|
5680
|
+
also(%w( workinghours.project workinghours.resource ))
|
5465
5681
|
end
|
5466
5682
|
|
5467
5683
|
def rule_yesNo
|