##// END OF EJS Templates
PDF: code clean up lib/redmine/export/pdf.rb....
Toshi MARUYAMA -
r6018:aa973f0af699
parent child
Show More
@@ -1,445 +1,445
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2011 Jean-Philippe Lang
4 # Copyright (C) 2006-2011 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 'fpdf/chinese'
22 require 'fpdf/chinese'
23 require 'fpdf/japanese'
23 require 'fpdf/japanese'
24 require 'fpdf/korean'
24 require 'fpdf/korean'
25
25
26 module Redmine
26 module Redmine
27 module Export
27 module Export
28 module PDF
28 module PDF
29 include ActionView::Helpers::TextHelper
29 include ActionView::Helpers::TextHelper
30 include ActionView::Helpers::NumberHelper
30 include ActionView::Helpers::NumberHelper
31
31
32 class ITCPDF < TCPDF
32 class ITCPDF < TCPDF
33 include Redmine::I18n
33 include Redmine::I18n
34 attr_accessor :footer_date
34 attr_accessor :footer_date
35
35
36 def initialize(lang)
36 def initialize(lang)
37 set_language_if_valid lang
37 set_language_if_valid lang
38 pdf_encoding = l(:general_pdf_encoding).upcase
38 pdf_encoding = l(:general_pdf_encoding).upcase
39 if RUBY_VERSION < '1.9'
39 if RUBY_VERSION < '1.9'
40 @ic = Iconv.new(pdf_encoding, 'UTF-8')
40 @ic = Iconv.new(pdf_encoding, 'UTF-8')
41 end
41 end
42 super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
42 super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
43 case current_language.to_s.downcase
43 case current_language.to_s.downcase
44 when 'vi'
44 when 'vi'
45 @font_for_content = 'DejaVuSans'
45 @font_for_content = 'DejaVuSans'
46 @font_for_footer = 'DejaVuSans'
46 @font_for_footer = 'DejaVuSans'
47 else
47 else
48 case pdf_encoding
48 case pdf_encoding
49 when 'UTF-8'
49 when 'UTF-8'
50 @font_for_content = 'FreeSans'
50 @font_for_content = 'FreeSans'
51 @font_for_footer = 'FreeSans'
51 @font_for_footer = 'FreeSans'
52 when 'CP949'
52 when 'CP949'
53 extend(PDF_Korean)
53 extend(PDF_Korean)
54 AddUHCFont()
54 AddUHCFont()
55 @font_for_content = 'UHC'
55 @font_for_content = 'UHC'
56 @font_for_footer = 'UHC'
56 @font_for_footer = 'UHC'
57 when 'CP932', 'SJIS', 'SHIFT_JIS'
57 when 'CP932', 'SJIS', 'SHIFT_JIS'
58 extend(PDF_Japanese)
58 extend(PDF_Japanese)
59 AddSJISFont()
59 AddSJISFont()
60 @font_for_content = 'SJIS'
60 @font_for_content = 'SJIS'
61 @font_for_footer = 'SJIS'
61 @font_for_footer = 'SJIS'
62 when 'GB18030'
62 when 'GB18030'
63 extend(PDF_Chinese)
63 extend(PDF_Chinese)
64 AddGBFont()
64 AddGBFont()
65 @font_for_content = 'GB'
65 @font_for_content = 'GB'
66 @font_for_footer = 'GB'
66 @font_for_footer = 'GB'
67 when 'BIG5'
67 when 'BIG5'
68 extend(PDF_Chinese)
68 extend(PDF_Chinese)
69 AddBig5Font()
69 AddBig5Font()
70 @font_for_content = 'Big5'
70 @font_for_content = 'Big5'
71 @font_for_footer = 'Big5'
71 @font_for_footer = 'Big5'
72 else
72 else
73 @font_for_content = 'Arial'
73 @font_for_content = 'Arial'
74 @font_for_footer = 'Helvetica'
74 @font_for_footer = 'Helvetica'
75 end
75 end
76 end
76 end
77 SetCreator(Redmine::Info.app_name)
77 SetCreator(Redmine::Info.app_name)
78 SetFont(@font_for_content)
78 SetFont(@font_for_content)
79 end
79 end
80
80
81 def SetFontStyle(style, size)
81 def SetFontStyle(style, size)
82 SetFont(@font_for_content, style, size)
82 SetFont(@font_for_content, style, size)
83 end
83 end
84
84
85 def SetTitle(txt)
85 def SetTitle(txt)
86 txt = begin
86 txt = begin
87 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
87 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
88 hextxt = "<FEFF" # FEFF is BOM
88 hextxt = "<FEFF" # FEFF is BOM
89 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
89 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
90 hextxt << ">"
90 hextxt << ">"
91 rescue
91 rescue
92 txt
92 txt
93 end || ''
93 end || ''
94 super(txt)
94 super(txt)
95 end
95 end
96
96
97 def textstring(s)
97 def textstring(s)
98 # Format a text string
98 # Format a text string
99 if s =~ /^</ # This means the string is hex-dumped.
99 if s =~ /^</ # This means the string is hex-dumped.
100 return s
100 return s
101 else
101 else
102 return '('+escape(s)+')'
102 return '('+escape(s)+')'
103 end
103 end
104 end
104 end
105
105
106 def fix_text_encoding(txt)
106 def fix_text_encoding(txt)
107 RDMPdfEncoding::rdm_pdf_iconv(@ic, txt)
107 RDMPdfEncoding::rdm_pdf_iconv(@ic, txt)
108 end
108 end
109
109
110 def RDMCell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
110 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
111 Cell(w,h,fix_text_encoding(txt),border,ln,align,fill,link)
111 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
112 end
112 end
113
113
114 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
114 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
115 MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
115 MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
116 end
116 end
117
117
118 def RDMwriteHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0)
118 def RDMwriteHTMLCell(w, h, x, y, html='', border=0, ln=1, fill=0)
119 writeHTMLCell(w, h, x, y, fix_text_encoding(html), border, ln, fill)
119 writeHTMLCell(w, h, x, y, fix_text_encoding(html), border, ln, fill)
120 end
120 end
121
121
122 def Footer
122 def Footer
123 SetFont(@font_for_footer, 'I', 8)
123 SetFont(@font_for_footer, 'I', 8)
124 SetY(-15)
124 SetY(-15)
125 SetX(15)
125 SetX(15)
126 RDMCell(0, 5, @footer_date, 0, 0, 'L')
126 RDMCell(0, 5, @footer_date, 0, 0, 'L')
127 SetY(-15)
127 SetY(-15)
128 SetX(-30)
128 SetX(-30)
129 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
129 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
130 end
130 end
131 end
131 end
132
132
133 # Returns a PDF string of a list of issues
133 # Returns a PDF string of a list of issues
134 def issues_to_pdf(issues, project, query)
134 def issues_to_pdf(issues, project, query)
135 pdf = ITCPDF.new(current_language)
135 pdf = ITCPDF.new(current_language)
136 title = query.new_record? ? l(:label_issue_plural) : query.name
136 title = query.new_record? ? l(:label_issue_plural) : query.name
137 title = "#{project} - #{title}" if project
137 title = "#{project} - #{title}" if project
138 pdf.SetTitle(title)
138 pdf.SetTitle(title)
139 pdf.alias_nb_pages
139 pdf.alias_nb_pages
140 pdf.footer_date = format_date(Date.today)
140 pdf.footer_date = format_date(Date.today)
141 pdf.SetAutoPageBreak(false)
141 pdf.SetAutoPageBreak(false)
142 pdf.AddPage("L")
142 pdf.AddPage("L")
143
143
144 # Landscape A4 = 210 x 297 mm
144 # Landscape A4 = 210 x 297 mm
145 page_height = 210
145 page_height = 210
146 page_width = 297
146 page_width = 297
147 right_margin = 10
147 right_margin = 10
148 bottom_margin = 20
148 bottom_margin = 20
149 col_id_width = 10
149 col_id_width = 10
150 row_height = 5
150 row_height = 5
151
151
152 # column widths
152 # column widths
153 table_width = page_width - right_margin - 10 # fixed left margin
153 table_width = page_width - right_margin - 10 # fixed left margin
154 col_width = []
154 col_width = []
155 unless query.columns.empty?
155 unless query.columns.empty?
156 col_width = query.columns.collect do |c|
156 col_width = query.columns.collect do |c|
157 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) && ['string', 'text'].include?(c.custom_field.field_format)))? 4.0 : 1.0
157 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) && ['string', 'text'].include?(c.custom_field.field_format)))? 4.0 : 1.0
158 end
158 end
159 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
159 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
160 col_width = col_width.collect {|w| w * ratio}
160 col_width = col_width.collect {|w| w * ratio}
161 end
161 end
162
162
163 # title
163 # title
164 pdf.SetFontStyle('B',11)
164 pdf.SetFontStyle('B',11)
165 pdf.RDMCell(190,10, title)
165 pdf.RDMCell(190,10, title)
166 pdf.Ln
166 pdf.Ln
167
167
168 # headers
168 # headers
169 pdf.SetFontStyle('B',8)
169 pdf.SetFontStyle('B',8)
170 pdf.SetFillColor(230, 230, 230)
170 pdf.SetFillColor(230, 230, 230)
171
171
172 # render it background to find the max height used
172 # render it background to find the max height used
173 base_x = pdf.GetX
173 base_x = pdf.GetX
174 base_y = pdf.GetY
174 base_y = pdf.GetY
175 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
175 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
176 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
176 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
177 pdf.SetXY(base_x, base_y);
177 pdf.SetXY(base_x, base_y);
178
178
179 # write the cells on page
179 # write the cells on page
180 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
180 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
181 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
181 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
182 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
182 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
183 pdf.SetY(base_y + max_height);
183 pdf.SetY(base_y + max_height);
184
184
185 # rows
185 # rows
186 pdf.SetFontStyle('',8)
186 pdf.SetFontStyle('',8)
187 pdf.SetFillColor(255, 255, 255)
187 pdf.SetFillColor(255, 255, 255)
188 previous_group = false
188 previous_group = false
189 issues.each do |issue|
189 issues.each do |issue|
190 if query.grouped? &&
190 if query.grouped? &&
191 (group = query.group_by_column.value(issue)) != previous_group
191 (group = query.group_by_column.value(issue)) != previous_group
192 pdf.SetFontStyle('B',9)
192 pdf.SetFontStyle('B',9)
193 pdf.RDMCell(277, row_height,
193 pdf.RDMCell(277, row_height,
194 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
194 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
195 1, 1, 'L')
195 1, 1, 'L')
196 pdf.SetFontStyle('',8)
196 pdf.SetFontStyle('',8)
197 previous_group = group
197 previous_group = group
198 end
198 end
199 # fetch all the row values
199 # fetch all the row values
200 col_values = query.columns.collect do |column|
200 col_values = query.columns.collect do |column|
201 s = if column.is_a?(QueryCustomFieldColumn)
201 s = if column.is_a?(QueryCustomFieldColumn)
202 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
202 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
203 show_value(cv)
203 show_value(cv)
204 else
204 else
205 value = issue.send(column.name)
205 value = issue.send(column.name)
206 if value.is_a?(Date)
206 if value.is_a?(Date)
207 format_date(value)
207 format_date(value)
208 elsif value.is_a?(Time)
208 elsif value.is_a?(Time)
209 format_time(value)
209 format_time(value)
210 else
210 else
211 value
211 value
212 end
212 end
213 end
213 end
214 s.to_s
214 s.to_s
215 end
215 end
216
216
217 # render it off-page to find the max height used
217 # render it off-page to find the max height used
218 base_x = pdf.GetX
218 base_x = pdf.GetX
219 base_y = pdf.GetY
219 base_y = pdf.GetY
220 pdf.SetY(2 * page_height)
220 pdf.SetY(2 * page_height)
221 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
221 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
222 pdf.SetXY(base_x, base_y)
222 pdf.SetXY(base_x, base_y)
223
223
224 # make new page if it doesn't fit on the current one
224 # make new page if it doesn't fit on the current one
225 space_left = page_height - base_y - bottom_margin
225 space_left = page_height - base_y - bottom_margin
226 if max_height > space_left
226 if max_height > space_left
227 pdf.AddPage("L")
227 pdf.AddPage("L")
228 base_x = pdf.GetX
228 base_x = pdf.GetX
229 base_y = pdf.GetY
229 base_y = pdf.GetY
230 end
230 end
231
231
232 # write the cells on page
232 # write the cells on page
233 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
233 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
234 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
234 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
235 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
235 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
236 pdf.SetY(base_y + max_height);
236 pdf.SetY(base_y + max_height);
237 end
237 end
238
238
239 if issues.size == Setting.issues_export_limit.to_i
239 if issues.size == Setting.issues_export_limit.to_i
240 pdf.SetFontStyle('B',10)
240 pdf.SetFontStyle('B',10)
241 pdf.RDMCell(0, row_height, '...')
241 pdf.RDMCell(0, row_height, '...')
242 end
242 end
243 pdf.Output
243 pdf.Output
244 end
244 end
245
245
246 # Renders MultiCells and returns the maximum height used
246 # Renders MultiCells and returns the maximum height used
247 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
247 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
248 row_height, head=false)
248 row_height, head=false)
249 base_y = pdf.GetY
249 base_y = pdf.GetY
250 max_height = row_height
250 max_height = row_height
251 col_values.each_with_index do |column, i|
251 col_values.each_with_index do |column, i|
252 col_x = pdf.GetX
252 col_x = pdf.GetX
253 if head == true
253 if head == true
254 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
254 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
255 else
255 else
256 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
256 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
257 end
257 end
258 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
258 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
259 pdf.SetXY(col_x + col_widths[i], base_y);
259 pdf.SetXY(col_x + col_widths[i], base_y);
260 end
260 end
261 return max_height
261 return max_height
262 end
262 end
263
263
264 # Draw lines to close the row (MultiCell border drawing in not uniform)
264 # Draw lines to close the row (MultiCell border drawing in not uniform)
265 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
265 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
266 id_width, col_widths)
266 id_width, col_widths)
267 col_x = top_x + id_width
267 col_x = top_x + id_width
268 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
268 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
269 col_widths.each do |width|
269 col_widths.each do |width|
270 col_x += width
270 col_x += width
271 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
271 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
272 end
272 end
273 pdf.Line(top_x, top_y, top_x, lower_y) # left border
273 pdf.Line(top_x, top_y, top_x, lower_y) # left border
274 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
274 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
275 end
275 end
276
276
277 # Returns a PDF string of a single issue
277 # Returns a PDF string of a single issue
278 def issue_to_pdf(issue)
278 def issue_to_pdf(issue)
279 pdf = ITCPDF.new(current_language)
279 pdf = ITCPDF.new(current_language)
280 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
280 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
281 pdf.alias_nb_pages
281 pdf.alias_nb_pages
282 pdf.footer_date = format_date(Date.today)
282 pdf.footer_date = format_date(Date.today)
283 pdf.AddPage
283 pdf.AddPage
284 pdf.SetFontStyle('B',11)
284 pdf.SetFontStyle('B',11)
285 pdf.RDMMultiCell(190,5,
285 pdf.RDMMultiCell(190,5,
286 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
286 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
287 pdf.Ln
287 pdf.Ln
288
288
289 pdf.SetFontStyle('B',9)
289 pdf.SetFontStyle('B',9)
290 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
290 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
291 pdf.SetFontStyle('',9)
291 pdf.SetFontStyle('',9)
292 pdf.RDMCell(60,5, issue.status.to_s,"RT")
292 pdf.RDMCell(60,5, issue.status.to_s,"RT")
293 pdf.SetFontStyle('B',9)
293 pdf.SetFontStyle('B',9)
294 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
294 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
295 pdf.SetFontStyle('',9)
295 pdf.SetFontStyle('',9)
296 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
296 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
297 pdf.Ln
297 pdf.Ln
298
298
299 pdf.SetFontStyle('B',9)
299 pdf.SetFontStyle('B',9)
300 pdf.RDMCell(35,5, l(:field_author) + ":","L")
300 pdf.RDMCell(35,5, l(:field_author) + ":","L")
301 pdf.SetFontStyle('',9)
301 pdf.SetFontStyle('',9)
302 pdf.RDMCell(60,5, issue.author.to_s,"R")
302 pdf.RDMCell(60,5, issue.author.to_s,"R")
303 pdf.SetFontStyle('B',9)
303 pdf.SetFontStyle('B',9)
304 pdf.RDMCell(35,5, l(:field_category) + ":","L")
304 pdf.RDMCell(35,5, l(:field_category) + ":","L")
305 pdf.SetFontStyle('',9)
305 pdf.SetFontStyle('',9)
306 pdf.RDMCell(60,5, issue.category.to_s,"R")
306 pdf.RDMCell(60,5, issue.category.to_s,"R")
307 pdf.Ln
307 pdf.Ln
308
308
309 pdf.SetFontStyle('B',9)
309 pdf.SetFontStyle('B',9)
310 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
310 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
311 pdf.SetFontStyle('',9)
311 pdf.SetFontStyle('',9)
312 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
312 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
313 pdf.SetFontStyle('B',9)
313 pdf.SetFontStyle('B',9)
314 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
314 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
315 pdf.SetFontStyle('',9)
315 pdf.SetFontStyle('',9)
316 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
316 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
317 pdf.Ln
317 pdf.Ln
318
318
319 pdf.SetFontStyle('B',9)
319 pdf.SetFontStyle('B',9)
320 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
320 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
321 pdf.SetFontStyle('',9)
321 pdf.SetFontStyle('',9)
322 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
322 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
323 pdf.SetFontStyle('B',9)
323 pdf.SetFontStyle('B',9)
324 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
324 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
325 pdf.SetFontStyle('',9)
325 pdf.SetFontStyle('',9)
326 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
326 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
327 pdf.Ln
327 pdf.Ln
328
328
329 for custom_value in issue.custom_field_values
329 for custom_value in issue.custom_field_values
330 pdf.SetFontStyle('B',9)
330 pdf.SetFontStyle('B',9)
331 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
331 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
332 pdf.SetFontStyle('',9)
332 pdf.SetFontStyle('',9)
333 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
333 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
334 end
334 end
335
335
336 y0 = pdf.GetY
336 y0 = pdf.GetY
337
337
338 pdf.SetFontStyle('B',9)
338 pdf.SetFontStyle('B',9)
339 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
339 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
340 pdf.SetFontStyle('',9)
340 pdf.SetFontStyle('',9)
341 pdf.RDMMultiCell(155,5, issue.subject,"RT")
341 pdf.RDMMultiCell(155,5, issue.subject,"RT")
342 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
342 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
343
343
344 pdf.SetFontStyle('B',9)
344 pdf.SetFontStyle('B',9)
345 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
345 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
346 pdf.SetFontStyle('',9)
346 pdf.SetFontStyle('',9)
347 pdf.RDMMultiCell(35+155, 5, issue.description.to_s, "LRB")
347 pdf.RDMMultiCell(35+155, 5, issue.description.to_s, "LRB")
348 pdf.Ln
348 pdf.Ln
349
349
350 if issue.changesets.any? &&
350 if issue.changesets.any? &&
351 User.current.allowed_to?(:view_changesets, issue.project)
351 User.current.allowed_to?(:view_changesets, issue.project)
352 pdf.SetFontStyle('B',9)
352 pdf.SetFontStyle('B',9)
353 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
353 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
354 pdf.Ln
354 pdf.Ln
355 for changeset in issue.changesets
355 for changeset in issue.changesets
356 pdf.SetFontStyle('B',8)
356 pdf.SetFontStyle('B',8)
357 pdf.RDMCell(190,5,
357 pdf.RDMCell(190,5,
358 format_time(changeset.committed_on) + " - " + changeset.author.to_s)
358 format_time(changeset.committed_on) + " - " + changeset.author.to_s)
359 pdf.Ln
359 pdf.Ln
360 unless changeset.comments.blank?
360 unless changeset.comments.blank?
361 pdf.SetFontStyle('',8)
361 pdf.SetFontStyle('',8)
362 pdf.RDMMultiCell(190,5, changeset.comments.to_s)
362 pdf.RDMMultiCell(190,5, changeset.comments.to_s)
363 end
363 end
364 pdf.Ln
364 pdf.Ln
365 end
365 end
366 end
366 end
367
367
368 pdf.SetFontStyle('B',9)
368 pdf.SetFontStyle('B',9)
369 pdf.RDMCell(190,5, l(:label_history), "B")
369 pdf.RDMCell(190,5, l(:label_history), "B")
370 pdf.Ln
370 pdf.Ln
371 for journal in issue.journals.find(
371 for journal in issue.journals.find(
372 :all, :include => [:user, :details],
372 :all, :include => [:user, :details],
373 :order => "#{Journal.table_name}.created_on ASC")
373 :order => "#{Journal.table_name}.created_on ASC")
374 pdf.SetFontStyle('B',8)
374 pdf.SetFontStyle('B',8)
375 pdf.RDMCell(190,5,
375 pdf.RDMCell(190,5,
376 format_time(journal.created_on) + " - " + journal.user.name)
376 format_time(journal.created_on) + " - " + journal.user.name)
377 pdf.Ln
377 pdf.Ln
378 pdf.SetFontStyle('I',8)
378 pdf.SetFontStyle('I',8)
379 for detail in journal.details
379 for detail in journal.details
380 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
380 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
381 end
381 end
382 if journal.notes?
382 if journal.notes?
383 pdf.Ln unless journal.details.empty?
383 pdf.Ln unless journal.details.empty?
384 pdf.SetFontStyle('',8)
384 pdf.SetFontStyle('',8)
385 pdf.RDMMultiCell(190,5, journal.notes.to_s)
385 pdf.RDMMultiCell(190,5, journal.notes.to_s)
386 end
386 end
387 pdf.Ln
387 pdf.Ln
388 end
388 end
389
389
390 if issue.attachments.any?
390 if issue.attachments.any?
391 pdf.SetFontStyle('B',9)
391 pdf.SetFontStyle('B',9)
392 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
392 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
393 pdf.Ln
393 pdf.Ln
394 for attachment in issue.attachments
394 for attachment in issue.attachments
395 pdf.SetFontStyle('',8)
395 pdf.SetFontStyle('',8)
396 pdf.RDMCell(80,5, attachment.filename)
396 pdf.RDMCell(80,5, attachment.filename)
397 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
397 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
398 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
398 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
399 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
399 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
400 pdf.Ln
400 pdf.Ln
401 end
401 end
402 end
402 end
403 pdf.Output
403 pdf.Output
404 end
404 end
405
405
406 class RDMPdfEncoding
406 class RDMPdfEncoding
407 include Redmine::I18n
407 include Redmine::I18n
408 def self.rdm_pdf_iconv(ic, txt)
408 def self.rdm_pdf_iconv(ic, txt)
409 txt ||= ''
409 txt ||= ''
410 if txt.respond_to?(:force_encoding)
410 if txt.respond_to?(:force_encoding)
411 txt.force_encoding('UTF-8')
411 txt.force_encoding('UTF-8')
412 if l(:general_pdf_encoding).upcase != 'UTF-8'
412 if l(:general_pdf_encoding).upcase != 'UTF-8'
413 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
413 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
414 :undef => :replace, :replace => '?')
414 :undef => :replace, :replace => '?')
415 else
415 else
416 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
416 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
417 end
417 end
418 txt.force_encoding('ASCII-8BIT')
418 txt.force_encoding('ASCII-8BIT')
419 elsif RUBY_PLATFORM == 'java'
419 elsif RUBY_PLATFORM == 'java'
420 begin
420 begin
421 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
421 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
422 txt = ic.iconv(txt)
422 txt = ic.iconv(txt)
423 rescue
423 rescue
424 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
424 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
425 end
425 end
426 else
426 else
427 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
427 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
428 txtar = ""
428 txtar = ""
429 begin
429 begin
430 txtar += ic.iconv(txt)
430 txtar += ic.iconv(txt)
431 rescue Iconv::IllegalSequence
431 rescue Iconv::IllegalSequence
432 txtar += $!.success
432 txtar += $!.success
433 txt = '?' + $!.failed[1,$!.failed.length]
433 txt = '?' + $!.failed[1,$!.failed.length]
434 retry
434 retry
435 rescue
435 rescue
436 txtar += $!.success
436 txtar += $!.success
437 end
437 end
438 txt = txtar
438 txt = txtar
439 end
439 end
440 txt
440 txt
441 end
441 end
442 end
442 end
443 end
443 end
444 end
444 end
445 end
445 end
General Comments 0
You need to be logged in to leave comments. Login now