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