This specialization of ReportBase implements an export of the project data in the TJP syntax format.
Create a new object and set some default values.
# File lib/reports/TjpExportRE.rb, line 23 23: def initialize(report) 24: super(report) 25: 26: @supportedTaskAttrs = %( booking complete depends flags maxend 27: maxstart minend minstart note priority 28: responsible ) 29: @supportedResourceAttrs = %( vacation workinghours ) 30: @report.set('scenarios', [ 0 ]) 31: 32: # Show all tasks, sorted by seqno-up. 33: @report.set('hideTask', LogicalExpression.new(LogicalOperation.new(0))) 34: @report.set('sortTasks', [ [ 'seqno', true, 1 ] ]) 35: # Show all resources, sorted by seqno-up. 36: @report.set('hideResource', 37: LogicalExpression.new(LogicalOperation.new(0))) 38: @report.set('sortResources', [ [ 'seqno', true, 1 ] ]) 39: end
# File lib/reports/TjpExportRE.rb, line 41 41: def generateIntermediateFormat 42: super 43: end
Return the project data in TJP syntax format.
# File lib/reports/TjpExportRE.rb, line 46 46: def to_tjp 47: # Prepare the resource list. 48: @resourceList = PropertyList.new(@project.resources) 49: @resourceList.setSorting(a('sortResources')) 50: @resourceList = filterResourceList(@resourceList, nil, a('hideResource'), 51: a('rollupResource'), a('openNodes')) 52: @resourceList.sort! 53: 54: # Prepare the task list. 55: @taskList = PropertyList.new(@project.tasks) 56: @taskList.setSorting(a('sortTasks')) 57: @taskList = filterTaskList(@taskList, nil, a('hideTask'), a('rollupTask'), 58: a('openNodes')) 59: @taskList.sort! 60: 61: getBookings 62: 63: @file = '' 64: 65: generateProjectProperty if a('definitions').include?('project') 66: 67: generateFlagDeclaration if a('definitions').include?('flags') 68: generateProjectIDs if a('definitions').include?('projectids') 69: generateResourceList if a('definitions').include?('resources') 70: generateTaskList if a('definitions').include?('tasks') 71: 72: generateTaskAttributes unless a('taskAttributes').empty? 73: generateResourceAttributes unless a('resourceAttributes').empty? 74: 75: @file 76: end
# File lib/reports/TjpExportRE.rb, line 317 317: def generateAttribute(property, attrId, indent, scenarioIdx = nil) 318: val = scenarioIdx.nil? ? property.getAttr(attrId) : 319: property[attrId, scenarioIdx] 320: return if val.nil? || (val.is_a?(Array) && val.empty?) 321: 322: generateAttributeText(property.getAttr(attrId, scenarioIdx).to_tjp, 323: indent, scenarioIdx) 324: end
# File lib/reports/TjpExportRE.rb, line 326 326: def generateAttributeText(text, indent, scenarioIdx) 327: @file << ' ' * indent 328: tag = '' 329: if !scenarioIdx.nil? && scenarioIdx != 0 330: tag = @project.scenario(scenarioIdx).id 331: @file << "#{tag}:" 332: end 333: @file << "#{indentBlock(text, indent + tag.length + 2)}\n" 334: end
# File lib/reports/TjpExportRE.rb, line 362 362: def generateBooking(task, indent, scenarioIdx) 363: return unless @bookings[scenarioIdx].include?(task) 364: 365: @bookings[scenarioIdx][task].each_value do |booking| 366: generateAttributeText('booking ' + booking.to_tjp, indent, scenarioIdx) 367: end 368: end
# File lib/reports/TjpExportRE.rb, line 91 91: def generateCustomAttributeDeclarations(tag, propertySet, attributes) 92: # First we search the attribute definitions for any user defined 93: # attributes and count them. 94: customAttributes = 0 95: propertySet.eachAttributeDefinition do |ad| 96: customAttributes += 1 if ad.userDefined 97: end 98: # Return if there are no user defined attributes. 99: return if customAttributes == 0 100: 101: # Generate definitions for each user defined attribute that is in the 102: # taskAttributes list. 103: @file << ' extend ' + tag + "{\n" 104: propertySet.eachAttributeDefinition do |ad| 105: next unless ad.userDefined && attributes.include?(ad.id) 106: 107: @file << " #{ad.objClass.tjpId} #{ad.id} \"#{ad.name}\"\n" 108: end 109: @file << " }\n" 110: end
# File lib/reports/TjpExportRE.rb, line 112 112: def generateFlagDeclaration 113: flags = [] 114: 115: properties = @resourceList + @taskList 116: 117: properties.each do |property| 118: a('scenarios').each do |scenarioIdx| 119: property['flags', scenarioIdx].each do |flag| 120: flags << flag unless flags.include?(flag) 121: end 122: end 123: end 124: flags.sort 125: unless flags.empty? 126: @file << "flags #{flags.join(', ')}\n\n" 127: end 128: end
# File lib/reports/TjpExportRE.rb, line 130 130: def generateProjectIDs 131: # Compile a list of all projectIDs from the tasks in the taskList. 132: projectIDs = [] 133: a('scenarios').each do |scenarioIdx| 134: @taskList.each do |task| 135: pid = task['projectid', scenarioIdx] 136: projectIDs << pid unless pid.nil? || projectIDs.include?(pid) 137: end 138: end 139: 140: @file << "projectids #{projectIDs.join(', ')}\n\n" unless projectIDs.empty? 141: end
# File lib/reports/TjpExportRE.rb, line 80 80: def generateProjectProperty 81: @file << "project #{@project['projectid']} \"#{@project['name']}\" " + 82: "\"#{@project['version']}\" #{@project['start']} - " + 83: "#{@project['end']} {\n" 84: generateCustomAttributeDeclarations('resource', @project.resources, 85: a('resourceAttributes')) 86: generateCustomAttributeDeclarations('task', @project.tasks, 87: a('taskAttributes')) 88: @file << "}\n\n" 89: end
# File lib/reports/TjpExportRE.rb, line 154 154: def generateResource(resource, indent) 155: Log.activity if resource.sequenceNo % 100 == 0 156: 157: @file << ' ' * indent + "resource #{resource.id} \"#{resource.name}\"" 158: @file << ' {' unless resource.children.empty? 159: @file << "\n" 160: 161: # Call this function recursively for all children that are included in the 162: # resource list as well. 163: resource.children.each do |subresource| 164: if @resourceList.include?(subresource) 165: generateResource(subresource, indent + 2) 166: end 167: end 168: 169: @file << ' ' * indent + "}\n" unless resource.children.empty? 170: end
Generate a list of resource supplement statements that include the rest of the attributes.
# File lib/reports/TjpExportRE.rb, line 260 260: def generateResourceAttributes 261: @resourceList.each do |resource| 262: Log.activity if resource.sequenceNo % 100 == 0 263: 264: @file << "supplement resource #{resource.fullId} {\n" 265: @project.resources.eachAttributeDefinition do |attrDef| 266: id = attrDef.id 267: next if (!@supportedResourceAttrs.include?(id) && 268: ! attrDef.userDefined) || 269: !a('resourceAttributes').include?(id) 270: 271: if attrDef.scenarioSpecific 272: a('scenarios').each do |scenarioIdx| 273: generateAttribute(resource, id, 2, scenarioIdx) 274: end 275: else 276: generateAttribute(resource, id, 2) 277: end 278: end 279: 280: @file << "}\n" 281: end 282: end
# File lib/reports/TjpExportRE.rb, line 143 143: def generateResourceList 144: # The resource definitions are generated recursively. So we only need to 145: # start it for the top-level resources. 146: @resourceList.each do |resource| 147: if resource.parent.nil? 148: generateResource(resource, 0) 149: end 150: end 151: @file << "\n" 152: end
Generate a task definition. It only contains a very small set of attributes that have to be passed on the the nested tasks at creation time. All other attributes are declared in subsequent supplement statements.
# File lib/reports/TjpExportRE.rb, line 186 186: def generateTask(task, indent) 187: Log.activity if task.sequenceNo % 100 == 0 188: 189: @file << ' ' * indent + "task #{task.id} \"#{task.name}\" {\n" 190: 191: if a('taskAttributes').include?('depends') 192: a('scenarios').each do |scenarioIdx| 193: generateTaskDependency(scenarioIdx, task, 'depends', indent + 2) 194: generateTaskDependency(scenarioIdx, task, 'precedes', indent + 2) 195: end 196: end 197: 198: # Call this function recursively for all children that are included in the 199: # task list as well. 200: task.children.each do |subtask| 201: if @taskList.include?(subtask) 202: generateTask(subtask, indent + 2) 203: end 204: end 205: 206: # Determine whether this task has subtasks that are included in the 207: # report or whether this is a leaf task for the report. 208: isLeafTask = true 209: task.children.each do |subtask| 210: if @taskList.include?(subtask) 211: isLeafTask = false 212: break 213: end 214: end 215: 216: # For leaf tasks we put some attributes right here. 217: if isLeafTask 218: a('scenarios').each do |scenarioIdx| 219: generateAttribute(task, 'start', indent + 2, scenarioIdx) 220: if task['milestone', scenarioIdx] 221: generateAttributeText('milestone', indent + 2, scenarioIdx) 222: else 223: generateAttribute(task, 'end', indent + 2, scenarioIdx) 224: generateAttributeText('scheduling ' + 225: (task['forward', scenarioIdx] ? 226: 'asap' : 'alap'), 227: indent + 2, scenarioIdx) 228: end 229: if task['scheduled', scenarioIdx] 230: generateAttributeText('scheduled', indent + 2, scenarioIdx) 231: end 232: end 233: end 234: 235: @file << ' ' * indent + "}\n" 236: end
Generate a list of task supplement statements that include the rest of the attributes.
# File lib/reports/TjpExportRE.rb, line 286 286: def generateTaskAttributes 287: @taskList.each do |task| 288: Log.activity if task.sequenceNo % 100 == 0 289: 290: @file << "supplement task #{task.fullId} {\n" 291: @project.tasks.eachAttributeDefinition do |attrDef| 292: id = attrDef.id 293: next if (!@supportedTaskAttrs.include?(id) && !attrDef.userDefined) || 294: !a('taskAttributes').include?(id) 295: 296: if attrDef.scenarioSpecific 297: a('scenarios').each do |scenarioIdx| 298: # Some attributes need special treatment. 299: case id 300: when 'depends' 301: next # already taken care of 302: when 'booking' 303: generateBooking(task, 2, scenarioIdx) 304: else 305: generateAttribute(task, id, 2, scenarioIdx) 306: end 307: end 308: else 309: generateAttribute(task, id, 2) 310: end 311: end 312: 313: @file << "}\n" 314: end 315: end
Generate ‘depends’ or ‘precedes’ attributes for a task.
# File lib/reports/TjpExportRE.rb, line 239 239: def generateTaskDependency(scenarioIdx, task, tag, indent) 240: return unless a('taskAttributes').include?('depends') 241: 242: taskDeps = task[tag, scenarioIdx] 243: unless taskDeps.empty? 244: @file << ' ' * indent + tag + ' ' 245: first = true 246: taskDeps.each do |dep| 247: if first 248: first = false 249: else 250: @file << ', ' 251: end 252: @file << dep.task.fullId 253: end 254: @file << "\n" 255: end 256: end
# File lib/reports/TjpExportRE.rb, line 172 172: def generateTaskList 173: # The task definitions are generated recursively. So we only need to start 174: # it for the top-level tasks. 175: @taskList.each do |task| 176: if task.parent.nil? 177: generateTask(task, 0) 178: end 179: end 180: end
Get the booking data for all resources that should be included in the report.
# File lib/reports/TjpExportRE.rb, line 338 338: def getBookings 339: @bookings = {} 340: if a('taskAttributes').include?('booking') 341: a('scenarios').each do |scenarioIdx| 342: @bookings[scenarioIdx] = {} 343: @resourceList.each do |resource| 344: # Get the bookings for this resource hashed by task. 345: bookings = resource.getBookings(scenarioIdx, 346: Interval.new(a('start'), a('end'))) 347: next if bookings.nil? 348: 349: # Now convert/add them to a tripple-stage hash by scenarioIdx, task 350: # and then resource. 351: bookings.each do |task, booking| 352: if !@bookings[scenarioIdx].include?(task) 353: @bookings[scenarioIdx][task] = {} 354: end 355: @bookings[scenarioIdx][task][resource] = booking 356: end 357: end 358: end 359: end 360: end
This utility function is used to indent multi-line attributes. All attributes should be filtered through this function. Attributes that contain line breaks will be indented properly. In addition to the indentation specified by indent all but the first line will be indented after the first word of the first line. The text may not end with a line break.
# File lib/reports/TjpExportRE.rb, line 376 376: def indentBlock(text, indent) 377: out = '' 378: firstSpace = 0 379: text.length.times do |i| 380: if firstSpace == 0 && text[i] == \ \# There must be a space after ? 381: firstSpace = i 382: end 383: out << text[i] 384: if text[i] == \n\ 385: out += ' ' * (indent + firstSpace) 386: end 387: end 388: out 389: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.