##// END OF EJS Templates
Fix for ruby1.9.3....
Jean-Philippe Lang -
r8616:7409963c9a69
parent child
Show More
@@ -1,670 +1,670
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 'fpdf/chinese'
21 require 'fpdf/chinese'
22 require 'fpdf/japanese'
22 require 'fpdf/japanese'
23 require 'fpdf/korean'
23 require 'fpdf/korean'
24 require 'core/rmagick'
24 require 'core/rmagick'
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 include IssuesHelper
31 include IssuesHelper
32
32
33 class ITCPDF < TCPDF
33 class ITCPDF < TCPDF
34 include Redmine::I18n
34 include Redmine::I18n
35 attr_accessor :footer_date
35 attr_accessor :footer_date
36
36
37 def initialize(lang)
37 def initialize(lang)
38 @@k_path_cache = Rails.root.join('tmp', 'pdf')
38 @@k_path_cache = Rails.root.join('tmp', 'pdf')
39 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
39 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
40 set_language_if_valid lang
40 set_language_if_valid lang
41 pdf_encoding = l(:general_pdf_encoding).upcase
41 pdf_encoding = l(:general_pdf_encoding).upcase
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 @outlines = []
79 @outlines = []
80 @outlineRoot = nil
80 @outlineRoot = nil
81 end
81 end
82
82
83 def SetFontStyle(style, size)
83 def SetFontStyle(style, size)
84 SetFont(@font_for_content, style, size)
84 SetFont(@font_for_content, style, size)
85 end
85 end
86
86
87 def SetTitle(txt)
87 def SetTitle(txt)
88 txt = begin
88 txt = begin
89 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
89 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
90 hextxt = "<FEFF" # FEFF is BOM
90 hextxt = "<FEFF" # FEFF is BOM
91 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
91 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
92 hextxt << ">"
92 hextxt << ">"
93 rescue
93 rescue
94 txt
94 txt
95 end || ''
95 end || ''
96 super(txt)
96 super(txt)
97 end
97 end
98
98
99 def textstring(s)
99 def textstring(s)
100 # Format a text string
100 # Format a text string
101 if s =~ /^</ # This means the string is hex-dumped.
101 if s.chars.first == '<' # This means the string is hex-dumped.
102 return s
102 return s
103 else
103 else
104 return '('+escape(s)+')'
104 return '('+escape(s)+')'
105 end
105 end
106 end
106 end
107
107
108 def fix_text_encoding(txt)
108 def fix_text_encoding(txt)
109 RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
109 RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
110 end
110 end
111
111
112 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
112 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
113 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
113 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
114 end
114 end
115
115
116 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
116 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
117 MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
117 MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
118 end
118 end
119
119
120 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
120 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
121 @attachments = attachments
121 @attachments = attachments
122 writeHTMLCell(w, h, x, y,
122 writeHTMLCell(w, h, x, y,
123 fix_text_encoding(
123 fix_text_encoding(
124 Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
124 Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
125 border, ln, fill)
125 border, ln, fill)
126 end
126 end
127
127
128 def getImageFilename(attrname)
128 def getImageFilename(attrname)
129 # attrname: general_pdf_encoding string file/uri name
129 # attrname: general_pdf_encoding string file/uri name
130 atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
130 atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
131 if atta
131 if atta
132 return atta.diskfile
132 return atta.diskfile
133 else
133 else
134 return nil
134 return nil
135 end
135 end
136 end
136 end
137
137
138 def Footer
138 def Footer
139 SetFont(@font_for_footer, 'I', 8)
139 SetFont(@font_for_footer, 'I', 8)
140 SetY(-15)
140 SetY(-15)
141 SetX(15)
141 SetX(15)
142 RDMCell(0, 5, @footer_date, 0, 0, 'L')
142 RDMCell(0, 5, @footer_date, 0, 0, 'L')
143 SetY(-15)
143 SetY(-15)
144 SetX(-30)
144 SetX(-30)
145 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
145 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
146 end
146 end
147
147
148 def Bookmark(txt, level=0, y=0)
148 def Bookmark(txt, level=0, y=0)
149 utf16 = Iconv.conv('UTF-16', 'UTF-8', txt)
149 utf16 = Iconv.conv('UTF-16', 'UTF-8', txt)
150 if (y == -1)
150 if (y == -1)
151 y = GetY()
151 y = GetY()
152 end
152 end
153 @outlines << {:t => utf16, :l => level, :p => PageNo(), :y => (@h - y)*@k}
153 @outlines << {:t => utf16, :l => level, :p => PageNo(), :y => (@h - y)*@k}
154 end
154 end
155
155
156 def putbookmarks
156 def putbookmarks
157 nb=@outlines.size
157 nb=@outlines.size
158 return if (nb==0)
158 return if (nb==0)
159 lru=[]
159 lru=[]
160 level=0
160 level=0
161 @outlines.each_with_index do |o, i|
161 @outlines.each_with_index do |o, i|
162 if(o[:l]>0)
162 if(o[:l]>0)
163 parent=lru[o[:l]-1]
163 parent=lru[o[:l]-1]
164 #Set parent and last pointers
164 #Set parent and last pointers
165 @outlines[i][:parent]=parent
165 @outlines[i][:parent]=parent
166 @outlines[parent][:last]=i
166 @outlines[parent][:last]=i
167 if (o[:l]>level)
167 if (o[:l]>level)
168 #Level increasing: set first pointer
168 #Level increasing: set first pointer
169 @outlines[parent][:first]=i
169 @outlines[parent][:first]=i
170 end
170 end
171 else
171 else
172 @outlines[i][:parent]=nb
172 @outlines[i][:parent]=nb
173 end
173 end
174 if (o[:l]<=level && i>0)
174 if (o[:l]<=level && i>0)
175 #Set prev and next pointers
175 #Set prev and next pointers
176 prev=lru[o[:l]]
176 prev=lru[o[:l]]
177 @outlines[prev][:next]=i
177 @outlines[prev][:next]=i
178 @outlines[i][:prev]=prev
178 @outlines[i][:prev]=prev
179 end
179 end
180 lru[o[:l]]=i
180 lru[o[:l]]=i
181 level=o[:l]
181 level=o[:l]
182 end
182 end
183 #Outline items
183 #Outline items
184 n=self.n+1
184 n=self.n+1
185 @outlines.each_with_index do |o, i|
185 @outlines.each_with_index do |o, i|
186 newobj()
186 newobj()
187 out('<</Title '+textstring(o[:t]))
187 out('<</Title '+textstring(o[:t]))
188 out("/Parent #{n+o[:parent]} 0 R")
188 out("/Parent #{n+o[:parent]} 0 R")
189 if (o[:prev])
189 if (o[:prev])
190 out("/Prev #{n+o[:prev]} 0 R")
190 out("/Prev #{n+o[:prev]} 0 R")
191 end
191 end
192 if (o[:next])
192 if (o[:next])
193 out("/Next #{n+o[:next]} 0 R")
193 out("/Next #{n+o[:next]} 0 R")
194 end
194 end
195 if (o[:first])
195 if (o[:first])
196 out("/First #{n+o[:first]} 0 R")
196 out("/First #{n+o[:first]} 0 R")
197 end
197 end
198 if (o[:last])
198 if (o[:last])
199 out("/Last #{n+o[:last]} 0 R")
199 out("/Last #{n+o[:last]} 0 R")
200 end
200 end
201 out("/Dest [%d 0 R /XYZ 0 %.2f null]" % [1+2*o[:p], o[:y]])
201 out("/Dest [%d 0 R /XYZ 0 %.2f null]" % [1+2*o[:p], o[:y]])
202 out('/Count 0>>')
202 out('/Count 0>>')
203 out('endobj')
203 out('endobj')
204 end
204 end
205 #Outline root
205 #Outline root
206 newobj()
206 newobj()
207 @outlineRoot=self.n
207 @outlineRoot=self.n
208 out("<</Type /Outlines /First #{n} 0 R");
208 out("<</Type /Outlines /First #{n} 0 R");
209 out("/Last #{n+lru[0]} 0 R>>");
209 out("/Last #{n+lru[0]} 0 R>>");
210 out('endobj');
210 out('endobj');
211 end
211 end
212
212
213 def putresources()
213 def putresources()
214 super
214 super
215 putbookmarks()
215 putbookmarks()
216 end
216 end
217
217
218 def putcatalog()
218 def putcatalog()
219 super
219 super
220 if(@outlines.size > 0)
220 if(@outlines.size > 0)
221 out("/Outlines #{@outlineRoot} 0 R");
221 out("/Outlines #{@outlineRoot} 0 R");
222 out('/PageMode /UseOutlines');
222 out('/PageMode /UseOutlines');
223 end
223 end
224 end
224 end
225 end
225 end
226
226
227 # Returns a PDF string of a list of issues
227 # Returns a PDF string of a list of issues
228 def issues_to_pdf(issues, project, query)
228 def issues_to_pdf(issues, project, query)
229 pdf = ITCPDF.new(current_language)
229 pdf = ITCPDF.new(current_language)
230 title = query.new_record? ? l(:label_issue_plural) : query.name
230 title = query.new_record? ? l(:label_issue_plural) : query.name
231 title = "#{project} - #{title}" if project
231 title = "#{project} - #{title}" if project
232 pdf.SetTitle(title)
232 pdf.SetTitle(title)
233 pdf.alias_nb_pages
233 pdf.alias_nb_pages
234 pdf.footer_date = format_date(Date.today)
234 pdf.footer_date = format_date(Date.today)
235 pdf.SetAutoPageBreak(false)
235 pdf.SetAutoPageBreak(false)
236 pdf.AddPage("L")
236 pdf.AddPage("L")
237
237
238 # Landscape A4 = 210 x 297 mm
238 # Landscape A4 = 210 x 297 mm
239 page_height = 210
239 page_height = 210
240 page_width = 297
240 page_width = 297
241 right_margin = 10
241 right_margin = 10
242 bottom_margin = 20
242 bottom_margin = 20
243 col_id_width = 10
243 col_id_width = 10
244 row_height = 5
244 row_height = 5
245
245
246 # column widths
246 # column widths
247 table_width = page_width - right_margin - 10 # fixed left margin
247 table_width = page_width - right_margin - 10 # fixed left margin
248 col_width = []
248 col_width = []
249 unless query.columns.empty?
249 unless query.columns.empty?
250 col_width = query.columns.collect do |c|
250 col_width = query.columns.collect do |c|
251 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
251 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
252 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
252 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
253 end
253 end
254 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
254 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
255 col_width = col_width.collect {|w| w * ratio}
255 col_width = col_width.collect {|w| w * ratio}
256 end
256 end
257
257
258 # title
258 # title
259 pdf.SetFontStyle('B',11)
259 pdf.SetFontStyle('B',11)
260 pdf.RDMCell(190,10, title)
260 pdf.RDMCell(190,10, title)
261 pdf.Ln
261 pdf.Ln
262
262
263 # headers
263 # headers
264 pdf.SetFontStyle('B',8)
264 pdf.SetFontStyle('B',8)
265 pdf.SetFillColor(230, 230, 230)
265 pdf.SetFillColor(230, 230, 230)
266
266
267 # render it background to find the max height used
267 # render it background to find the max height used
268 base_x = pdf.GetX
268 base_x = pdf.GetX
269 base_y = pdf.GetY
269 base_y = pdf.GetY
270 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
270 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
271 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
271 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
272 pdf.SetXY(base_x, base_y);
272 pdf.SetXY(base_x, base_y);
273
273
274 # write the cells on page
274 # write the cells on page
275 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
275 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
276 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
276 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
277 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
277 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
278 pdf.SetY(base_y + max_height);
278 pdf.SetY(base_y + max_height);
279
279
280 # rows
280 # rows
281 pdf.SetFontStyle('',8)
281 pdf.SetFontStyle('',8)
282 pdf.SetFillColor(255, 255, 255)
282 pdf.SetFillColor(255, 255, 255)
283 previous_group = false
283 previous_group = false
284 issue_list(issues) do |issue, level|
284 issue_list(issues) do |issue, level|
285 if query.grouped? &&
285 if query.grouped? &&
286 (group = query.group_by_column.value(issue)) != previous_group
286 (group = query.group_by_column.value(issue)) != previous_group
287 pdf.SetFontStyle('B',9)
287 pdf.SetFontStyle('B',9)
288 group_label = group.blank? ? 'None' : group.to_s
288 group_label = group.blank? ? 'None' : group.to_s
289 group_label << " (#{query.issue_count_by_group[group]})"
289 group_label << " (#{query.issue_count_by_group[group]})"
290 pdf.Bookmark group_label, 0, -1
290 pdf.Bookmark group_label, 0, -1
291 pdf.RDMCell(277, row_height, group_label, 1, 1, 'L')
291 pdf.RDMCell(277, row_height, group_label, 1, 1, 'L')
292 pdf.SetFontStyle('',8)
292 pdf.SetFontStyle('',8)
293 previous_group = group
293 previous_group = group
294 end
294 end
295 # fetch all the row values
295 # fetch all the row values
296 col_values = query.columns.collect do |column|
296 col_values = query.columns.collect do |column|
297 s = if column.is_a?(QueryCustomFieldColumn)
297 s = if column.is_a?(QueryCustomFieldColumn)
298 cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
298 cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
299 show_value(cv)
299 show_value(cv)
300 else
300 else
301 value = issue.send(column.name)
301 value = issue.send(column.name)
302 if column.name == :subject
302 if column.name == :subject
303 value = " " * level + value
303 value = " " * level + value
304 end
304 end
305 if value.is_a?(Date)
305 if value.is_a?(Date)
306 format_date(value)
306 format_date(value)
307 elsif value.is_a?(Time)
307 elsif value.is_a?(Time)
308 format_time(value)
308 format_time(value)
309 else
309 else
310 value
310 value
311 end
311 end
312 end
312 end
313 s.to_s
313 s.to_s
314 end
314 end
315
315
316 # render it off-page to find the max height used
316 # render it off-page to find the max height used
317 base_x = pdf.GetX
317 base_x = pdf.GetX
318 base_y = pdf.GetY
318 base_y = pdf.GetY
319 pdf.SetY(2 * page_height)
319 pdf.SetY(2 * page_height)
320 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
320 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
321 pdf.SetXY(base_x, base_y)
321 pdf.SetXY(base_x, base_y)
322
322
323 # make new page if it doesn't fit on the current one
323 # make new page if it doesn't fit on the current one
324 space_left = page_height - base_y - bottom_margin
324 space_left = page_height - base_y - bottom_margin
325 if max_height > space_left
325 if max_height > space_left
326 pdf.AddPage("L")
326 pdf.AddPage("L")
327 base_x = pdf.GetX
327 base_x = pdf.GetX
328 base_y = pdf.GetY
328 base_y = pdf.GetY
329 end
329 end
330
330
331 # write the cells on page
331 # write the cells on page
332 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
332 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
333 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
333 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
334 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
334 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
335 pdf.SetY(base_y + max_height);
335 pdf.SetY(base_y + max_height);
336 end
336 end
337
337
338 if issues.size == Setting.issues_export_limit.to_i
338 if issues.size == Setting.issues_export_limit.to_i
339 pdf.SetFontStyle('B',10)
339 pdf.SetFontStyle('B',10)
340 pdf.RDMCell(0, row_height, '...')
340 pdf.RDMCell(0, row_height, '...')
341 end
341 end
342 pdf.Output
342 pdf.Output
343 end
343 end
344
344
345 # Renders MultiCells and returns the maximum height used
345 # Renders MultiCells and returns the maximum height used
346 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
346 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
347 row_height, head=false)
347 row_height, head=false)
348 base_y = pdf.GetY
348 base_y = pdf.GetY
349 max_height = row_height
349 max_height = row_height
350 col_values.each_with_index do |column, i|
350 col_values.each_with_index do |column, i|
351 col_x = pdf.GetX
351 col_x = pdf.GetX
352 if head == true
352 if head == true
353 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
353 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
354 else
354 else
355 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
355 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
356 end
356 end
357 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
357 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
358 pdf.SetXY(col_x + col_widths[i], base_y);
358 pdf.SetXY(col_x + col_widths[i], base_y);
359 end
359 end
360 return max_height
360 return max_height
361 end
361 end
362
362
363 # Draw lines to close the row (MultiCell border drawing in not uniform)
363 # Draw lines to close the row (MultiCell border drawing in not uniform)
364 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
364 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
365 id_width, col_widths)
365 id_width, col_widths)
366 col_x = top_x + id_width
366 col_x = top_x + id_width
367 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
367 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
368 col_widths.each do |width|
368 col_widths.each do |width|
369 col_x += width
369 col_x += width
370 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
370 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
371 end
371 end
372 pdf.Line(top_x, top_y, top_x, lower_y) # left border
372 pdf.Line(top_x, top_y, top_x, lower_y) # left border
373 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
373 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
374 end
374 end
375
375
376 # Returns a PDF string of a single issue
376 # Returns a PDF string of a single issue
377 def issue_to_pdf(issue)
377 def issue_to_pdf(issue)
378 pdf = ITCPDF.new(current_language)
378 pdf = ITCPDF.new(current_language)
379 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
379 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
380 pdf.alias_nb_pages
380 pdf.alias_nb_pages
381 pdf.footer_date = format_date(Date.today)
381 pdf.footer_date = format_date(Date.today)
382 pdf.AddPage
382 pdf.AddPage
383 pdf.SetFontStyle('B',11)
383 pdf.SetFontStyle('B',11)
384 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
384 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
385 pdf.RDMMultiCell(190, 5, buf)
385 pdf.RDMMultiCell(190, 5, buf)
386 pdf.Ln
386 pdf.Ln
387 pdf.SetFontStyle('',8)
387 pdf.SetFontStyle('',8)
388 base_x = pdf.GetX
388 base_x = pdf.GetX
389 i = 1
389 i = 1
390 issue.ancestors.each do |ancestor|
390 issue.ancestors.each do |ancestor|
391 pdf.SetX(base_x + i)
391 pdf.SetX(base_x + i)
392 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
392 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
393 pdf.RDMMultiCell(190 - i, 5, buf)
393 pdf.RDMMultiCell(190 - i, 5, buf)
394 i += 1 if i < 35
394 i += 1 if i < 35
395 end
395 end
396 pdf.Ln
396 pdf.Ln
397
397
398 pdf.SetFontStyle('B',9)
398 pdf.SetFontStyle('B',9)
399 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
399 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
400 pdf.SetFontStyle('',9)
400 pdf.SetFontStyle('',9)
401 pdf.RDMCell(60,5, issue.status.to_s,"RT")
401 pdf.RDMCell(60,5, issue.status.to_s,"RT")
402 pdf.SetFontStyle('B',9)
402 pdf.SetFontStyle('B',9)
403 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
403 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
404 pdf.SetFontStyle('',9)
404 pdf.SetFontStyle('',9)
405 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
405 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
406 pdf.Ln
406 pdf.Ln
407
407
408 pdf.SetFontStyle('B',9)
408 pdf.SetFontStyle('B',9)
409 pdf.RDMCell(35,5, l(:field_author) + ":","L")
409 pdf.RDMCell(35,5, l(:field_author) + ":","L")
410 pdf.SetFontStyle('',9)
410 pdf.SetFontStyle('',9)
411 pdf.RDMCell(60,5, issue.author.to_s,"R")
411 pdf.RDMCell(60,5, issue.author.to_s,"R")
412 pdf.SetFontStyle('B',9)
412 pdf.SetFontStyle('B',9)
413 pdf.RDMCell(35,5, l(:field_category) + ":","L")
413 pdf.RDMCell(35,5, l(:field_category) + ":","L")
414 pdf.SetFontStyle('',9)
414 pdf.SetFontStyle('',9)
415 pdf.RDMCell(60,5, issue.category.to_s,"R")
415 pdf.RDMCell(60,5, issue.category.to_s,"R")
416 pdf.Ln
416 pdf.Ln
417
417
418 pdf.SetFontStyle('B',9)
418 pdf.SetFontStyle('B',9)
419 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
419 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
420 pdf.SetFontStyle('',9)
420 pdf.SetFontStyle('',9)
421 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
421 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
422 pdf.SetFontStyle('B',9)
422 pdf.SetFontStyle('B',9)
423 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
423 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
424 pdf.SetFontStyle('',9)
424 pdf.SetFontStyle('',9)
425 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
425 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
426 pdf.Ln
426 pdf.Ln
427
427
428 pdf.SetFontStyle('B',9)
428 pdf.SetFontStyle('B',9)
429 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
429 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
430 pdf.SetFontStyle('',9)
430 pdf.SetFontStyle('',9)
431 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
431 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
432 pdf.SetFontStyle('B',9)
432 pdf.SetFontStyle('B',9)
433 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
433 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
434 pdf.SetFontStyle('',9)
434 pdf.SetFontStyle('',9)
435 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
435 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
436 pdf.Ln
436 pdf.Ln
437
437
438 for custom_value in issue.custom_field_values
438 for custom_value in issue.custom_field_values
439 pdf.SetFontStyle('B',9)
439 pdf.SetFontStyle('B',9)
440 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
440 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
441 pdf.SetFontStyle('',9)
441 pdf.SetFontStyle('',9)
442 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
442 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
443 end
443 end
444
444
445 y0 = pdf.GetY
445 y0 = pdf.GetY
446
446
447 pdf.SetFontStyle('B',9)
447 pdf.SetFontStyle('B',9)
448 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
448 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
449 pdf.SetFontStyle('',9)
449 pdf.SetFontStyle('',9)
450 pdf.RDMMultiCell(155,5, issue.subject,"RT")
450 pdf.RDMMultiCell(155,5, issue.subject,"RT")
451 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
451 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
452
452
453 pdf.SetFontStyle('B',9)
453 pdf.SetFontStyle('B',9)
454 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
454 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
455 pdf.SetFontStyle('',9)
455 pdf.SetFontStyle('',9)
456
456
457 # Set resize image scale
457 # Set resize image scale
458 pdf.SetImageScale(1.6)
458 pdf.SetImageScale(1.6)
459 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
459 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
460 issue.description.to_s, issue.attachments, "LRB")
460 issue.description.to_s, issue.attachments, "LRB")
461
461
462 unless issue.leaf?
462 unless issue.leaf?
463 # for CJK
463 # for CJK
464 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
464 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
465
465
466 pdf.SetFontStyle('B',9)
466 pdf.SetFontStyle('B',9)
467 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
467 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
468 pdf.Ln
468 pdf.Ln
469 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
469 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
470 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
470 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
471 :length => truncate_length)
471 :length => truncate_length)
472 level = 10 if level >= 10
472 level = 10 if level >= 10
473 pdf.SetFontStyle('',8)
473 pdf.SetFontStyle('',8)
474 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
474 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
475 pdf.SetFontStyle('B',8)
475 pdf.SetFontStyle('B',8)
476 pdf.RDMCell(20,5, child.status.to_s, "R")
476 pdf.RDMCell(20,5, child.status.to_s, "R")
477 pdf.Ln
477 pdf.Ln
478 end
478 end
479 end
479 end
480
480
481 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
481 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
482 unless relations.empty?
482 unless relations.empty?
483 # for CJK
483 # for CJK
484 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
484 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
485
485
486 pdf.SetFontStyle('B',9)
486 pdf.SetFontStyle('B',9)
487 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
487 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
488 pdf.Ln
488 pdf.Ln
489 relations.each do |relation|
489 relations.each do |relation|
490 buf = ""
490 buf = ""
491 buf += "#{l(relation.label_for(issue))} "
491 buf += "#{l(relation.label_for(issue))} "
492 if relation.delay && relation.delay != 0
492 if relation.delay && relation.delay != 0
493 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
493 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
494 end
494 end
495 if Setting.cross_project_issue_relations?
495 if Setting.cross_project_issue_relations?
496 buf += "#{relation.other_issue(issue).project} - "
496 buf += "#{relation.other_issue(issue).project} - "
497 end
497 end
498 buf += "#{relation.other_issue(issue).tracker}" +
498 buf += "#{relation.other_issue(issue).tracker}" +
499 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
499 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
500 buf = truncate(buf, :length => truncate_length)
500 buf = truncate(buf, :length => truncate_length)
501 pdf.SetFontStyle('', 8)
501 pdf.SetFontStyle('', 8)
502 pdf.RDMCell(35+155-60, 5, buf, "L")
502 pdf.RDMCell(35+155-60, 5, buf, "L")
503 pdf.SetFontStyle('B',8)
503 pdf.SetFontStyle('B',8)
504 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
504 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
505 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
505 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
506 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
506 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
507 pdf.Ln
507 pdf.Ln
508 end
508 end
509 end
509 end
510 pdf.RDMCell(190,5, "", "T")
510 pdf.RDMCell(190,5, "", "T")
511 pdf.Ln
511 pdf.Ln
512
512
513 if issue.changesets.any? &&
513 if issue.changesets.any? &&
514 User.current.allowed_to?(:view_changesets, issue.project)
514 User.current.allowed_to?(:view_changesets, issue.project)
515 pdf.SetFontStyle('B',9)
515 pdf.SetFontStyle('B',9)
516 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
516 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
517 pdf.Ln
517 pdf.Ln
518 for changeset in issue.changesets
518 for changeset in issue.changesets
519 pdf.SetFontStyle('B',8)
519 pdf.SetFontStyle('B',8)
520 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
520 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
521 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
521 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
522 pdf.RDMCell(190, 5, csstr)
522 pdf.RDMCell(190, 5, csstr)
523 pdf.Ln
523 pdf.Ln
524 unless changeset.comments.blank?
524 unless changeset.comments.blank?
525 pdf.SetFontStyle('',8)
525 pdf.SetFontStyle('',8)
526 pdf.RDMwriteHTMLCell(190,5,0,0,
526 pdf.RDMwriteHTMLCell(190,5,0,0,
527 changeset.comments.to_s, issue.attachments, "")
527 changeset.comments.to_s, issue.attachments, "")
528 end
528 end
529 pdf.Ln
529 pdf.Ln
530 end
530 end
531 end
531 end
532
532
533 pdf.SetFontStyle('B',9)
533 pdf.SetFontStyle('B',9)
534 pdf.RDMCell(190,5, l(:label_history), "B")
534 pdf.RDMCell(190,5, l(:label_history), "B")
535 pdf.Ln
535 pdf.Ln
536 indice = 0
536 indice = 0
537 for journal in issue.journals.find(
537 for journal in issue.journals.find(
538 :all, :include => [:user, :details],
538 :all, :include => [:user, :details],
539 :order => "#{Journal.table_name}.created_on ASC")
539 :order => "#{Journal.table_name}.created_on ASC")
540 indice = indice + 1
540 indice = indice + 1
541 pdf.SetFontStyle('B',8)
541 pdf.SetFontStyle('B',8)
542 pdf.RDMCell(190,5,
542 pdf.RDMCell(190,5,
543 "#" + indice.to_s +
543 "#" + indice.to_s +
544 " - " + format_time(journal.created_on) +
544 " - " + format_time(journal.created_on) +
545 " - " + journal.user.name)
545 " - " + journal.user.name)
546 pdf.Ln
546 pdf.Ln
547 pdf.SetFontStyle('I',8)
547 pdf.SetFontStyle('I',8)
548 details_to_strings(journal.details, true).each do |string|
548 details_to_strings(journal.details, true).each do |string|
549 pdf.RDMMultiCell(190,5, "- " + string)
549 pdf.RDMMultiCell(190,5, "- " + string)
550 end
550 end
551 if journal.notes?
551 if journal.notes?
552 pdf.Ln unless journal.details.empty?
552 pdf.Ln unless journal.details.empty?
553 pdf.SetFontStyle('',8)
553 pdf.SetFontStyle('',8)
554 pdf.RDMwriteHTMLCell(190,5,0,0,
554 pdf.RDMwriteHTMLCell(190,5,0,0,
555 journal.notes.to_s, issue.attachments, "")
555 journal.notes.to_s, issue.attachments, "")
556 end
556 end
557 pdf.Ln
557 pdf.Ln
558 end
558 end
559
559
560 if issue.attachments.any?
560 if issue.attachments.any?
561 pdf.SetFontStyle('B',9)
561 pdf.SetFontStyle('B',9)
562 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
562 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
563 pdf.Ln
563 pdf.Ln
564 for attachment in issue.attachments
564 for attachment in issue.attachments
565 pdf.SetFontStyle('',8)
565 pdf.SetFontStyle('',8)
566 pdf.RDMCell(80,5, attachment.filename)
566 pdf.RDMCell(80,5, attachment.filename)
567 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
567 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
568 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
568 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
569 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
569 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
570 pdf.Ln
570 pdf.Ln
571 end
571 end
572 end
572 end
573 pdf.Output
573 pdf.Output
574 end
574 end
575
575
576 # Returns a PDF string of a set of wiki pages
576 # Returns a PDF string of a set of wiki pages
577 def wiki_pages_to_pdf(pages, project)
577 def wiki_pages_to_pdf(pages, project)
578 pdf = ITCPDF.new(current_language)
578 pdf = ITCPDF.new(current_language)
579 pdf.SetTitle(project.name)
579 pdf.SetTitle(project.name)
580 pdf.alias_nb_pages
580 pdf.alias_nb_pages
581 pdf.footer_date = format_date(Date.today)
581 pdf.footer_date = format_date(Date.today)
582 pdf.AddPage
582 pdf.AddPage
583 pdf.SetFontStyle('B',11)
583 pdf.SetFontStyle('B',11)
584 pdf.RDMMultiCell(190,5, project.name)
584 pdf.RDMMultiCell(190,5, project.name)
585 pdf.Ln
585 pdf.Ln
586 # Set resize image scale
586 # Set resize image scale
587 pdf.SetImageScale(1.6)
587 pdf.SetImageScale(1.6)
588 pdf.SetFontStyle('',9)
588 pdf.SetFontStyle('',9)
589 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
589 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
590 pdf.Output
590 pdf.Output
591 end
591 end
592
592
593 # Returns a PDF string of a single wiki page
593 # Returns a PDF string of a single wiki page
594 def wiki_page_to_pdf(page, project)
594 def wiki_page_to_pdf(page, project)
595 pdf = ITCPDF.new(current_language)
595 pdf = ITCPDF.new(current_language)
596 pdf.SetTitle("#{project} - #{page.title}")
596 pdf.SetTitle("#{project} - #{page.title}")
597 pdf.alias_nb_pages
597 pdf.alias_nb_pages
598 pdf.footer_date = format_date(Date.today)
598 pdf.footer_date = format_date(Date.today)
599 pdf.AddPage
599 pdf.AddPage
600 pdf.SetFontStyle('B',11)
600 pdf.SetFontStyle('B',11)
601 pdf.RDMMultiCell(190,5,
601 pdf.RDMMultiCell(190,5,
602 "#{project} - #{page.title} - # #{page.content.version}")
602 "#{project} - #{page.title} - # #{page.content.version}")
603 pdf.Ln
603 pdf.Ln
604 # Set resize image scale
604 # Set resize image scale
605 pdf.SetImageScale(1.6)
605 pdf.SetImageScale(1.6)
606 pdf.SetFontStyle('',9)
606 pdf.SetFontStyle('',9)
607 write_wiki_page(pdf, page)
607 write_wiki_page(pdf, page)
608 pdf.Output
608 pdf.Output
609 end
609 end
610
610
611 def write_page_hierarchy(pdf, pages, node=nil, level=0)
611 def write_page_hierarchy(pdf, pages, node=nil, level=0)
612 if pages[node]
612 if pages[node]
613 pages[node].each do |page|
613 pages[node].each do |page|
614 if @new_page
614 if @new_page
615 pdf.AddPage
615 pdf.AddPage
616 else
616 else
617 @new_page = true
617 @new_page = true
618 end
618 end
619 pdf.Bookmark page.title, level
619 pdf.Bookmark page.title, level
620 write_wiki_page(pdf, page)
620 write_wiki_page(pdf, page)
621 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
621 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
622 end
622 end
623 end
623 end
624 end
624 end
625
625
626 def write_wiki_page(pdf, page)
626 def write_wiki_page(pdf, page)
627 pdf.RDMwriteHTMLCell(190,5,0,0,
627 pdf.RDMwriteHTMLCell(190,5,0,0,
628 page.content.text.to_s, page.attachments, "TLRB")
628 page.content.text.to_s, page.attachments, "TLRB")
629 if page.attachments.any?
629 if page.attachments.any?
630 pdf.Ln
630 pdf.Ln
631 pdf.SetFontStyle('B',9)
631 pdf.SetFontStyle('B',9)
632 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
632 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
633 pdf.Ln
633 pdf.Ln
634 for attachment in page.attachments
634 for attachment in page.attachments
635 pdf.SetFontStyle('',8)
635 pdf.SetFontStyle('',8)
636 pdf.RDMCell(80,5, attachment.filename)
636 pdf.RDMCell(80,5, attachment.filename)
637 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
637 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
638 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
638 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
639 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
639 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
640 pdf.Ln
640 pdf.Ln
641 end
641 end
642 end
642 end
643 end
643 end
644
644
645 class RDMPdfEncoding
645 class RDMPdfEncoding
646 def self.rdm_from_utf8(txt, encoding)
646 def self.rdm_from_utf8(txt, encoding)
647 txt ||= ''
647 txt ||= ''
648 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
648 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
649 if txt.respond_to?(:force_encoding)
649 if txt.respond_to?(:force_encoding)
650 txt.force_encoding('ASCII-8BIT')
650 txt.force_encoding('ASCII-8BIT')
651 end
651 end
652 txt
652 txt
653 end
653 end
654
654
655 def self.attach(attachments, filename, encoding)
655 def self.attach(attachments, filename, encoding)
656 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
656 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
657 atta = nil
657 atta = nil
658 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
658 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
659 atta = Attachment.latest_attach(attachments, filename_utf8)
659 atta = Attachment.latest_attach(attachments, filename_utf8)
660 end
660 end
661 if atta && atta.readable? && atta.visible?
661 if atta && atta.readable? && atta.visible?
662 return atta
662 return atta
663 else
663 else
664 return nil
664 return nil
665 end
665 end
666 end
666 end
667 end
667 end
668 end
668 end
669 end
669 end
670 end
670 end
General Comments 0
You need to be logged in to leave comments. Login now