annotate lib/redmine/export/pdf.rb @ 872:9d7526c3a78a feature_124

Close obsolete branch feature_124
author Chris Cannam
date Sat, 02 Apr 2011 11:56:49 +0100
parents 40f7cfd4df19
children 0579821a129a
rev   line source
Chris@0 1 # encoding: utf-8
Chris@0 2 #
Chris@0 3 # Redmine - project management software
Chris@0 4 # Copyright (C) 2006-2009 Jean-Philippe Lang
Chris@0 5 #
Chris@0 6 # This program is free software; you can redistribute it and/or
Chris@0 7 # modify it under the terms of the GNU General Public License
Chris@0 8 # as published by the Free Software Foundation; either version 2
Chris@0 9 # of the License, or (at your option) any later version.
Chris@0 10 #
Chris@0 11 # This program is distributed in the hope that it will be useful,
Chris@0 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 14 # GNU General Public License for more details.
Chris@0 15 #
Chris@0 16 # You should have received a copy of the GNU General Public License
Chris@0 17 # along with this program; if not, write to the Free Software
Chris@0 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 19
Chris@0 20 require 'iconv'
Chris@0 21 require 'rfpdf/fpdf'
Chris@0 22 require 'rfpdf/chinese'
Chris@0 23
Chris@0 24 module Redmine
Chris@0 25 module Export
Chris@0 26 module PDF
Chris@0 27 include ActionView::Helpers::TextHelper
Chris@0 28 include ActionView::Helpers::NumberHelper
Chris@0 29
Chris@0 30 class IFPDF < FPDF
Chris@0 31 include Redmine::I18n
Chris@0 32 attr_accessor :footer_date
Chris@0 33
Chris@0 34 def initialize(lang)
Chris@0 35 super()
Chris@0 36 set_language_if_valid lang
Chris@0 37 case current_language.to_s.downcase
Chris@0 38 when 'ko'
Chris@0 39 extend(PDF_Korean)
Chris@0 40 AddUHCFont()
Chris@0 41 @font_for_content = 'UHC'
Chris@0 42 @font_for_footer = 'UHC'
Chris@0 43 when 'ja'
Chris@0 44 extend(PDF_Japanese)
Chris@0 45 AddSJISFont()
Chris@0 46 @font_for_content = 'SJIS'
Chris@0 47 @font_for_footer = 'SJIS'
Chris@0 48 when 'zh'
Chris@0 49 extend(PDF_Chinese)
Chris@0 50 AddGBFont()
Chris@0 51 @font_for_content = 'GB'
Chris@0 52 @font_for_footer = 'GB'
Chris@0 53 when 'zh-tw'
Chris@0 54 extend(PDF_Chinese)
Chris@0 55 AddBig5Font()
Chris@0 56 @font_for_content = 'Big5'
Chris@0 57 @font_for_footer = 'Big5'
Chris@0 58 else
Chris@0 59 @font_for_content = 'Arial'
Chris@0 60 @font_for_footer = 'Helvetica'
Chris@0 61 end
Chris@0 62 SetCreator(Redmine::Info.app_name)
Chris@0 63 SetFont(@font_for_content)
Chris@0 64 end
Chris@0 65
Chris@0 66 def SetFontStyle(style, size)
Chris@0 67 SetFont(@font_for_content, style, size)
Chris@0 68 end
Chris@0 69
Chris@0 70 def SetTitle(txt)
Chris@0 71 txt = begin
Chris@0 72 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
Chris@0 73 hextxt = "<FEFF" # FEFF is BOM
Chris@0 74 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
Chris@0 75 hextxt << ">"
Chris@0 76 rescue
Chris@0 77 txt
Chris@0 78 end || ''
Chris@0 79 super(txt)
Chris@0 80 end
Chris@0 81
Chris@0 82 def textstring(s)
Chris@0 83 # Format a text string
Chris@0 84 if s =~ /^</ # This means the string is hex-dumped.
Chris@0 85 return s
Chris@0 86 else
Chris@0 87 return '('+escape(s)+')'
Chris@0 88 end
Chris@0 89 end
Chris@0 90
Chris@0 91 def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
Chris@0 92 @ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
Chris@0 93 # these quotation marks are not correctly rendered in the pdf
Chris@0 94 txt = txt.gsub(/[“�]/, '"') if txt
Chris@0 95 txt = begin
Chris@0 96 # 0x5c char handling
Chris@0 97 txtar = txt.split('\\')
Chris@0 98 txtar << '' if txt[-1] == ?\\
Chris@0 99 txtar.collect {|x| @ic.iconv(x)}.join('\\').gsub(/\\/, "\\\\\\\\")
Chris@0 100 rescue
Chris@0 101 txt
Chris@0 102 end || ''
Chris@0 103 super w,h,txt,border,ln,align,fill,link
Chris@0 104 end
Chris@0 105
Chris@0 106 def Footer
Chris@0 107 SetFont(@font_for_footer, 'I', 8)
Chris@0 108 SetY(-15)
Chris@0 109 SetX(15)
Chris@0 110 Cell(0, 5, @footer_date, 0, 0, 'L')
Chris@0 111 SetY(-15)
Chris@0 112 SetX(-30)
Chris@0 113 Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
Chris@0 114 end
Chris@0 115 end
Chris@0 116
Chris@0 117 # Returns a PDF string of a list of issues
Chris@0 118 def issues_to_pdf(issues, project, query)
Chris@0 119 pdf = IFPDF.new(current_language)
Chris@0 120 title = query.new_record? ? l(:label_issue_plural) : query.name
Chris@0 121 title = "#{project} - #{title}" if project
Chris@0 122 pdf.SetTitle(title)
Chris@0 123 pdf.AliasNbPages
Chris@0 124 pdf.footer_date = format_date(Date.today)
Chris@0 125 pdf.AddPage("L")
Chris@0 126
Chris@0 127 row_height = 6
Chris@0 128 col_width = []
Chris@0 129 unless query.columns.empty?
Chris@0 130 col_width = query.columns.collect {|column| column.name == :subject ? 4.0 : 1.0 }
Chris@0 131 ratio = 262.0 / col_width.inject(0) {|s,w| s += w}
Chris@0 132 col_width = col_width.collect {|w| w * ratio}
Chris@0 133 end
Chris@0 134
Chris@0 135 # title
Chris@0 136 pdf.SetFontStyle('B',11)
Chris@0 137 pdf.Cell(190,10, title)
Chris@0 138 pdf.Ln
Chris@0 139
Chris@0 140 # headers
Chris@0 141 pdf.SetFontStyle('B',8)
Chris@0 142 pdf.SetFillColor(230, 230, 230)
Chris@0 143 pdf.Cell(15, row_height, "#", 1, 0, 'L', 1)
Chris@0 144 query.columns.each_with_index do |column, i|
Chris@0 145 pdf.Cell(col_width[i], row_height, column.caption, 1, 0, 'L', 1)
Chris@0 146 end
Chris@0 147 pdf.Ln
Chris@0 148
Chris@0 149 # rows
Chris@0 150 pdf.SetFontStyle('',8)
Chris@0 151 pdf.SetFillColor(255, 255, 255)
Chris@0 152 previous_group = false
Chris@0 153 issues.each do |issue|
Chris@0 154 if query.grouped? && (group = query.group_by_column.value(issue)) != previous_group
Chris@0 155 pdf.SetFontStyle('B',9)
Chris@0 156 pdf.Cell(277, row_height,
chris@22 157 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
Chris@0 158 1, 1, 'L')
Chris@0 159 pdf.SetFontStyle('',8)
Chris@0 160 previous_group = group
Chris@0 161 end
Chris@0 162 pdf.Cell(15, row_height, issue.id.to_s, 1, 0, 'L', 1)
Chris@0 163 query.columns.each_with_index do |column, i|
Chris@0 164 s = if column.is_a?(QueryCustomFieldColumn)
Chris@0 165 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
Chris@0 166 show_value(cv)
Chris@0 167 else
Chris@0 168 value = issue.send(column.name)
Chris@0 169 if value.is_a?(Date)
Chris@0 170 format_date(value)
Chris@0 171 elsif value.is_a?(Time)
Chris@0 172 format_time(value)
Chris@0 173 else
Chris@0 174 value
Chris@0 175 end
Chris@0 176 end
Chris@0 177 pdf.Cell(col_width[i], row_height, s.to_s, 1, 0, 'L', 1)
Chris@0 178 end
Chris@0 179 pdf.Ln
Chris@0 180 end
Chris@0 181 if issues.size == Setting.issues_export_limit.to_i
Chris@0 182 pdf.SetFontStyle('B',10)
Chris@0 183 pdf.Cell(0, row_height, '...')
Chris@0 184 end
Chris@0 185 pdf.Output
Chris@0 186 end
chris@22 187
Chris@0 188 # Returns a PDF string of a single issue
Chris@0 189 def issue_to_pdf(issue)
Chris@0 190 pdf = IFPDF.new(current_language)
Chris@0 191 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
Chris@0 192 pdf.AliasNbPages
Chris@0 193 pdf.footer_date = format_date(Date.today)
Chris@0 194 pdf.AddPage
Chris@0 195
Chris@0 196 pdf.SetFontStyle('B',11)
Chris@0 197 pdf.Cell(190,10, "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
Chris@0 198 pdf.Ln
Chris@0 199
Chris@0 200 y0 = pdf.GetY
Chris@0 201
Chris@0 202 pdf.SetFontStyle('B',9)
Chris@0 203 pdf.Cell(35,5, l(:field_status) + ":","LT")
Chris@0 204 pdf.SetFontStyle('',9)
Chris@0 205 pdf.Cell(60,5, issue.status.to_s,"RT")
Chris@0 206 pdf.SetFontStyle('B',9)
Chris@0 207 pdf.Cell(35,5, l(:field_priority) + ":","LT")
Chris@0 208 pdf.SetFontStyle('',9)
Chris@0 209 pdf.Cell(60,5, issue.priority.to_s,"RT")
Chris@0 210 pdf.Ln
chris@22 211
Chris@0 212 pdf.SetFontStyle('B',9)
Chris@0 213 pdf.Cell(35,5, l(:field_author) + ":","L")
Chris@0 214 pdf.SetFontStyle('',9)
Chris@0 215 pdf.Cell(60,5, issue.author.to_s,"R")
Chris@0 216 pdf.SetFontStyle('B',9)
Chris@0 217 pdf.Cell(35,5, l(:field_category) + ":","L")
Chris@0 218 pdf.SetFontStyle('',9)
Chris@0 219 pdf.Cell(60,5, issue.category.to_s,"R")
Chris@0 220 pdf.Ln
Chris@0 221
Chris@0 222 pdf.SetFontStyle('B',9)
Chris@0 223 pdf.Cell(35,5, l(:field_created_on) + ":","L")
Chris@0 224 pdf.SetFontStyle('',9)
Chris@0 225 pdf.Cell(60,5, format_date(issue.created_on),"R")
Chris@0 226 pdf.SetFontStyle('B',9)
Chris@0 227 pdf.Cell(35,5, l(:field_assigned_to) + ":","L")
Chris@0 228 pdf.SetFontStyle('',9)
Chris@0 229 pdf.Cell(60,5, issue.assigned_to.to_s,"R")
Chris@0 230 pdf.Ln
Chris@0 231
Chris@0 232 pdf.SetFontStyle('B',9)
Chris@0 233 pdf.Cell(35,5, l(:field_updated_on) + ":","LB")
Chris@0 234 pdf.SetFontStyle('',9)
Chris@0 235 pdf.Cell(60,5, format_date(issue.updated_on),"RB")
Chris@0 236 pdf.SetFontStyle('B',9)
Chris@0 237 pdf.Cell(35,5, l(:field_due_date) + ":","LB")
Chris@0 238 pdf.SetFontStyle('',9)
Chris@0 239 pdf.Cell(60,5, format_date(issue.due_date),"RB")
Chris@0 240 pdf.Ln
chris@22 241
Chris@0 242 for custom_value in issue.custom_field_values
Chris@0 243 pdf.SetFontStyle('B',9)
Chris@0 244 pdf.Cell(35,5, custom_value.custom_field.name + ":","L")
Chris@0 245 pdf.SetFontStyle('',9)
Chris@0 246 pdf.MultiCell(155,5, (show_value custom_value),"R")
Chris@0 247 end
chris@22 248
Chris@0 249 pdf.SetFontStyle('B',9)
Chris@0 250 pdf.Cell(35,5, l(:field_subject) + ":","LTB")
Chris@0 251 pdf.SetFontStyle('',9)
Chris@0 252 pdf.Cell(155,5, issue.subject,"RTB")
Chris@0 253 pdf.Ln
Chris@0 254
Chris@0 255 pdf.SetFontStyle('B',9)
Chris@0 256 pdf.Cell(35,5, l(:field_description) + ":")
Chris@0 257 pdf.SetFontStyle('',9)
chris@22 258 pdf.MultiCell(155,5, issue.description,"BR")
Chris@0 259
Chris@0 260 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
Chris@0 261 pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY)
Chris@0 262 pdf.Ln
Chris@0 263
Chris@0 264 if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project)
Chris@0 265 pdf.SetFontStyle('B',9)
Chris@0 266 pdf.Cell(190,5, l(:label_associated_revisions), "B")
Chris@0 267 pdf.Ln
Chris@0 268 for changeset in issue.changesets
Chris@0 269 pdf.SetFontStyle('B',8)
Chris@0 270 pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s)
Chris@0 271 pdf.Ln
Chris@0 272 unless changeset.comments.blank?
Chris@0 273 pdf.SetFontStyle('',8)
Chris@0 274 pdf.MultiCell(190,5, changeset.comments)
Chris@0 275 end
Chris@0 276 pdf.Ln
Chris@0 277 end
Chris@0 278 end
Chris@0 279
Chris@0 280 pdf.SetFontStyle('B',9)
Chris@0 281 pdf.Cell(190,5, l(:label_history), "B")
Chris@0 282 pdf.Ln
Chris@0 283 for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
Chris@0 284 pdf.SetFontStyle('B',8)
Chris@0 285 pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name)
Chris@0 286 pdf.Ln
Chris@0 287 pdf.SetFontStyle('I',8)
Chris@0 288 for detail in journal.details
Chris@0 289 pdf.Cell(190,5, "- " + show_detail(detail, true))
Chris@0 290 pdf.Ln
Chris@0 291 end
Chris@0 292 if journal.notes?
Chris@0 293 pdf.SetFontStyle('',8)
Chris@0 294 pdf.MultiCell(190,5, journal.notes)
Chris@0 295 end
Chris@0 296 pdf.Ln
Chris@0 297 end
Chris@0 298
Chris@0 299 if issue.attachments.any?
Chris@0 300 pdf.SetFontStyle('B',9)
Chris@0 301 pdf.Cell(190,5, l(:label_attachment_plural), "B")
Chris@0 302 pdf.Ln
Chris@0 303 for attachment in issue.attachments
Chris@0 304 pdf.SetFontStyle('',8)
Chris@0 305 pdf.Cell(80,5, attachment.filename)
Chris@0 306 pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
Chris@0 307 pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R")
Chris@0 308 pdf.Cell(65,5, attachment.author.name,0,0,"R")
Chris@0 309 pdf.Ln
Chris@0 310 end
Chris@0 311 end
Chris@0 312 pdf.Output
Chris@0 313 end
chris@22 314
Chris@0 315 end
Chris@0 316 end
Chris@0 317 end