Class TaskJuggler::TraceReport
In: lib/taskjuggler/reports/TraceReport.rb
Parent: ReportBase

The trace report is used to periodically snapshot a specific list of property attributes and add them to a CSV file.

Methods

Included Modules

MessageHandler

Public Class methods

Create a new object and set some default values.

[Source]

# File lib/taskjuggler/reports/TraceReport.rb, line 29
    def initialize(report)
      super
      @table = nil
    end

Public Instance methods

Generate the table in the intermediate format.

[Source]

# File lib/taskjuggler/reports/TraceReport.rb, line 35
    def generateIntermediateFormat
      super

      queryAttrs = { 'project' => @project,
                     'scopeProperty' => nil,
                     'loadUnit' => a('loadUnit'),
                     'numberFormat' => a('numberFormat'),
                     # We use a hardcoded %Y-%m-%d format for tracereports.
                     'timeFormat' => "%Y-%m-%d",
                     'currencyFormat' => a('currencyFormat'),
                     'start' => a('start'), 'end' => a('end'),
                     'hideJournalEntry' => a('hideJournalEntry'),
                     'journalMode' => a('journalMode'),
                     'journalAttributes' => a('journalAttributes'),
                     'sortJournalEntries' => a('sortJournalEntries'),
                     'costAccount' => a('costaccount'),
                     'revenueAccount' => a('revenueaccount') }
      query = Query.new(queryAttrs)

      # Prepare the account list.
      accountList = PropertyList.new(@project.accounts)
      accountList.setSorting(a('sortAccounts'))
      accountList.query = query
      accountList = filterAccountList(accountList, a('hideAccount'),
                                      a('rollupAccount'), a('openNodes'))
      accountList.sort!

      # Prepare the resource list.
      resourceList = PropertyList.new(@project.resources)
      resourceList.setSorting(a('sortResources'))
      resourceList.query = query
      resourceList = filterTaskList(resourceList, nil, a('hideResource'),
                                     a('rollupResource'), a('openNodes'))
      resourceList.sort!

      # Prepare the task list.
      taskList = PropertyList.new(@project.tasks)
      taskList.includeAdopted
      taskList.setSorting(a('sortTasks'))
      taskList.query = query
      taskList = filterTaskList(taskList, nil, a('hideTask'), a('rollupTask'),
                                a('openNodes'))
      taskList.sort!

      @fileName = ((@report.name[0] == '/' ? '' : @project.outputDir) +
                  @report.name + '.csv').untaint

      # Generate the table header.
      headers = [ 'Date' ] +
                generatePropertyListHeader(accountList, query) +
                generatePropertyListHeader(resourceList, query) +
                generatePropertyListHeader(taskList, query)

      discontinuedColumns = 0
      if File.exists?(@fileName)
        begin
          @table = CSVFile.new.read(@fileName)
        rescue
          error('tr_cannot_read_csv',
                "Cannot read CSV file #{@fileName}: #{$!}")
        end

        if @table[0] != headers
          # Some columns have changed. We move all discontinued columns to the
          # last columns and rearrange the others according to the new
          # headers. New columns will be filled with nil in previous rows.
          sorter = TableColumnSorter.new(@table)
          @table = sorter.sort(headers)
          discontinuedColumns = sorter.discontinuedColumns
        end
      else
        @table = [ headers ]
      end

      # Convert empty strings into nil objects and dates in %Y-%m-%d format
      # into TjTime objects.
      @table.each do |line|
        line.length.times do |i|
          if line[i] == ''
            line[i] = nil
          elsif line[i].is_a?(String) && /\d{4}-\d{2}-\d{2}/ =~ line[i]
            line[i] = TjTime.new(line[i])
          end
        end
      end

      query = @project.reportContexts.last.query.dup
      dateTag = @project['now'].midnight

      idx = @table.index { |line| line[0] == dateTag }
      discColumnValues = discontinuedColumns > 0 ?
                         Array.new(discontinuedColumns, nil) : []
      if idx
        # We already have an entry for the current date. All old values of
        # this line will be overwritten with the current values. The old
        # values in the discontinued columns will be kept.
        if discontinuedColumns > 0
          discColumnValues = @table[idx][headers.length..-1]
        end
        @table[idx] = []
      else
        # Append a new line of values to the table.
        @table << []
        idx = -1
      end
      # The first entry is always the current date.
      @table[idx] << dateTag

      # Now add the new values to the line
      generatePropertyListValues(idx, accountList, query)
      generatePropertyListValues(idx, resourceList, query)
      generatePropertyListValues(idx, taskList, query)

      # Fill the discontinued columns with old values or nil.
      @table[idx] += discColumnValues

      # Sort the table by ascending first column dates. We need to ensure that
      # the header remains the first line in the table.
      @table.sort! { |l1, l2| l1[0].is_a?(String) ? -1 :
                              (l2[0].is_a?(String) ? 1 : l1[0] <=> l2[0]) }
    end

[Source]

# File lib/taskjuggler/reports/TraceReport.rb, line 174
    def to_csv
      # Convert all TjTime values into String with format %Y-%m-%d and nil
      # objects into empty Strings.
      @table.each do |line|
        line.length.times do |i|
          if line[i].nil?
            line[i] = ''
          elsif line[i].is_a?(TjTime)
            line[i] = line[i].to_s('%Y-%m-%d')
          end
        end
      end

      @table
    end

[Source]

# File lib/taskjuggler/reports/TraceReport.rb, line 157
    def to_html
      html = []
      html << rt_to_html('header')

      begin
        plotter = ChartPlotter.new(a('width'), a('height'), @table)
        plotter.generate
        html << plotter.to_svg
      rescue ChartPlotterError => exception
        warning('chartPlotterError', exception.message, @report.sourceFileInfo)
      end

      html << rt_to_html('footer')

      html
    end

[Validate]