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