##// END OF EJS Templates
PDF: add new "RDMwriteHTMLCell" method for textilized PDF (#69)....
Toshi MARUYAMA -
r6017:3a79ab74010f
parent child
Show More
@@ -1,441 +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)
119 writeHTMLCell(w, h, x, y, fix_text_encoding(html), border, ln, fill)
120 end
121
118 def Footer
122 def Footer
119 SetFont(@font_for_footer, 'I', 8)
123 SetFont(@font_for_footer, 'I', 8)
120 SetY(-15)
124 SetY(-15)
121 SetX(15)
125 SetX(15)
122 RDMCell(0, 5, @footer_date, 0, 0, 'L')
126 RDMCell(0, 5, @footer_date, 0, 0, 'L')
123 SetY(-15)
127 SetY(-15)
124 SetX(-30)
128 SetX(-30)
125 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
129 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
126 end
130 end
127 end
131 end
128
132
129 # Returns a PDF string of a list of issues
133 # Returns a PDF string of a list of issues
130 def issues_to_pdf(issues, project, query)
134 def issues_to_pdf(issues, project, query)
131 pdf = ITCPDF.new(current_language)
135 pdf = ITCPDF.new(current_language)
132 title = query.new_record? ? l(:label_issue_plural) : query.name
136 title = query.new_record? ? l(:label_issue_plural) : query.name
133 title = "#{project} - #{title}" if project
137 title = "#{project} - #{title}" if project
134 pdf.SetTitle(title)
138 pdf.SetTitle(title)
135 pdf.alias_nb_pages
139 pdf.alias_nb_pages
136 pdf.footer_date = format_date(Date.today)
140 pdf.footer_date = format_date(Date.today)
137 pdf.SetAutoPageBreak(false)
141 pdf.SetAutoPageBreak(false)
138 pdf.AddPage("L")
142 pdf.AddPage("L")
139
143
140 # Landscape A4 = 210 x 297 mm
144 # Landscape A4 = 210 x 297 mm
141 page_height = 210
145 page_height = 210
142 page_width = 297
146 page_width = 297
143 right_margin = 10
147 right_margin = 10
144 bottom_margin = 20
148 bottom_margin = 20
145 col_id_width = 10
149 col_id_width = 10
146 row_height = 5
150 row_height = 5
147
151
148 # column widths
152 # column widths
149 table_width = page_width - right_margin - 10 # fixed left margin
153 table_width = page_width - right_margin - 10 # fixed left margin
150 col_width = []
154 col_width = []
151 unless query.columns.empty?
155 unless query.columns.empty?
152 col_width = query.columns.collect do |c|
156 col_width = query.columns.collect do |c|
153 (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
154 end
158 end
155 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}
156 col_width = col_width.collect {|w| w * ratio}
160 col_width = col_width.collect {|w| w * ratio}
157 end
161 end
158
162
159 # title
163 # title
160 pdf.SetFontStyle('B',11)
164 pdf.SetFontStyle('B',11)
161 pdf.RDMCell(190,10, title)
165 pdf.RDMCell(190,10, title)
162 pdf.Ln
166 pdf.Ln
163
167
164 # headers
168 # headers
165 pdf.SetFontStyle('B',8)
169 pdf.SetFontStyle('B',8)
166 pdf.SetFillColor(230, 230, 230)
170 pdf.SetFillColor(230, 230, 230)
167
171
168 # render it background to find the max height used
172 # render it background to find the max height used
169 base_x = pdf.GetX
173 base_x = pdf.GetX
170 base_y = pdf.GetY
174 base_y = pdf.GetY
171 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)
172 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
176 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
173 pdf.SetXY(base_x, base_y);
177 pdf.SetXY(base_x, base_y);
174
178
175 # write the cells on page
179 # write the cells on page
176 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
180 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
177 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)
178 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)
179 pdf.SetY(base_y + max_height);
183 pdf.SetY(base_y + max_height);
180
184
181 # rows
185 # rows
182 pdf.SetFontStyle('',8)
186 pdf.SetFontStyle('',8)
183 pdf.SetFillColor(255, 255, 255)
187 pdf.SetFillColor(255, 255, 255)
184 previous_group = false
188 previous_group = false
185 issues.each do |issue|
189 issues.each do |issue|
186 if query.grouped? &&
190 if query.grouped? &&
187 (group = query.group_by_column.value(issue)) != previous_group
191 (group = query.group_by_column.value(issue)) != previous_group
188 pdf.SetFontStyle('B',9)
192 pdf.SetFontStyle('B',9)
189 pdf.RDMCell(277, row_height,
193 pdf.RDMCell(277, row_height,
190 (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]})",
191 1, 1, 'L')
195 1, 1, 'L')
192 pdf.SetFontStyle('',8)
196 pdf.SetFontStyle('',8)
193 previous_group = group
197 previous_group = group
194 end
198 end
195 # fetch all the row values
199 # fetch all the row values
196 col_values = query.columns.collect do |column|
200 col_values = query.columns.collect do |column|
197 s = if column.is_a?(QueryCustomFieldColumn)
201 s = if column.is_a?(QueryCustomFieldColumn)
198 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}
199 show_value(cv)
203 show_value(cv)
200 else
204 else
201 value = issue.send(column.name)
205 value = issue.send(column.name)
202 if value.is_a?(Date)
206 if value.is_a?(Date)
203 format_date(value)
207 format_date(value)
204 elsif value.is_a?(Time)
208 elsif value.is_a?(Time)
205 format_time(value)
209 format_time(value)
206 else
210 else
207 value
211 value
208 end
212 end
209 end
213 end
210 s.to_s
214 s.to_s
211 end
215 end
212
216
213 # render it off-page to find the max height used
217 # render it off-page to find the max height used
214 base_x = pdf.GetX
218 base_x = pdf.GetX
215 base_y = pdf.GetY
219 base_y = pdf.GetY
216 pdf.SetY(2 * page_height)
220 pdf.SetY(2 * page_height)
217 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)
218 pdf.SetXY(base_x, base_y)
222 pdf.SetXY(base_x, base_y)
219
223
220 # 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
221 space_left = page_height - base_y - bottom_margin
225 space_left = page_height - base_y - bottom_margin
222 if max_height > space_left
226 if max_height > space_left
223 pdf.AddPage("L")
227 pdf.AddPage("L")
224 base_x = pdf.GetX
228 base_x = pdf.GetX
225 base_y = pdf.GetY
229 base_y = pdf.GetY
226 end
230 end
227
231
228 # write the cells on page
232 # write the cells on page
229 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)
230 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)
231 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)
232 pdf.SetY(base_y + max_height);
236 pdf.SetY(base_y + max_height);
233 end
237 end
234
238
235 if issues.size == Setting.issues_export_limit.to_i
239 if issues.size == Setting.issues_export_limit.to_i
236 pdf.SetFontStyle('B',10)
240 pdf.SetFontStyle('B',10)
237 pdf.RDMCell(0, row_height, '...')
241 pdf.RDMCell(0, row_height, '...')
238 end
242 end
239 pdf.Output
243 pdf.Output
240 end
244 end
241
245
242 # Renders MultiCells and returns the maximum height used
246 # Renders MultiCells and returns the maximum height used
243 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
247 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
244 row_height, head=false)
248 row_height, head=false)
245 base_y = pdf.GetY
249 base_y = pdf.GetY
246 max_height = row_height
250 max_height = row_height
247 col_values.each_with_index do |column, i|
251 col_values.each_with_index do |column, i|
248 col_x = pdf.GetX
252 col_x = pdf.GetX
249 if head == true
253 if head == true
250 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)
251 else
255 else
252 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
256 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
253 end
257 end
254 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
255 pdf.SetXY(col_x + col_widths[i], base_y);
259 pdf.SetXY(col_x + col_widths[i], base_y);
256 end
260 end
257 return max_height
261 return max_height
258 end
262 end
259
263
260 # 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)
261 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,
262 id_width, col_widths)
266 id_width, col_widths)
263 col_x = top_x + id_width
267 col_x = top_x + id_width
264 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
265 col_widths.each do |width|
269 col_widths.each do |width|
266 col_x += width
270 col_x += width
267 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
268 end
272 end
269 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
270 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
271 end
275 end
272
276
273 # Returns a PDF string of a single issue
277 # Returns a PDF string of a single issue
274 def issue_to_pdf(issue)
278 def issue_to_pdf(issue)
275 pdf = ITCPDF.new(current_language)
279 pdf = ITCPDF.new(current_language)
276 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
280 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
277 pdf.alias_nb_pages
281 pdf.alias_nb_pages
278 pdf.footer_date = format_date(Date.today)
282 pdf.footer_date = format_date(Date.today)
279 pdf.AddPage
283 pdf.AddPage
280 pdf.SetFontStyle('B',11)
284 pdf.SetFontStyle('B',11)
281 pdf.RDMMultiCell(190,5,
285 pdf.RDMMultiCell(190,5,
282 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
286 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
283 pdf.Ln
287 pdf.Ln
284
288
285 pdf.SetFontStyle('B',9)
289 pdf.SetFontStyle('B',9)
286 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
290 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
287 pdf.SetFontStyle('',9)
291 pdf.SetFontStyle('',9)
288 pdf.RDMCell(60,5, issue.status.to_s,"RT")
292 pdf.RDMCell(60,5, issue.status.to_s,"RT")
289 pdf.SetFontStyle('B',9)
293 pdf.SetFontStyle('B',9)
290 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
294 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
291 pdf.SetFontStyle('',9)
295 pdf.SetFontStyle('',9)
292 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
296 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
293 pdf.Ln
297 pdf.Ln
294
298
295 pdf.SetFontStyle('B',9)
299 pdf.SetFontStyle('B',9)
296 pdf.RDMCell(35,5, l(:field_author) + ":","L")
300 pdf.RDMCell(35,5, l(:field_author) + ":","L")
297 pdf.SetFontStyle('',9)
301 pdf.SetFontStyle('',9)
298 pdf.RDMCell(60,5, issue.author.to_s,"R")
302 pdf.RDMCell(60,5, issue.author.to_s,"R")
299 pdf.SetFontStyle('B',9)
303 pdf.SetFontStyle('B',9)
300 pdf.RDMCell(35,5, l(:field_category) + ":","L")
304 pdf.RDMCell(35,5, l(:field_category) + ":","L")
301 pdf.SetFontStyle('',9)
305 pdf.SetFontStyle('',9)
302 pdf.RDMCell(60,5, issue.category.to_s,"R")
306 pdf.RDMCell(60,5, issue.category.to_s,"R")
303 pdf.Ln
307 pdf.Ln
304
308
305 pdf.SetFontStyle('B',9)
309 pdf.SetFontStyle('B',9)
306 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
310 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
307 pdf.SetFontStyle('',9)
311 pdf.SetFontStyle('',9)
308 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
312 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
309 pdf.SetFontStyle('B',9)
313 pdf.SetFontStyle('B',9)
310 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
314 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
311 pdf.SetFontStyle('',9)
315 pdf.SetFontStyle('',9)
312 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
316 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
313 pdf.Ln
317 pdf.Ln
314
318
315 pdf.SetFontStyle('B',9)
319 pdf.SetFontStyle('B',9)
316 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
320 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
317 pdf.SetFontStyle('',9)
321 pdf.SetFontStyle('',9)
318 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
322 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
319 pdf.SetFontStyle('B',9)
323 pdf.SetFontStyle('B',9)
320 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
324 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
321 pdf.SetFontStyle('',9)
325 pdf.SetFontStyle('',9)
322 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
326 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
323 pdf.Ln
327 pdf.Ln
324
328
325 for custom_value in issue.custom_field_values
329 for custom_value in issue.custom_field_values
326 pdf.SetFontStyle('B',9)
330 pdf.SetFontStyle('B',9)
327 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
331 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
328 pdf.SetFontStyle('',9)
332 pdf.SetFontStyle('',9)
329 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
333 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
330 end
334 end
331
335
332 y0 = pdf.GetY
336 y0 = pdf.GetY
333
337
334 pdf.SetFontStyle('B',9)
338 pdf.SetFontStyle('B',9)
335 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
339 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
336 pdf.SetFontStyle('',9)
340 pdf.SetFontStyle('',9)
337 pdf.RDMMultiCell(155,5, issue.subject,"RT")
341 pdf.RDMMultiCell(155,5, issue.subject,"RT")
338 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
342 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
339
343
340 pdf.SetFontStyle('B',9)
344 pdf.SetFontStyle('B',9)
341 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
345 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
342 pdf.SetFontStyle('',9)
346 pdf.SetFontStyle('',9)
343 pdf.RDMMultiCell(35+155, 5, issue.description.to_s, "LRB")
347 pdf.RDMMultiCell(35+155, 5, issue.description.to_s, "LRB")
344 pdf.Ln
348 pdf.Ln
345
349
346 if issue.changesets.any? &&
350 if issue.changesets.any? &&
347 User.current.allowed_to?(:view_changesets, issue.project)
351 User.current.allowed_to?(:view_changesets, issue.project)
348 pdf.SetFontStyle('B',9)
352 pdf.SetFontStyle('B',9)
349 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
353 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
350 pdf.Ln
354 pdf.Ln
351 for changeset in issue.changesets
355 for changeset in issue.changesets
352 pdf.SetFontStyle('B',8)
356 pdf.SetFontStyle('B',8)
353 pdf.RDMCell(190,5,
357 pdf.RDMCell(190,5,
354 format_time(changeset.committed_on) + " - " + changeset.author.to_s)
358 format_time(changeset.committed_on) + " - " + changeset.author.to_s)
355 pdf.Ln
359 pdf.Ln
356 unless changeset.comments.blank?
360 unless changeset.comments.blank?
357 pdf.SetFontStyle('',8)
361 pdf.SetFontStyle('',8)
358 pdf.RDMMultiCell(190,5, changeset.comments.to_s)
362 pdf.RDMMultiCell(190,5, changeset.comments.to_s)
359 end
363 end
360 pdf.Ln
364 pdf.Ln
361 end
365 end
362 end
366 end
363
367
364 pdf.SetFontStyle('B',9)
368 pdf.SetFontStyle('B',9)
365 pdf.RDMCell(190,5, l(:label_history), "B")
369 pdf.RDMCell(190,5, l(:label_history), "B")
366 pdf.Ln
370 pdf.Ln
367 for journal in issue.journals.find(
371 for journal in issue.journals.find(
368 :all, :include => [:user, :details],
372 :all, :include => [:user, :details],
369 :order => "#{Journal.table_name}.created_on ASC")
373 :order => "#{Journal.table_name}.created_on ASC")
370 pdf.SetFontStyle('B',8)
374 pdf.SetFontStyle('B',8)
371 pdf.RDMCell(190,5,
375 pdf.RDMCell(190,5,
372 format_time(journal.created_on) + " - " + journal.user.name)
376 format_time(journal.created_on) + " - " + journal.user.name)
373 pdf.Ln
377 pdf.Ln
374 pdf.SetFontStyle('I',8)
378 pdf.SetFontStyle('I',8)
375 for detail in journal.details
379 for detail in journal.details
376 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
380 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
377 end
381 end
378 if journal.notes?
382 if journal.notes?
379 pdf.Ln unless journal.details.empty?
383 pdf.Ln unless journal.details.empty?
380 pdf.SetFontStyle('',8)
384 pdf.SetFontStyle('',8)
381 pdf.RDMMultiCell(190,5, journal.notes.to_s)
385 pdf.RDMMultiCell(190,5, journal.notes.to_s)
382 end
386 end
383 pdf.Ln
387 pdf.Ln
384 end
388 end
385
389
386 if issue.attachments.any?
390 if issue.attachments.any?
387 pdf.SetFontStyle('B',9)
391 pdf.SetFontStyle('B',9)
388 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
392 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
389 pdf.Ln
393 pdf.Ln
390 for attachment in issue.attachments
394 for attachment in issue.attachments
391 pdf.SetFontStyle('',8)
395 pdf.SetFontStyle('',8)
392 pdf.RDMCell(80,5, attachment.filename)
396 pdf.RDMCell(80,5, attachment.filename)
393 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")
394 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")
395 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
399 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
396 pdf.Ln
400 pdf.Ln
397 end
401 end
398 end
402 end
399 pdf.Output
403 pdf.Output
400 end
404 end
401
405
402 class RDMPdfEncoding
406 class RDMPdfEncoding
403 include Redmine::I18n
407 include Redmine::I18n
404 def self.rdm_pdf_iconv(ic, txt)
408 def self.rdm_pdf_iconv(ic, txt)
405 txt ||= ''
409 txt ||= ''
406 if txt.respond_to?(:force_encoding)
410 if txt.respond_to?(:force_encoding)
407 txt.force_encoding('UTF-8')
411 txt.force_encoding('UTF-8')
408 if l(:general_pdf_encoding).upcase != 'UTF-8'
412 if l(:general_pdf_encoding).upcase != 'UTF-8'
409 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
413 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
410 :undef => :replace, :replace => '?')
414 :undef => :replace, :replace => '?')
411 else
415 else
412 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
416 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
413 end
417 end
414 txt.force_encoding('ASCII-8BIT')
418 txt.force_encoding('ASCII-8BIT')
415 elsif RUBY_PLATFORM == 'java'
419 elsif RUBY_PLATFORM == 'java'
416 begin
420 begin
417 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
421 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
418 txt = ic.iconv(txt)
422 txt = ic.iconv(txt)
419 rescue
423 rescue
420 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
424 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
421 end
425 end
422 else
426 else
423 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
427 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
424 txtar = ""
428 txtar = ""
425 begin
429 begin
426 txtar += ic.iconv(txt)
430 txtar += ic.iconv(txt)
427 rescue Iconv::IllegalSequence
431 rescue Iconv::IllegalSequence
428 txtar += $!.success
432 txtar += $!.success
429 txt = '?' + $!.failed[1,$!.failed.length]
433 txt = '?' + $!.failed[1,$!.failed.length]
430 retry
434 retry
431 rescue
435 rescue
432 txtar += $!.success
436 txtar += $!.success
433 end
437 end
434 txt = txtar
438 txt = txtar
435 end
439 end
436 txt
440 txt
437 end
441 end
438 end
442 end
439 end
443 end
440 end
444 end
441 end
445 end
General Comments 0
You need to be logged in to leave comments. Login now