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