Index: app/helpers/issues_helper.rb
===================================================================
--- app/helpers/issues_helper.rb (revision 2823)
+++ app/helpers/issues_helper.rb (working copy)
@@ -129,13 +129,173 @@
end
end
- def issues_to_csv(issues, project = nil)
+ def retrieveHeaders(query, custom_fields)
+ headers = Array.new(query.column_names.length())
+ 0.upto(query.column_names.length() - 1) do |counter|
+ headerName = nil
+ columnName = query.column_names[counter].to_s()
+ case columnName
+ when 'status'
+ headerName = l(:field_status)
+ when 'project'
+ headerName = l(:field_project)
+ when 'tracker'
+ headerName = l(:field_tracker)
+ when 'priority'
+ headerName = l(:field_priority)
+ when 'subject'
+ headerName = l(:field_subject)
+ when 'assigned_to'
+ headerName = l(:field_assigned_to)
+ when 'category'
+ headerName = l(:field_category)
+ when 'fixed_version'
+ headerName = l(:field_fixed_version)
+ when 'author'
+ headerName = l(:field_author)
+ when 'start_date'
+ headerName = l(:field_start_date)
+ when 'due_date'
+ headerName = l(:field_due_date)
+ when 'done_ratio'
+ headerName = l(:field_done_ratio)
+ when 'estimated_hours'
+ headerName = l(:field_estimated_hours)
+ when 'created_on'
+ headerName = l(:field_created_on)
+ when 'updated_on'
+ headerName = l(:field_updated_on)
+ else
+ #custom field case...
+
+ #parse the custom column id # from the column header
+ id = getIDFromCustomColName(columnName)
+
+ #match it with a custom field id to extract the correct header and field data
+ custom_fields.each do |custom_field| #cycle through all possible custom fields
+ if id == custom_field.id.to_s()
+ headerName = custom_field.name.to_s()
+ break
+ end
+ end
+ end
+ headers[counter] = headerName != nil ? headerName : ''
+ end
+ return headers
+ end
+
+ def retrieveFieldData(issues, query, decimal_separator,custom_fields)
+ fields = Array.new(query.column_names.length()){[]}
+ #cycle through each issue (row) in the table..
+ issues.each do |issue|
+ #cycle through each column in the row...
+ #loading the column names from the passed query...
+ #in order to load the correct column data for each issue --> fields2[column][issue]
+ #this method also loads the headers for each column --> headers2[column]
+ 0.upto(query.column_names.length() - 1) do |counter|
+ columnName = query.column_names[counter].to_s()
+ case columnName
+ when 'status'
+ fieldData = issue.status.name
+ when 'project'
+ fieldData = issue.project.name
+ when 'tracker'
+ fieldData = issue.tracker.name
+ when 'priority'
+ fieldData = issue.priority.name
+ when 'subject'
+ fieldData= issue.subject
+ when 'assigned_to'
+ fieldData = issue.assigned_to
+ when 'category'
+ fieldData = issue.category
+ when 'fixed_version'
+ fieldData = issue.fixed_version
+ when 'author'
+ fieldData = issue.author.name
+ when 'start_date'
+ fieldData = format_date(issue.start_date)
+ when 'due_date'
+ fieldData = format_date(issue.due_date)
+ when 'done_ratio'
+ fieldData = issue.done_ratio
+ when 'estimated_hours'
+ fieldData = issue.estimated_hours.to_s.gsub('.', decimal_separator)
+ when 'created_on'
+ fieldData = format_time(issue.created_on)
+ when 'updated_on'
+ fieldData = format_time(issue.updated_on)
+ else
+ #custom field case...
+
+ #parse the custom column id # from the column header
+ id = getIDFromCustomColName(columnName)
+
+ #match it with a custom field id to extract the correct header and field data
+ custom_fields.each do |custom_field| #cycle through all possible custom fields
+ if id == custom_field.id.to_s()
+ fieldData = show_value(issue.custom_value_for(custom_field))
+ break
+ end
+ end
+ end #end case
+ fields[counter][issue.id] = fieldData
+ end #end upto
+ end #end issues.each
+ return fields
+ end
+
+ #Method changed 7/7/09
+ def issues_to_csv(issues, query, project = nil)
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
decimal_separator = l(:general_csv_decimal_separator)
export = StringIO.new
CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
- # csv header fields
- headers = [ "#",
+ # csv header fields
+
+ #if the user has specified columns in the query...
+ if(@query.column_names != nil)
+ headers = Array.new(query.column_names.length()) #array for column headers
+ fields = Array.new(query.column_names.length()){[]} #array for column fields
+ custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
+
+ # - _ - Retrieve the header and column data.
+
+ fields = retrieveFieldData(issues,query,decimal_separator,custom_fields)
+ headers = retrieveHeaders(query,custom_fields)
+ #fields[col][row] is a multi-dimensional array which holds all the field data for the csv table.
+ #...The first index is the column, and the second is the issue or row.
+ #
+ #headers[col] is an array which holds data for the column headers
+
+ # - _ - Now, Print the headers and fields
+
+ #Add bug number to the front of column headers list, via new array headersTemp
+ #Make '#' the first entry, then append with the 'headers' array
+ headersTemp = Array.new(1)
+ headersTemp[0] = "#"
+ 0.upto(headers.length()-1) do |counter|
+ headersTemp << headers[counter]
+ end
+
+ #print headers, via headersTemp
+ csv << headersTemp.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
+
+ #add bug number to the field arrays, via a new array called together
+ together = Array.new(issues.length())
+ issues.each do |issue| #for each issue...
+ together[issue.id] = [issue.id.to_s()] #add the issue id
+ #for each column in the issue...
+ 0.upto(@query.column_names.length() - 1) do |counter|
+ # construct the issue rows from the columns.
+ together[issue.id] << fields[counter][issue.id]
+ end
+ #print the fields to the screen, issue at a time, via together
+ csv << together[issue.id].collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
+ end
+ else # if no fields specified --> then display default fields in csv
+ # csv default header fields
+ headers = [ "#",
l(:field_status),
l(:field_project),
l(:field_tracker),
@@ -183,6 +343,7 @@
csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
end
end
+ end
export.rewind
export
end
Index: app/helpers/custom_fields_helper.rb
===================================================================
--- app/helpers/custom_fields_helper.rb (revision 2823)
+++ app/helpers/custom_fields_helper.rb (working copy)
@@ -85,4 +85,101 @@
def custom_field_formats_for_select
CustomField::FIELD_FORMATS.sort {|a,b| a[1][:order]<=>b[1][:order]}.collect { |k| [ l(k[1][:name]), k[0] ] }
end
-end
+
+
+ #Method Added 7/7/09
+ #Extracts the id from a custom column name
+ #E.g. "cf_6" becomes "6", which is the id for the custom column
+ def getIDFromCustomColName(colName)
+ return colName.gsub(/.*_(.*)/, '\1')
+ end
+
+#Method Added 7/7/09
+ #Capitalizes each word in a title
+ def capitalizeEachWord(title)
+ spaceFlag = nil
+ newTitle = ""
+ 0.upto(title.length() - 1) do |cntr|
+ char = title.slice(cntr..cntr)
+ if(cntr == 0)
+ char.capitalize!
+ elsif(char == " ")
+ spaceFlag = true
+ elsif(spaceFlag)
+ char.capitalize!
+ spaceFlag = nil
+ end
+ newTitle = newTitle + char
+ end
+ return newTitle
+ end
+
+#Method Added 7/7/09
+ #Returns the type of the custom field or the column name for default fields
+ def getType(issue,pos)
+ fieldType = ""
+
+ if (@query.column_names != nil) # make sure we have user query
+
+ col = @query.column_names[pos].to_s()
+
+ if (issue.respond_to?(col))
+ fieldType = col.to_s()
+
+ else # custom field
+ custom_fields = @project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields
+ columnName = @query.column_names[pos].to_s()
+ id = getIDFromCustomColName(columnName)
+ custom_fields.each do |custom_field|
+ if id == custom_field.id.to_s()
+ fieldType = custom_field.field_format.to_s()
+ break
+ end
+ end
+ end
+ end
+ return fieldType
+ end
+
+#Method Added 7/2/09
+ #Given an issue and a column this returns the correct data
+ def getValue(issue, pos)
+ fieldValue = ""
+ col = @query.column_names[pos].to_s()
+
+ #Default field
+ if(issue.respond_to?(col))
+ type = (issue.send(col)).type.to_s()
+ case type
+ when "Time"
+ fieldValue = format_time(issue.send(col))
+ when "Date"
+ fieldValue = format_date(issue.send(col))
+ when "Float", "String", "int", "Fixnum", ""
+ fieldValue = issue.send(col).to_s()
+ when "Text", "Tracker","IssueStatus", "IssueCategory", "Enumeration", "Version", "User", "Project"
+ fieldValue = issue.send(col).name
+ end
+
+ #Custom Field
+ else
+ custom_fields = @project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields
+ columnName = @query.column_names[pos].to_s()
+ id = getIDFromCustomColName(columnName)
+ custom_fields.each do |custom_field|
+ if id == custom_field.id.to_s()
+ type = custom_field.field_format.to_s()
+ fieldValue = show_value(issue.custom_value_for(custom_field))
+ break
+ end
+ end
+
+ #If type is a boolean value
+ if type == "bool"
+ fieldValue = (fieldValue == "1") ? "YES" : "NO"
+ end
+ end
+
+ return fieldValue
+ end
+end
\ No newline at end of file
Index: app/controllers/issues_controller.rb
===================================================================
--- app/controllers/issues_controller.rb (revision 2823)
+++ app/controllers/issues_controller.rb (working copy)
@@ -77,8 +77,12 @@
render :template => 'issues/index.rhtml', :layout => !request.xhr?
}
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
- format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
- format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
+ #Changed 7/7/09 - call smarter csv and pdf functions
+ format.csv { send_data(issues_to_csv(@issues, @query, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
+# format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
+ format.pdf { send_data(issues_to_pdf(@issues, @query, @project), :type => 'application/pdf', :filename => 'export.pdf') }
+# format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
+
end
else
# Send html if the query is not valid
Index: app/views/issues/_list.rhtml
===================================================================
--- app/views/issues/_list.rhtml (revision 2823)
+++ app/views/issues/_list.rhtml (working copy)
@@ -25,8 +25,20 @@
+
+
+ <% pos = 0 %>
+ <% query.columns.each do |column| %>
+ <% value = column.name %>
+
+ <% if query.column_names != nil %>
+ <% value = getType(issue, pos) %>
+ <% pos = pos + 1 %>
+ <% end %>
+
+ <%= content_tag 'td', column_content(column, issue), :class => value %>
+ <% end -%>
+
<% end -%>
Index: lib/redmine/export/pdf.rb
===================================================================
--- lib/redmine/export/pdf.rb (revision 2823)
+++ lib/redmine/export/pdf.rb (working copy)
@@ -22,6 +22,11 @@
module Redmine
module Export
module PDF
+ #Added 7/2/09
+#*****************************************************************************
+ MAXCOLSIZE = 60 #Maximum column size before wrappping (string length)
+ MAXPDFWIDTH = 250 #Approximate width of pdf document
+#*****************************************************************************
include ActionView::Helpers::TextHelper
include ActionView::Helpers::NumberHelper
@@ -96,7 +101,11 @@
super w,h,txt,border,ln,align,fill,link
end
- def Footer
+ #Method Changed 7/2/09
+ def Footer
+ tempSize = getFontSize()
+ tempFamily = getFontFamily()
+ tempStyle = getFontStyle()
SetFont(@font_for_footer, 'I', 8)
SetY(-15)
SetX(15)
@@ -104,13 +113,213 @@
SetY(-15)
SetX(-30)
Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
+ SetFont(tempFamily, tempStyle, tempSize)
end
end
-
- # Returns a PDF string of a list of issues
- def issues_to_pdf(issues, project, query)
- pdf = IFPDF.new(current_language)
- title = project ? "#{project} - #{l(:label_issue_plural)}" : "#{l(:label_issue_plural)}"
+ #Method Added 7/2/09
+ def printColumnHeadersPDF(query, issues, colWidth, row_height, fontSize, pdf, maxCustomContent)
+ # headers
+ pdf.SetFontStyle('B',fontSize)
+ pdf.SetFillColor(230, 230, 230)
+
+ #Print the column header
+ pdf.Cell(20, row_height, "#", 0, 0, 'L', 1)
+
+ 0.upto(@query.column_names.length - 1) do |cntr|
+ colName = query.column_names[cntr].to_s()
+ re = /^cf.*/ #identifier for the column names of custom fields
+
+ # custom field
+ if (re.match(colName))
+
+ custom_fields = @project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields
+ id = getIDFromCustomColName(colName)
+ custom_fields.each do |custom_field| #find the name
+ if id == custom_field.id.to_s()
+ colName = custom_field.name.to_s()
+ break
+ end
+ end
+ end
+
+ colName = colName.gsub(/[_]/, ' ').to_s() # convert underscores to spaces
+ colName = capitalizeEachWord(colName)
+ pdf.Cell(colWidth[cntr], row_height, colName, 0, 0, 'L', 1)
+ end
+
+ end
+
+ #Method Added 7/2/09
+ def printFieldsPDF(query, issues, colWidth, row_height, fontSize, pdf, rowHeightMultiCell, maxMultiColWidth)
+
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.Ln
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.SetY(pdf.GetY() + 1)
+ pdf.SetFontStyle('',fontSize)
+ pdf.SetFillColor(255, 255, 255)
+
+ #Print the rows
+ issues.each do |issue|
+ flag = 0 #How many lines occur during a text wrapping
+ flagPageBreak = 0 #Check if a page break has occurred
+ pageBreakPos = 0 #Position after the page break used for restoring
+
+ pdf.Cell(20, row_height, issue.id.to_s, 0, 0, 'L', 1)
+
+ 0.upto(query.column_names.length - 1) do |cntr|
+
+ if(getValue(issue,cntr).length < MAXCOLSIZE) #No text wrapping
+ pdf.SetFontStyle('',fontSize)
+ pdf.Cell(colWidth[cntr], row_height, getValue(issue,cntr))
+ else #For text wrapping
+ beforeX = pdf.GetX() #Before X position
+ beforeY = pdf.GetY() #Before Y position
+ pad = 1 #Extra Height of muli-cells
+
+ pdf.SetY(pdf.GetY() + pad)
+ pdf.SetX(beforeX)
+ pdf.MultiCell(colWidth[cntr], rowHeightMultiCell, getValue(issue,cntr))
+
+ afterX = pdf.GetX()
+ pdf.SetY(pdf.GetY() + pad)
+ pdf.SetX(afterX)
+
+ currentPage = pdf.getPage()
+ afterY = pdf.GetY() #After Y position
+ dif = afterY - beforeY #Difference after text wrapping
+ if(afterY < beforeY)
+ pdf.setPage(pdf.getPage - 1)
+ flagPageBreak = 1
+ if(pageBreakPos < afterY)
+ pageBreakPos = afterY
+ end
+ end
+
+ #Count the number of lines skipped
+ if(dif/rowHeightMultiCell > flag)
+ flag = 0
+ while (dif > 0)
+ dif = dif - rowHeightMultiCell
+ flag = flag + 1
+ end
+ end
+
+ pdf.SetY(beforeY)
+ pdf.SetX(beforeX + maxMultiColWidth)
+
+ end
+ end
+ if(flagPageBreak == 1) #Restore Page after break
+ pdf.setPage(pdf.getPage() + 1)
+ pdf.SetY(pageBreakPos - row_height)
+ flagPageBreak = 0
+ else
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ end
+ #Restore after wrapping
+ if(flag > 0)
+ pdf.SetY(pdf.GetY() + rowHeightMultiCell * flag)
+ else
+ pdf.SetY(pdf.GetY() + 10)
+ end
+ end
+ end
+
+#Method Added 7/7/09
+ def printUserQuery(pdf, row_height)
+
+ rowHeightMultiCell = 4 #Default height for multi-cell
+ fontSize = 10 #Font size before shinking
+ maxMultiColWidth = 120 #Maximium column width before wrapping
+ maxCustomContent = 0 #Issue that contains the most custom fields
+
+ arrMaxColLen = Array.new(@query.column_names.length) #Column Width in terms of characters based on the longest string
+ colWidth = Array.new(@query.column_names.length) #Contains the width of each column in pdf units
+
+
+ #Create an array containing the lengths of the largest fields in each column
+ 0.upto(@query.column_names.length - 1) do |cntr|
+ currentMax = 0;
+ @issues.each do |issue|
+ valueLength = getValue(issue,cntr).length()
+ if(valueLength > currentMax)
+ currentMax = valueLength
+ end
+ arrMaxColLen[cntr] = currentMax
+ end
+ end
+
+ #See if any of the headers are longer than the largest value
+ 0.upto(@query.column_names.length - 1) do |cntr|
+ len = 0 #Length of the column name header
+ re = /^cf.*/ #Identify column fields by their column headers
+
+ #Finds the length of the column name header
+ if (!re.match(@query.column_names[cntr].to_s()))
+ len = @query.column_names[cntr].to_s().length()
+ else #Custom Field
+ max = 0
+ 0.upto(@issues.length - 1) do |issue|
+ if(@issues[issue].custom_values.length() > max)
+ max = @issues[issue].custom_values.length()
+ maxCustomContent = issue #Issue that contains the most custom fields
+ end
+ end
+ columnNameId = getIDFromCustomColName(@query.column_names[cntr].to_s())
+ 0.upto(@issues[maxCustomContent].custom_values.length - 1) do |custom_value|
+ customField = @issues[maxCustomContent].custom_values[custom_value].custom_field
+
+ if (customField.id.to_s() == columnNameId)
+ len = customField.name.length() #Length of the header of the custom fields
+ end
+ end
+ end
+
+ #Check if column name headers are larger than the fields
+ if(arrMaxColLen[cntr] < len)
+ arrMaxColLen[cntr] = len
+ end
+ end
+
+ #Set each column width given the value lengths
+ 0.upto(@query.column_names.length - 1) do |cntr|
+ ourColumnWidth = arrMaxColLen[cntr] * 1.5 + 10
+
+ colWidth[cntr] = (ourColumnWidth < maxMultiColWidth) ? ourColumnWidth : maxMultiColWidth
+ end
+
+ #Total column length of the whole page
+ total = 0
+ 0.upto(colWidth.length - 1) do |cntr|
+ total = total + colWidth[cntr]
+ end
+
+ #Scales the font sizes based on column data width
+ percent = 1.0
+ if(total > MAXPDFWIDTH)
+ percent = MAXPDFWIDTH.to_f()/total.to_f()
+ maxMultiColWidth = percent * maxMultiColWidth
+ 0.upto(@query.column_names.length - 1) do |cntr|
+ colWidth[cntr] = colWidth[cntr] * percent
+ end
+ fontSize = fontSize * 0.75 * percent
+ pdf.SetFontStyle('B',fontSize)
+ end
+
+ printColumnHeadersPDF(@query, @issues, colWidth, row_height, fontSize, pdf, maxCustomContent)
+ printFieldsPDF (@query, @issues, colWidth, row_height, fontSize, pdf, rowHeightMultiCell, maxMultiColWidth)
+ end
+
+
+ # Returns a PDF string of a list of issues
+ def issues_to_pdf(issues, query, project)
+ pdf = IFPDF.new(current_language)
+ if(query.name != "_")
+ title = project ? "#{project} - #{@query.name.to_s()}" : " #{@query.name.to_s()}"
+ else
+ title = project ? "#{project} - #{l(:label_issue_plural)}" : "#{l(:label_issue_plural)}"
+ end
pdf.SetTitle(title)
pdf.AliasNbPages
pdf.footer_date = format_date(Date.today)
@@ -122,48 +331,53 @@
pdf.Cell(190,10, title)
pdf.Ln
- # headers
- pdf.SetFontStyle('B',10)
- pdf.SetFillColor(230, 230, 230)
- pdf.Cell(15, row_height, "#", 0, 0, 'L', 1)
- pdf.Cell(30, row_height, l(:field_tracker), 0, 0, 'L', 1)
- pdf.Cell(30, row_height, l(:field_status), 0, 0, 'L', 1)
- pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1)
- pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1)
- pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1)
- pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1)
- pdf.Line(10, pdf.GetY, 287, pdf.GetY)
- pdf.Ln
- pdf.Line(10, pdf.GetY, 287, pdf.GetY)
- pdf.SetY(pdf.GetY() + 1)
+ # headers
+ #If there are column names
+ if(@query.column_names != nil)
+ printUserQuery(pdf, row_height)
+ else #If there are no columns
+ pdf.SetFontStyle('B',10)
+ pdf.SetFillColor(230, 230, 230)
+ pdf.Cell(15, row_height, "#", 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, l(:field_tracker), 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, l(:field_status), 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1)
+ pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1)
+ pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1)
+ pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1)
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.Ln
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.SetY(pdf.GetY() + 1)
- # rows
- pdf.SetFontStyle('',9)
- pdf.SetFillColor(255, 255, 255)
- group = false
- issues.each do |issue|
- if query.grouped? && issue.send(query.group_by) != group
- group = issue.send(query.group_by)
- pdf.SetFontStyle('B',10)
- pdf.Cell(0, row_height, "#{group.blank? ? 'None' : group.to_s}", 0, 1, 'L')
- pdf.Line(10, pdf.GetY, 287, pdf.GetY)
- pdf.SetY(pdf.GetY() + 0.5)
- pdf.Line(10, pdf.GetY, 287, pdf.GetY)
- pdf.SetY(pdf.GetY() + 1)
- pdf.SetFontStyle('',9)
+ # rows
+ pdf.SetFontStyle('',9)
+ pdf.SetFillColor(255, 255, 255)
+ group = false
+ issues.each do |issue|
+ if query.grouped? && issue.send(query.group_by) != group
+ group = issue.send(query.group_by)
+ pdf.SetFontStyle('B',10)
+ pdf.Cell(0, row_height, "#{group.blank? ? 'None' : group.to_s}", 0, 1, 'L')
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.SetY(pdf.GetY() + 0.5)
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.SetY(pdf.GetY() + 1)
+ pdf.SetFontStyle('',9)
+ end
+ pdf.Cell(15, row_height, issue.id.to_s, 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, issue.tracker.name, 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, issue.status.name, 0, 0, 'L', 1)
+ pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1)
+ pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.to_s : '', 0, 0, 'L', 1)
+ pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1)
+ pdf.MultiCell(0, row_height, (project == issue.project ? issue.subject : "#{issue.project} - #{issue.subject}"))
+ pdf.Line(10, pdf.GetY, 287, pdf.GetY)
+ pdf.SetY(pdf.GetY() + 1)
end
- pdf.Cell(15, row_height, issue.id.to_s, 0, 0, 'L', 1)
- pdf.Cell(30, row_height, issue.tracker.name, 0, 0, 'L', 1)
- pdf.Cell(30, row_height, issue.status.name, 0, 0, 'L', 1)
- pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1)
- pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.to_s : '', 0, 0, 'L', 1)
- pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1)
- pdf.MultiCell(0, row_height, (project == issue.project ? issue.subject : "#{issue.project} - #{issue.subject}"))
- pdf.Line(10, pdf.GetY, 287, pdf.GetY)
- pdf.SetY(pdf.GetY() + 1)
- end
+ end
pdf.Output
- end
+ end
# Returns a PDF string of a single issue
def issue_to_pdf(issue)
Index: vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb
===================================================================
--- vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb (revision 2823)
+++ vendor/plugins/rfpdf/lib/rfpdf/fpdf.rb (working copy)
@@ -279,6 +279,14 @@
end
def AddPage(orientation='')
+ #Added 7/2/09
+#************************************
+ #If next page already exists
+ if(getPage() < @pages.length() - 1)
+ setPage(getPage() + 1)
+ @y = 0 + @tMargin
+#************************************
+ else
# Start a new page
self.Open if @state==0
family=@FontFamily
@@ -313,6 +321,7 @@
out(fc) if fc!='0 g'
@TextColor=tc
@ColorFlag=cf
+ end
# Page header
self.Header
# Restore line width
@@ -870,9 +879,30 @@
@y=@y+@lasth
else
@y=@y+h
- end
+ end
+ end
+
+ #Added 7/2/09 for pdf.rb
+#***********************
+ def getFontFamily
+ @FontFamily
+ end
+
+ def getFontStyle
+ @FontStyle
+ end
+
+ def getFontSize
+ @FontSizePt
end
+ def getPage()
+ @page
+ end
+ def setPage(page)
+ @page = page
+ end
+#**********************
def GetX
# Get x position
@x
Index: public/stylesheets/application.css
===================================================================
--- public/stylesheets/application.css (revision 2823)
+++ public/stylesheets/application.css (working copy)
@@ -93,10 +93,12 @@
tr.project td.name a { padding-left: 16px; white-space:nowrap; }
tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; }
-
-tr.issue { text-align: center; white-space: nowrap; }
-tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }
-tr.issue td.subject { text-align: left; }
+ /*** Changed 7/7/09 - nowrap was a bad idea! ***/
+tr.issue { text-align: center; white-space: normal; }
+/*tr.issue { text-align: center; white-space: nowrap; }
+tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; }*/
+tr.issue td.subject, tr.issue td.text, tr.issue td.string { text-align: left; }
+/*tr.issue td.subject { text-align: left; }*/
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
tr.entry { border: 1px solid #f8f8f8; }