lib/reports/TableReport.rb in taskjuggler-0.0.4 vs lib/reports/TableReport.rb in taskjuggler-0.0.5
- old
+ new
@@ -36,30 +36,34 @@
'duration' => [ 'Duration', true, :right, true ],
'effort' => [ 'Effort', true, :right, true ],
'effortdone' => [ 'Effort Done', true, :right, true ],
'effortleft' => [ 'Effort Left', true, :right, true ],
'freetime' => [ 'Free Time', true, :right, true ],
+ 'followers' => [ 'Followers', false, :left, true ],
'id' => [ 'Id', false, :left, false ],
+ 'journal' => [ 'Journal', false, :left, false ],
'line' => [ 'Line No.', false, :right, false ],
'name' => [ 'Name', true, :left, false ],
'no' => [ 'No.', false, :right, false ],
+ 'precursors' => [ 'Precursors', false, :left, true ],
'rate' => [ 'Rate', true, :right, true ],
'resources' => [ 'Resources', false, :left, true ],
'responsible' => [ 'Responsible', false, :left, true ],
'revenue' => [ 'Revenue', true, :right, true ],
'scenario' => [ 'Scenario', false, :left, true ],
'status' => [ 'Status', false, :left, true ],
'targets' => [ 'Targets', false, :left, true ],
'wbs' => [ 'WBS', false, :left, false ]
}
@@propertiesByType = {
- # Type Indent Align
- DateAttribute => [ false, :left ],
- FixnumAttribute => [ false, :right ],
- FloatAttribute => [ false, :right ],
- RichTextAttribute => [ false, :left ],
- StringAttribute => [ false, :left ]
+ # Type Indent Align
+ DateAttribute => [ false, :left ],
+ FixnumAttribute => [ false, :right ],
+ FloatAttribute => [ false, :right ],
+ ResourceListAttribute => [ false, :left ],
+ RichTextAttribute => [ false, :left ],
+ StringAttribute => [ false, :left ]
}
# Generate a new TableReport object.
def initialize(report)
super
@report.content = self
@@ -74,61 +78,41 @@
def generateIntermediateFormat
super
end
-
-
# Turn the TableReport into an equivalent HTML element tree.
def to_html
html = []
html << rt_to_html('header')
- html << (table = XMLElement.new('table', 'summary' => 'Report Table',
- 'cellspacing' => '2', 'border' => '0',
- 'cellpadding' => '0', 'align' => 'center',
- 'class' => 'tjtable'))
+ html << (tableFrame = generateHtmlTableFrame)
- # The headline is put in a sub-table to appear bigger.
- if a('headline')
- table << (thead = XMLElement.new('thead'))
- thead << (tr = XMLElement.new('tr'))
- tr << (td = XMLElement.new('td'))
- td << (table1 = XMLElement.new('table', 'summary' => 'headline',
- 'cellspacing' => '1', 'border' => '0',
- 'cellpadding' => '5',
- 'align' => 'center', 'width' => '100%'))
- table1 << (tr1 = XMLElement.new('tr'))
- tr1 << (td1 = XMLElement.new('td', 'align' => 'center',
- 'style' => 'font-size:16px; ' +
- 'font-weight:bold; ' +
- 'padding:5px',
- 'class' => 'tabfront'))
- td1 << a('headline').to_html
+ # Now generate the actual table with the data.
+ tableFrame << generateHtmlTableRow do
+ td = XMLElement.new('td')
+ td << @table.to_html
+ td
end
- # Now generate the actual table with the data.
- table << (tbody = XMLElement.new('tbody'))
- tbody << (tr = XMLElement.new('tr'))
- tr << (td = XMLElement.new('td'))
- td << @table.to_html
-
# Embedd the caption as RichText into the table footer.
if a('caption')
- tbody << (tr = XMLElement.new('tr'))
- tr << (td = XMLElement.new('td', 'class' => 'tabback'))
- td << (div = XMLElement.new('div', 'class' => 'caption',
- 'style' => 'margin:1px'))
- a('caption').sectionNumbers = false
- div << a('caption').to_html
+ tableFrame << generateHtmlTableRow do
+ td = XMLElement.new('td')
+ td << (div = XMLElement.new('div', 'class' => 'tj_table_caption'))
+ a('caption').sectionNumbers = false
+ div << a('caption').to_html
+ td
+ end
end
- # A sub-table with the legend.
- tbody << (tr = XMLElement.new('tr', 'style' => 'font-size:10px;'))
- tr << (td = XMLElement.new('td', 'style' =>
- 'padding-left:1px; padding-right:1px;'))
- td << @legend.to_html
+ # The legend.
+ tableFrame << generateHtmlTableRow do
+ td = XMLElement.new('td')
+ td << @legend.to_html
+ td
+ end
html << rt_to_html('footer')
html
end
@@ -551,14 +535,12 @@
cell.hidden = true
cell.text = nil
# The GanttChart can be reached via the special variable of the column
# header.
chart = columnDef.column.cell1.special
- GanttLine.new(chart, property, line.scopeProperty,
- query.scenarioIdx,
- (line.subLineNo - 1) * (line.height + 1),
- line.height)
+ GanttLine.new(chart, query, (line.subLineNo - 1) * (line.height + 1),
+ line.height, a('selfcontained') ? nil : columnDef.tooltip)
return true
# The calendar cells can be all generated by the same function. But we
# need to use different parameters.
when 'hourly'
start = @start.midnight
@@ -702,10 +684,12 @@
'resource'
end
else
nil
end
+ cell.iconTooltip = RichText.new("'''ID:''' #{property.fullId}").
+ generateIntermediateFormat
when 'no'
cell.text = line.no.to_s
when 'wbs'
cell.indent = 2 if line.scopeLine
when 'scenario'
@@ -740,54 +724,67 @@
# object. Therefor a single @table column usually has many cells on each
# single line. _scenarioIdx_ is the index of the scenario that is reported
# in this line. _line_ is the @table line. _t_ is the start date for the
# calendar. _sameTimeNextFunc_ is the function that will move the date to
# the next cell.
- def genCalChartTaskCell(query, line, columnDef, t, sameTimeNextFunc)
+ def genCalChartTaskCell(origQuery, line, columnDef, t, sameTimeNextFunc)
task = line.property
# Find out if we have an enclosing resource scope.
if line.scopeLine && line.scopeLine.property.is_a?(Resource)
resource = line.scopeLine.property
else
resource = nil
end
# Get the interval of the task. In case a date is invalid due to a
# scheduling problem, we use the full project interval.
- taskIv = Interval.new(task['start', query.scenarioIdx].nil? ?
- @project['start'] : task['start', query.scenarioIdx],
- task['end', query.scenarioIdx].nil? ?
- @project['end'] : task['end', query.scenarioIdx])
+ taskStart = task['start', origQuery.scenarioIdx]
+ taskEnd = task['end', origQuery.scenarioIdx]
+ taskIv = Interval.new(taskStart.nil? ? @project['start'] : taskStart,
+ taskEnd.nil? ? @project['end'] : taskEnd)
firstCell = nil
while t < @end
- # Create a new cell
- cell = newCell(query, line)
-
+ # We modify the start and end dates to match the cell boundaries. So
+ # we need to make sure we don't modify the original Query but our own
+ # copies.
+ query = origQuery.dup
# call TjTime::sameTimeNext... function
nextT = t.send(sameTimeNextFunc)
cellIv = Interval.new(t, nextT)
case columnDef.content
when 'empty'
+ # Create a new cell
+ cell = newCell(query, line)
# We only generate cells will different background colors.
when 'load'
query.attributeId = 'effort'
- query.startIdx = t
- query.endIdx = nextT
+ query.start = t
+ query.end = nextT
query.process
+
+ # Create a new cell
+ cell = newCell(query, line)
+
# To increase readability, we don't show 0.0 values.
cell.text = query.to_s if query.to_num != 0.0
else
raise "Unknown column content #{column.content}"
end
# Determine cell category (mostly the background color)
if cellIv.overlaps?(taskIv)
+ # The cell is either a container or leaf task
cell.category = task.container? ? 'calconttask' : 'caltask'
+ # If the user has requested a custom tooltip, add it to each task cell.
+ cell.tooltip = columnDef.tooltip.getPattern(query) || nil
+ cell.showTooltipHint = false
elsif !@project.isWorkingTime(cellIv)
+ # The cell is a vacation cell.
cell.category = 'offduty'
else
+ # The cell is just filled with the background color.
cell.category = 'taskcell'
end
cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'
tryCellMerging(cell, line, firstCell)
@@ -806,29 +803,33 @@
# ColumnTable object. Therefor a single @table column usually has many cells
# on each single line. _scenarioIdx_ is the index of the scenario that is
# reported in this line. _line_ is the @table line. _t_ is the start date
# for the calendar. _sameTimeNextFunc_ is the function that will move the
# date to the next cell.
- def genCalChartResourceCell(query, line, columnDef, t,
+ def genCalChartResourceCell(origQuery, line, columnDef, t,
sameTimeNextFunc)
resource = line.property
# Find out if we have an enclosing task scope.
if line.scopeLine && line.scopeLine.property.is_a?(Task)
task = line.scopeLine.property
# Get the interval of the task. In case a date is invalid due to a
# scheduling problem, we use the full project interval.
- taskIv = Interval.new(task['start', query.scenarioIdx].nil? ?
- @project['start'] :
- task['start', query.scenarioIdx],
- task['end', query.scenarioIdx].nil? ?
- @project['end'] : task['end', query.scenarioIdx])
+ taskStart = task['start', origQuery.scenarioIdx]
+ taskEnd = task['end', origQuery.scenarioIdx]
+ taskIv = Interval.new(taskStart.nil? ? @project['start'] : taskStart,
+ taskEnd.nil? ? @project['end'] : taskEnd)
else
task = nil
end
firstCell = nil
while t < @end
+ # We modify the start and end dates to match the cell boundaries. So
+ # we need to make sure we don't modify the original Query but our own
+ # copies.
+ query = origQuery.dup
+
# Create a new cell
cell = newCell(query, line)
# call TjTime::sameTimeNext... function
nextT = t.send(sameTimeNextFunc)
@@ -866,26 +867,33 @@
end
else
raise "Unknown column content #{column.content}"
end
+ # Set the tooltip for the cell. We might delete it again.
+ cell.tooltip = columnDef.tooltip.getPattern(query) || nil
+ cell.showTooltipHint = false
+
# Determine cell category (mostly the background color)
cell.category = if task
if cellIv.overlaps?(taskIv)
if workLoadTask > 0.0 && freeLoad == 0.0
'busy'
elsif workLoad == 0.0 && freeLoad == 0.0
+ cell.tooltip = nil
'offduty'
else
'loaded'
end
else
if freeLoad > 0.0
'free'
elsif workLoad == 0.0 && freeLoad == 0.0
+ cell.tooltip = nil
'offduty'
else
+ cell.tooltip = nil
'resourcecell'
end
end
else
if workLoad > 0.0 && freeLoad == 0.0
@@ -893,9 +901,10 @@
elsif workLoad > 0.0 && freeLoad > 0.0
'loaded'
elsif workLoad == 0.0 && freeLoad > 0.0
'free'
else
+ cell.tooltip = nil
'offduty'
end
end
cell.category += line.property.get('index') % 2 == 1 ? '1' : '2'