Class: TaskJuggler::TraceReport

Inherits:
ReportBase show all
Includes:
MessageHandler
Defined in:
lib/taskjuggler/reports/TraceReport.rb

Overview

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

Instance Method Summary collapse

Methods included from MessageHandler

#critical, #debug, #error, #fatal, #info, #warning

Methods inherited from ReportBase

#a, #filterAccountList, #filterResourceList, #filterTaskList

Constructor Details

#initialize(report) ⇒ TraceReport

Create a new object and set some default values.



29
30
31
32
# File 'lib/taskjuggler/reports/TraceReport.rb', line 29

def initialize(report)
  super
  @table = nil
end

Instance Method Details

#generateIntermediateFormatObject

Generate the table in the intermediate format.



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# 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.exist?(@fileName)
    begin
      @table = CSVFile.new(nil, nil).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

#to_csvObject



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# 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

#to_htmlObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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