##// END OF EJS Templates
Merged r13977 from trunk to 2.6-stable (#10681, #18586)...
Toshi MARUYAMA -
r13602:bdaf2c27a17f
parent child
Show More
@@ -1,707 +1,709
1 # encoding: utf-8
1 # encoding: utf-8
2 #
2 #
3 # Redmine - project management software
3 # Redmine - project management software
4 # Copyright (C) 2006-2015 Jean-Philippe Lang
4 # Copyright (C) 2006-2015 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 'rbpdf'
20 require 'rbpdf'
21
21
22 module Redmine
22 module Redmine
23 module Export
23 module Export
24 module PDF
24 module PDF
25 include ActionView::Helpers::TextHelper
25 include ActionView::Helpers::TextHelper
26 include ActionView::Helpers::NumberHelper
26 include ActionView::Helpers::NumberHelper
27 include IssuesHelper
27 include IssuesHelper
28
28
29 class ITCPDF < RBPDF
29 class ITCPDF < RBPDF
30 include Redmine::I18n
30 include Redmine::I18n
31 attr_accessor :footer_date
31 attr_accessor :footer_date
32
32
33 def initialize(lang, orientation='P')
33 def initialize(lang, orientation='P')
34 @@k_path_cache = Rails.root.join('tmp', 'pdf')
34 @@k_path_cache = Rails.root.join('tmp', 'pdf')
35 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
35 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
36 set_language_if_valid lang
36 set_language_if_valid lang
37 super(orientation, 'mm', 'A4')
37 super(orientation, 'mm', 'A4')
38 set_print_header(false)
38 set_print_header(false)
39 set_rtl(l(:direction) == 'rtl')
39 set_rtl(l(:direction) == 'rtl')
40
40
41 @font_for_content = l(:general_pdf_fontname)
41 @font_for_content = l(:general_pdf_fontname)
42 @font_for_footer = l(:general_pdf_fontname)
42 @font_for_footer = l(:general_pdf_fontname)
43 set_creator(Redmine::Info.app_name)
43 set_creator(Redmine::Info.app_name)
44 set_font(@font_for_content)
44 set_font(@font_for_content)
45
45
46 set_header_font([@font_for_content, '', 10])
46 set_header_font([@font_for_content, '', 10])
47 set_footer_font([@font_for_content, '', 8])
47 set_footer_font([@font_for_content, '', 8])
48 set_default_monospaced_font(@font_for_content)
48 set_default_monospaced_font(@font_for_content)
49 end
49 end
50
50
51 def SetFontStyle(style, size)
51 def SetFontStyle(style, size)
52 set_font(@font_for_content, style, size)
52 set_font(@font_for_content, style, size)
53 end
53 end
54
54
55 def SetFont(family, style='', size=0, fontfile='')
55 def SetFont(family, style='', size=0, fontfile='')
56 style.delete!('B') if current_language.to_s.downcase == 'th' # FreeSerif Bold Thai font has problem.
56 # FreeSerif Bold Thai font has problem.
57 style.delete!('I') if current_language.to_s.downcase =~ /^(fa|ar)$/ # DejaVuSans Italic Arabic and Persian font has problem.
57 style.delete!('B') if l(:general_pdf_fontname) == 'freeserif'
58 # DejaVuSans Italic Arabic and Persian font has problem.
59 style.delete!('I') if l(:general_pdf_fontname) == 'DejaVuSans'
58 super(family, style, size, fontfile)
60 super(family, style, size, fontfile)
59 end
61 end
60 alias_method :set_font, :SetFont
62 alias_method :set_font, :SetFont
61
63
62 def fix_text_encoding(txt)
64 def fix_text_encoding(txt)
63 RDMPdfEncoding::rdm_from_utf8(txt, "UTF-8")
65 RDMPdfEncoding::rdm_from_utf8(txt, "UTF-8")
64 end
66 end
65
67
66 def formatted_text(text)
68 def formatted_text(text)
67 html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text)
69 html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text)
68 # Strip {{toc}} tags
70 # Strip {{toc}} tags
69 html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '')
71 html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '')
70 html
72 html
71 end
73 end
72
74
73 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
75 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
74 cell(w, h, txt, border, ln, align, fill, link)
76 cell(w, h, txt, border, ln, align, fill, link)
75 end
77 end
76
78
77 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
79 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
78 multi_cell(w, h, txt, border, align, fill, ln)
80 multi_cell(w, h, txt, border, align, fill, ln)
79 end
81 end
80
82
81 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
83 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
82 @attachments = attachments
84 @attachments = attachments
83
85
84 css_tag = ' <style>
86 css_tag = ' <style>
85 table, td {
87 table, td {
86 border: 2px #ff0000 solid;
88 border: 2px #ff0000 solid;
87 }
89 }
88 th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; text-align: center; font-style: bold;}
90 th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; text-align: center; font-style: bold;}
89 pre {
91 pre {
90 background-color: #fafafa;
92 background-color: #fafafa;
91 }
93 }
92 </style>'
94 </style>'
93
95
94 writeHTMLCell(w, h, x, y,
96 writeHTMLCell(w, h, x, y,
95 css_tag + formatted_text(txt),
97 css_tag + formatted_text(txt),
96 border, ln, fill)
98 border, ln, fill)
97 end
99 end
98
100
99 def get_image_filename(attrname)
101 def get_image_filename(attrname)
100 atta = RDMPdfEncoding.attach(@attachments, attrname, "UTF-8")
102 atta = RDMPdfEncoding.attach(@attachments, attrname, "UTF-8")
101 if atta
103 if atta
102 return atta.diskfile
104 return atta.diskfile
103 else
105 else
104 return nil
106 return nil
105 end
107 end
106 end
108 end
107
109
108 def get_sever_url(url)
110 def get_sever_url(url)
109 if !empty_string(url) and (url[0, 1] == '/')
111 if !empty_string(url) and (url[0, 1] == '/')
110 Setting.host_name.split('/')[0] + url
112 Setting.host_name.split('/')[0] + url
111 else
113 else
112 url
114 url
113 end
115 end
114 end
116 end
115
117
116 def Footer
118 def Footer
117 set_font(@font_for_footer, 'I', 8)
119 set_font(@font_for_footer, 'I', 8)
118 set_x(15)
120 set_x(15)
119 if get_rtl
121 if get_rtl
120 RDMCell(0, 5, @footer_date, 0, 0, 'R')
122 RDMCell(0, 5, @footer_date, 0, 0, 'R')
121 else
123 else
122 RDMCell(0, 5, @footer_date, 0, 0, 'L')
124 RDMCell(0, 5, @footer_date, 0, 0, 'L')
123 end
125 end
124 set_x(-30)
126 set_x(-30)
125 RDMCell(0, 5, get_alias_num_page() + '/' + get_alias_nb_pages(), 0, 0, 'C')
127 RDMCell(0, 5, get_alias_num_page() + '/' + get_alias_nb_pages(), 0, 0, 'C')
126 end
128 end
127 end
129 end
128
130
129 def is_cjk?
131 def is_cjk?
130 case current_language.to_s.downcase
132 case current_language.to_s.downcase
131 when 'ja', 'zh-tw', 'zh', 'ko'
133 when 'ja', 'zh-tw', 'zh', 'ko'
132 true
134 true
133 else
135 else
134 false
136 false
135 end
137 end
136 end
138 end
137
139
138 # fetch row values
140 # fetch row values
139 def fetch_row_values(issue, query, level)
141 def fetch_row_values(issue, query, level)
140 query.inline_columns.collect do |column|
142 query.inline_columns.collect do |column|
141 s = if column.is_a?(QueryCustomFieldColumn)
143 s = if column.is_a?(QueryCustomFieldColumn)
142 cv = issue.visible_custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
144 cv = issue.visible_custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
143 show_value(cv, false)
145 show_value(cv, false)
144 else
146 else
145 value = issue.send(column.name)
147 value = issue.send(column.name)
146 if column.name == :subject
148 if column.name == :subject
147 value = " " * level + value
149 value = " " * level + value
148 end
150 end
149 if value.is_a?(Date)
151 if value.is_a?(Date)
150 format_date(value)
152 format_date(value)
151 elsif value.is_a?(Time)
153 elsif value.is_a?(Time)
152 format_time(value)
154 format_time(value)
153 else
155 else
154 value
156 value
155 end
157 end
156 end
158 end
157 s.to_s
159 s.to_s
158 end
160 end
159 end
161 end
160
162
161 # calculate columns width
163 # calculate columns width
162 def calc_col_width(issues, query, table_width, pdf)
164 def calc_col_width(issues, query, table_width, pdf)
163 # calculate statistics
165 # calculate statistics
164 # by captions
166 # by captions
165 pdf.SetFontStyle('B',8)
167 pdf.SetFontStyle('B',8)
166 margins = pdf.get_margins
168 margins = pdf.get_margins
167 col_padding = margins['cell']
169 col_padding = margins['cell']
168 col_width_min = query.inline_columns.map {|v| pdf.get_string_width(v.caption) + col_padding}
170 col_width_min = query.inline_columns.map {|v| pdf.get_string_width(v.caption) + col_padding}
169 col_width_max = Array.new(col_width_min)
171 col_width_max = Array.new(col_width_min)
170 col_width_avg = Array.new(col_width_min)
172 col_width_avg = Array.new(col_width_min)
171 col_min = pdf.get_string_width('OO') + col_padding * 2
173 col_min = pdf.get_string_width('OO') + col_padding * 2
172 if table_width > col_min * col_width_avg.length
174 if table_width > col_min * col_width_avg.length
173 table_width -= col_min * col_width_avg.length
175 table_width -= col_min * col_width_avg.length
174 else
176 else
175 col_min = pdf.get_string_width('O') + col_padding * 2
177 col_min = pdf.get_string_width('O') + col_padding * 2
176 if table_width > col_min * col_width_avg.length
178 if table_width > col_min * col_width_avg.length
177 table_width -= col_min * col_width_avg.length
179 table_width -= col_min * col_width_avg.length
178 else
180 else
179 ratio = table_width / col_width_avg.inject(0, :+)
181 ratio = table_width / col_width_avg.inject(0, :+)
180 return col_width = col_width_avg.map {|w| w * ratio}
182 return col_width = col_width_avg.map {|w| w * ratio}
181 end
183 end
182 end
184 end
183 word_width_max = query.inline_columns.map {|c|
185 word_width_max = query.inline_columns.map {|c|
184 n = 10
186 n = 10
185 c.caption.split.each {|w|
187 c.caption.split.each {|w|
186 x = pdf.get_string_width(w) + col_padding
188 x = pdf.get_string_width(w) + col_padding
187 n = x if n < x
189 n = x if n < x
188 }
190 }
189 n
191 n
190 }
192 }
191
193
192 # by properties of issues
194 # by properties of issues
193 pdf.SetFontStyle('',8)
195 pdf.SetFontStyle('',8)
194 k = 1
196 k = 1
195 issue_list(issues) {|issue, level|
197 issue_list(issues) {|issue, level|
196 k += 1
198 k += 1
197 values = fetch_row_values(issue, query, level)
199 values = fetch_row_values(issue, query, level)
198 values.each_with_index {|v,i|
200 values.each_with_index {|v,i|
199 n = pdf.get_string_width(v) + col_padding * 2
201 n = pdf.get_string_width(v) + col_padding * 2
200 col_width_max[i] = n if col_width_max[i] < n
202 col_width_max[i] = n if col_width_max[i] < n
201 col_width_min[i] = n if col_width_min[i] > n
203 col_width_min[i] = n if col_width_min[i] > n
202 col_width_avg[i] += n
204 col_width_avg[i] += n
203 v.split.each {|w|
205 v.split.each {|w|
204 x = pdf.get_string_width(w) + col_padding
206 x = pdf.get_string_width(w) + col_padding
205 word_width_max[i] = x if word_width_max[i] < x
207 word_width_max[i] = x if word_width_max[i] < x
206 }
208 }
207 }
209 }
208 }
210 }
209 col_width_avg.map! {|x| x / k}
211 col_width_avg.map! {|x| x / k}
210
212
211 # calculate columns width
213 # calculate columns width
212 ratio = table_width / col_width_avg.inject(0, :+)
214 ratio = table_width / col_width_avg.inject(0, :+)
213 col_width = col_width_avg.map {|w| w * ratio}
215 col_width = col_width_avg.map {|w| w * ratio}
214
216
215 # correct max word width if too many columns
217 # correct max word width if too many columns
216 ratio = table_width / word_width_max.inject(0, :+)
218 ratio = table_width / word_width_max.inject(0, :+)
217 word_width_max.map! {|v| v * ratio} if ratio < 1
219 word_width_max.map! {|v| v * ratio} if ratio < 1
218
220
219 # correct and lock width of some columns
221 # correct and lock width of some columns
220 done = 1
222 done = 1
221 col_fix = []
223 col_fix = []
222 col_width.each_with_index do |w,i|
224 col_width.each_with_index do |w,i|
223 if w > col_width_max[i]
225 if w > col_width_max[i]
224 col_width[i] = col_width_max[i]
226 col_width[i] = col_width_max[i]
225 col_fix[i] = 1
227 col_fix[i] = 1
226 done = 0
228 done = 0
227 elsif w < word_width_max[i]
229 elsif w < word_width_max[i]
228 col_width[i] = word_width_max[i]
230 col_width[i] = word_width_max[i]
229 col_fix[i] = 1
231 col_fix[i] = 1
230 done = 0
232 done = 0
231 else
233 else
232 col_fix[i] = 0
234 col_fix[i] = 0
233 end
235 end
234 end
236 end
235
237
236 # iterate while need to correct and lock coluns width
238 # iterate while need to correct and lock coluns width
237 while done == 0
239 while done == 0
238 # calculate free & locked columns width
240 # calculate free & locked columns width
239 done = 1
241 done = 1
240 ratio = table_width / col_width.inject(0, :+)
242 ratio = table_width / col_width.inject(0, :+)
241
243
242 # correct columns width
244 # correct columns width
243 col_width.each_with_index do |w,i|
245 col_width.each_with_index do |w,i|
244 if col_fix[i] == 0
246 if col_fix[i] == 0
245 col_width[i] = w * ratio
247 col_width[i] = w * ratio
246
248
247 # check if column width less then max word width
249 # check if column width less then max word width
248 if col_width[i] < word_width_max[i]
250 if col_width[i] < word_width_max[i]
249 col_width[i] = word_width_max[i]
251 col_width[i] = word_width_max[i]
250 col_fix[i] = 1
252 col_fix[i] = 1
251 done = 0
253 done = 0
252 elsif col_width[i] > col_width_max[i]
254 elsif col_width[i] > col_width_max[i]
253 col_width[i] = col_width_max[i]
255 col_width[i] = col_width_max[i]
254 col_fix[i] = 1
256 col_fix[i] = 1
255 done = 0
257 done = 0
256 end
258 end
257 end
259 end
258 end
260 end
259 end
261 end
260
262
261 ratio = table_width / col_width.inject(0, :+)
263 ratio = table_width / col_width.inject(0, :+)
262 col_width.map! {|v| v * ratio + col_min}
264 col_width.map! {|v| v * ratio + col_min}
263 col_width
265 col_width
264 end
266 end
265
267
266 def render_table_header(pdf, query, col_width, row_height, table_width)
268 def render_table_header(pdf, query, col_width, row_height, table_width)
267 # headers
269 # headers
268 pdf.SetFontStyle('B',8)
270 pdf.SetFontStyle('B',8)
269 pdf.set_fill_color(230, 230, 230)
271 pdf.set_fill_color(230, 230, 230)
270
272
271 base_x = pdf.get_x
273 base_x = pdf.get_x
272 base_y = pdf.get_y
274 base_y = pdf.get_y
273 max_height = get_issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, true)
275 max_height = get_issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, true)
274
276
275 # write the cells on page
277 # write the cells on page
276 issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, max_height, true)
278 issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, max_height, true)
277 pdf.set_xy(base_x, base_y + max_height)
279 pdf.set_xy(base_x, base_y + max_height)
278
280
279 # rows
281 # rows
280 pdf.SetFontStyle('',8)
282 pdf.SetFontStyle('',8)
281 pdf.set_fill_color(255, 255, 255)
283 pdf.set_fill_color(255, 255, 255)
282 end
284 end
283
285
284 # Returns a PDF string of a list of issues
286 # Returns a PDF string of a list of issues
285 def issues_to_pdf(issues, project, query)
287 def issues_to_pdf(issues, project, query)
286 pdf = ITCPDF.new(current_language, "L")
288 pdf = ITCPDF.new(current_language, "L")
287 title = query.new_record? ? l(:label_issue_plural) : query.name
289 title = query.new_record? ? l(:label_issue_plural) : query.name
288 title = "#{project} - #{title}" if project
290 title = "#{project} - #{title}" if project
289 pdf.set_title(title)
291 pdf.set_title(title)
290 pdf.alias_nb_pages
292 pdf.alias_nb_pages
291 pdf.footer_date = format_date(Date.today)
293 pdf.footer_date = format_date(Date.today)
292 pdf.set_auto_page_break(false)
294 pdf.set_auto_page_break(false)
293 pdf.add_page("L")
295 pdf.add_page("L")
294
296
295 # Landscape A4 = 210 x 297 mm
297 # Landscape A4 = 210 x 297 mm
296 page_height = pdf.get_page_height # 210
298 page_height = pdf.get_page_height # 210
297 page_width = pdf.get_page_width # 297
299 page_width = pdf.get_page_width # 297
298 left_margin = pdf.get_original_margins['left'] # 10
300 left_margin = pdf.get_original_margins['left'] # 10
299 right_margin = pdf.get_original_margins['right'] # 10
301 right_margin = pdf.get_original_margins['right'] # 10
300 bottom_margin = pdf.get_footer_margin
302 bottom_margin = pdf.get_footer_margin
301 row_height = 4
303 row_height = 4
302
304
303 # column widths
305 # column widths
304 table_width = page_width - right_margin - left_margin
306 table_width = page_width - right_margin - left_margin
305 col_width = []
307 col_width = []
306 unless query.inline_columns.empty?
308 unless query.inline_columns.empty?
307 col_width = calc_col_width(issues, query, table_width, pdf)
309 col_width = calc_col_width(issues, query, table_width, pdf)
308 table_width = col_width.inject(0, :+)
310 table_width = col_width.inject(0, :+)
309 end
311 end
310
312
311 # use full width if the description is displayed
313 # use full width if the description is displayed
312 if table_width > 0 && query.has_column?(:description)
314 if table_width > 0 && query.has_column?(:description)
313 col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width}
315 col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width}
314 table_width = col_width.inject(0, :+)
316 table_width = col_width.inject(0, :+)
315 end
317 end
316
318
317 # title
319 # title
318 pdf.SetFontStyle('B',11)
320 pdf.SetFontStyle('B',11)
319 pdf.RDMCell(190,10, title)
321 pdf.RDMCell(190,10, title)
320 pdf.ln
322 pdf.ln
321
323
322 render_table_header(pdf, query, col_width, row_height, table_width)
324 render_table_header(pdf, query, col_width, row_height, table_width)
323 previous_group = false
325 previous_group = false
324 issue_list(issues) do |issue, level|
326 issue_list(issues) do |issue, level|
325 if query.grouped? &&
327 if query.grouped? &&
326 (group = query.group_by_column.value(issue)) != previous_group
328 (group = query.group_by_column.value(issue)) != previous_group
327 pdf.SetFontStyle('B',10)
329 pdf.SetFontStyle('B',10)
328 group_label = group.blank? ? 'None' : group.to_s.dup
330 group_label = group.blank? ? 'None' : group.to_s.dup
329 group_label << " (#{query.issue_count_by_group[group]})"
331 group_label << " (#{query.issue_count_by_group[group]})"
330 pdf.bookmark group_label, 0, -1
332 pdf.bookmark group_label, 0, -1
331 pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L')
333 pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L')
332 pdf.SetFontStyle('',8)
334 pdf.SetFontStyle('',8)
333 previous_group = group
335 previous_group = group
334 end
336 end
335
337
336 # fetch row values
338 # fetch row values
337 col_values = fetch_row_values(issue, query, level)
339 col_values = fetch_row_values(issue, query, level)
338
340
339 # make new page if it doesn't fit on the current one
341 # make new page if it doesn't fit on the current one
340 base_y = pdf.get_y
342 base_y = pdf.get_y
341 max_height = get_issues_to_pdf_write_cells(pdf, col_values, col_width)
343 max_height = get_issues_to_pdf_write_cells(pdf, col_values, col_width)
342 space_left = page_height - base_y - bottom_margin
344 space_left = page_height - base_y - bottom_margin
343 if max_height > space_left
345 if max_height > space_left
344 pdf.add_page("L")
346 pdf.add_page("L")
345 render_table_header(pdf, query, col_width, row_height, table_width)
347 render_table_header(pdf, query, col_width, row_height, table_width)
346 base_y = pdf.get_y
348 base_y = pdf.get_y
347 end
349 end
348
350
349 # write the cells on page
351 # write the cells on page
350 issues_to_pdf_write_cells(pdf, col_values, col_width, max_height)
352 issues_to_pdf_write_cells(pdf, col_values, col_width, max_height)
351 pdf.set_y(base_y + max_height)
353 pdf.set_y(base_y + max_height)
352
354
353 if query.has_column?(:description) && issue.description?
355 if query.has_column?(:description) && issue.description?
354 pdf.set_x(10)
356 pdf.set_x(10)
355 pdf.set_auto_page_break(true, bottom_margin)
357 pdf.set_auto_page_break(true, bottom_margin)
356 pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.description.to_s, issue.attachments, "LRBT")
358 pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.description.to_s, issue.attachments, "LRBT")
357 pdf.set_auto_page_break(false)
359 pdf.set_auto_page_break(false)
358 end
360 end
359 end
361 end
360
362
361 if issues.size == Setting.issues_export_limit.to_i
363 if issues.size == Setting.issues_export_limit.to_i
362 pdf.SetFontStyle('B',10)
364 pdf.SetFontStyle('B',10)
363 pdf.RDMCell(0, row_height, '...')
365 pdf.RDMCell(0, row_height, '...')
364 end
366 end
365 pdf.output
367 pdf.output
366 end
368 end
367
369
368 # returns the maximum height of MultiCells
370 # returns the maximum height of MultiCells
369 def get_issues_to_pdf_write_cells(pdf, col_values, col_widths, head=false)
371 def get_issues_to_pdf_write_cells(pdf, col_values, col_widths, head=false)
370 heights = []
372 heights = []
371 col_values.each_with_index do |column, i|
373 col_values.each_with_index do |column, i|
372 heights << pdf.get_string_height(col_widths[i], head ? column.caption : column)
374 heights << pdf.get_string_height(col_widths[i], head ? column.caption : column)
373 end
375 end
374 return heights.max
376 return heights.max
375 end
377 end
376
378
377 # Renders MultiCells and returns the maximum height used
379 # Renders MultiCells and returns the maximum height used
378 def issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height, head=false)
380 def issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height, head=false)
379 col_values.each_with_index do |column, i|
381 col_values.each_with_index do |column, i|
380 pdf.RDMMultiCell(col_widths[i], row_height, head ? column.caption : column.strip, 1, '', 1, 0)
382 pdf.RDMMultiCell(col_widths[i], row_height, head ? column.caption : column.strip, 1, '', 1, 0)
381 end
383 end
382 end
384 end
383
385
384 # Draw lines to close the row (MultiCell border drawing in not uniform)
386 # Draw lines to close the row (MultiCell border drawing in not uniform)
385 #
387 #
386 # parameter "col_id_width" is not used. it is kept for compatibility.
388 # parameter "col_id_width" is not used. it is kept for compatibility.
387 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
389 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
388 col_id_width, col_widths, rtl=false)
390 col_id_width, col_widths, rtl=false)
389 col_x = top_x
391 col_x = top_x
390 pdf.line(col_x, top_y, col_x, lower_y) # id right border
392 pdf.line(col_x, top_y, col_x, lower_y) # id right border
391 col_widths.each do |width|
393 col_widths.each do |width|
392 if rtl
394 if rtl
393 col_x -= width
395 col_x -= width
394 else
396 else
395 col_x += width
397 col_x += width
396 end
398 end
397 pdf.line(col_x, top_y, col_x, lower_y) # columns right border
399 pdf.line(col_x, top_y, col_x, lower_y) # columns right border
398 end
400 end
399 pdf.line(top_x, top_y, top_x, lower_y) # left border
401 pdf.line(top_x, top_y, top_x, lower_y) # left border
400 pdf.line(top_x, lower_y, col_x, lower_y) # bottom border
402 pdf.line(top_x, lower_y, col_x, lower_y) # bottom border
401 end
403 end
402
404
403 # Returns a PDF string of a single issue
405 # Returns a PDF string of a single issue
404 def issue_to_pdf(issue, assoc={})
406 def issue_to_pdf(issue, assoc={})
405 pdf = ITCPDF.new(current_language)
407 pdf = ITCPDF.new(current_language)
406 pdf.set_title("#{issue.project} - #{issue.tracker} ##{issue.id}")
408 pdf.set_title("#{issue.project} - #{issue.tracker} ##{issue.id}")
407 pdf.alias_nb_pages
409 pdf.alias_nb_pages
408 pdf.footer_date = format_date(Date.today)
410 pdf.footer_date = format_date(Date.today)
409 pdf.add_page
411 pdf.add_page
410 pdf.SetFontStyle('B',11)
412 pdf.SetFontStyle('B',11)
411 buf = "#{issue.project} - #{issue.tracker} ##{issue.id}"
413 buf = "#{issue.project} - #{issue.tracker} ##{issue.id}"
412 pdf.RDMMultiCell(190, 5, buf)
414 pdf.RDMMultiCell(190, 5, buf)
413 pdf.SetFontStyle('',8)
415 pdf.SetFontStyle('',8)
414 base_x = pdf.get_x
416 base_x = pdf.get_x
415 i = 1
417 i = 1
416 issue.ancestors.visible.each do |ancestor|
418 issue.ancestors.visible.each do |ancestor|
417 pdf.set_x(base_x + i)
419 pdf.set_x(base_x + i)
418 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
420 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
419 pdf.RDMMultiCell(190 - i, 5, buf)
421 pdf.RDMMultiCell(190 - i, 5, buf)
420 i += 1 if i < 35
422 i += 1 if i < 35
421 end
423 end
422 pdf.SetFontStyle('B',11)
424 pdf.SetFontStyle('B',11)
423 pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s)
425 pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s)
424 pdf.SetFontStyle('',8)
426 pdf.SetFontStyle('',8)
425 pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}")
427 pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}")
426 pdf.ln
428 pdf.ln
427
429
428 left = []
430 left = []
429 left << [l(:field_status), issue.status]
431 left << [l(:field_status), issue.status]
430 left << [l(:field_priority), issue.priority]
432 left << [l(:field_priority), issue.priority]
431 left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id')
433 left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id')
432 left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id')
434 left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id')
433 left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id')
435 left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id')
434
436
435 right = []
437 right = []
436 right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date')
438 right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date')
437 right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date')
439 right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date')
438 right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio')
440 right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio')
439 right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours')
441 right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours')
440 right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project)
442 right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project)
441
443
442 rows = left.size > right.size ? left.size : right.size
444 rows = left.size > right.size ? left.size : right.size
443 while left.size < rows
445 while left.size < rows
444 left << nil
446 left << nil
445 end
447 end
446 while right.size < rows
448 while right.size < rows
447 right << nil
449 right << nil
448 end
450 end
449
451
450 half = (issue.visible_custom_field_values.size / 2.0).ceil
452 half = (issue.visible_custom_field_values.size / 2.0).ceil
451 issue.visible_custom_field_values.each_with_index do |custom_value, i|
453 issue.visible_custom_field_values.each_with_index do |custom_value, i|
452 (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value, false)]
454 (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value, false)]
453 end
455 end
454
456
455 if pdf.get_rtl
457 if pdf.get_rtl
456 border_first_top = 'RT'
458 border_first_top = 'RT'
457 border_last_top = 'LT'
459 border_last_top = 'LT'
458 border_first = 'R'
460 border_first = 'R'
459 border_last = 'L'
461 border_last = 'L'
460 else
462 else
461 border_first_top = 'LT'
463 border_first_top = 'LT'
462 border_last_top = 'RT'
464 border_last_top = 'RT'
463 border_first = 'L'
465 border_first = 'L'
464 border_last = 'R'
466 border_last = 'R'
465 end
467 end
466
468
467 rows = left.size > right.size ? left.size : right.size
469 rows = left.size > right.size ? left.size : right.size
468 rows.times do |i|
470 rows.times do |i|
469 heights = []
471 heights = []
470 pdf.SetFontStyle('B',9)
472 pdf.SetFontStyle('B',9)
471 item = left[i]
473 item = left[i]
472 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
474 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
473 item = right[i]
475 item = right[i]
474 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
476 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
475 pdf.SetFontStyle('',9)
477 pdf.SetFontStyle('',9)
476 item = left[i]
478 item = left[i]
477 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
479 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
478 item = right[i]
480 item = right[i]
479 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
481 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
480 height = heights.max
482 height = heights.max
481
483
482 item = left[i]
484 item = left[i]
483 pdf.SetFontStyle('B',9)
485 pdf.SetFontStyle('B',9)
484 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
486 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
485 pdf.SetFontStyle('',9)
487 pdf.SetFontStyle('',9)
486 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 0)
488 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 0)
487
489
488 item = right[i]
490 item = right[i]
489 pdf.SetFontStyle('B',9)
491 pdf.SetFontStyle('B',9)
490 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
492 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
491 pdf.SetFontStyle('',9)
493 pdf.SetFontStyle('',9)
492 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 2)
494 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 2)
493
495
494 pdf.set_x(base_x)
496 pdf.set_x(base_x)
495 end
497 end
496
498
497 pdf.SetFontStyle('B',9)
499 pdf.SetFontStyle('B',9)
498 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
500 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
499 pdf.SetFontStyle('',9)
501 pdf.SetFontStyle('',9)
500
502
501 # Set resize image scale
503 # Set resize image scale
502 pdf.set_image_scale(1.6)
504 pdf.set_image_scale(1.6)
503 pdf.RDMwriteHTMLCell(35+155, 5, '', '',
505 pdf.RDMwriteHTMLCell(35+155, 5, '', '',
504 issue.description.to_s, issue.attachments, "LRB")
506 issue.description.to_s, issue.attachments, "LRB")
505
507
506 unless issue.leaf?
508 unless issue.leaf?
507 truncate_length = (!is_cjk? ? 90 : 65)
509 truncate_length = (!is_cjk? ? 90 : 65)
508 pdf.SetFontStyle('B',9)
510 pdf.SetFontStyle('B',9)
509 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
511 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
510 pdf.ln
512 pdf.ln
511 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
513 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
512 buf = "#{child.tracker} # #{child.id}: #{child.subject}".
514 buf = "#{child.tracker} # #{child.id}: #{child.subject}".
513 truncate(truncate_length)
515 truncate(truncate_length)
514 level = 10 if level >= 10
516 level = 10 if level >= 10
515 pdf.SetFontStyle('',8)
517 pdf.SetFontStyle('',8)
516 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, border_first)
518 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, border_first)
517 pdf.SetFontStyle('B',8)
519 pdf.SetFontStyle('B',8)
518 pdf.RDMCell(20,5, child.status.to_s, border_last)
520 pdf.RDMCell(20,5, child.status.to_s, border_last)
519 pdf.ln
521 pdf.ln
520 end
522 end
521 end
523 end
522
524
523 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
525 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
524 unless relations.empty?
526 unless relations.empty?
525 truncate_length = (!is_cjk? ? 80 : 60)
527 truncate_length = (!is_cjk? ? 80 : 60)
526 pdf.SetFontStyle('B',9)
528 pdf.SetFontStyle('B',9)
527 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
529 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
528 pdf.ln
530 pdf.ln
529 relations.each do |relation|
531 relations.each do |relation|
530 buf = ""
532 buf = ""
531 buf += "#{l(relation.label_for(issue))} "
533 buf += "#{l(relation.label_for(issue))} "
532 if relation.delay && relation.delay != 0
534 if relation.delay && relation.delay != 0
533 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
535 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
534 end
536 end
535 if Setting.cross_project_issue_relations?
537 if Setting.cross_project_issue_relations?
536 buf += "#{relation.other_issue(issue).project} - "
538 buf += "#{relation.other_issue(issue).project} - "
537 end
539 end
538 buf += "#{relation.other_issue(issue).tracker}" +
540 buf += "#{relation.other_issue(issue).tracker}" +
539 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
541 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
540 buf = buf.truncate(truncate_length)
542 buf = buf.truncate(truncate_length)
541 pdf.SetFontStyle('', 8)
543 pdf.SetFontStyle('', 8)
542 pdf.RDMCell(35+155-60, 5, buf, border_first)
544 pdf.RDMCell(35+155-60, 5, buf, border_first)
543 pdf.SetFontStyle('B',8)
545 pdf.SetFontStyle('B',8)
544 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
546 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
545 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
547 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
546 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), border_last)
548 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), border_last)
547 pdf.ln
549 pdf.ln
548 end
550 end
549 end
551 end
550 pdf.RDMCell(190,5, "", "T")
552 pdf.RDMCell(190,5, "", "T")
551 pdf.ln
553 pdf.ln
552
554
553 if issue.changesets.any? &&
555 if issue.changesets.any? &&
554 User.current.allowed_to?(:view_changesets, issue.project)
556 User.current.allowed_to?(:view_changesets, issue.project)
555 pdf.SetFontStyle('B',9)
557 pdf.SetFontStyle('B',9)
556 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
558 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
557 pdf.ln
559 pdf.ln
558 for changeset in issue.changesets
560 for changeset in issue.changesets
559 pdf.SetFontStyle('B',8)
561 pdf.SetFontStyle('B',8)
560 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
562 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
561 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
563 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
562 pdf.RDMCell(190, 5, csstr)
564 pdf.RDMCell(190, 5, csstr)
563 pdf.ln
565 pdf.ln
564 unless changeset.comments.blank?
566 unless changeset.comments.blank?
565 pdf.SetFontStyle('',8)
567 pdf.SetFontStyle('',8)
566 pdf.RDMwriteHTMLCell(190,5,'','',
568 pdf.RDMwriteHTMLCell(190,5,'','',
567 changeset.comments.to_s, issue.attachments, "")
569 changeset.comments.to_s, issue.attachments, "")
568 end
570 end
569 pdf.ln
571 pdf.ln
570 end
572 end
571 end
573 end
572
574
573 if assoc[:journals].present?
575 if assoc[:journals].present?
574 pdf.SetFontStyle('B',9)
576 pdf.SetFontStyle('B',9)
575 pdf.RDMCell(190,5, l(:label_history), "B")
577 pdf.RDMCell(190,5, l(:label_history), "B")
576 pdf.ln
578 pdf.ln
577 assoc[:journals].each do |journal|
579 assoc[:journals].each do |journal|
578 pdf.SetFontStyle('B',8)
580 pdf.SetFontStyle('B',8)
579 title = "##{journal.indice} - #{format_time(journal.created_on)} - #{journal.user}"
581 title = "##{journal.indice} - #{format_time(journal.created_on)} - #{journal.user}"
580 title << " (#{l(:field_private_notes)})" if journal.private_notes?
582 title << " (#{l(:field_private_notes)})" if journal.private_notes?
581 pdf.RDMCell(190,5, title)
583 pdf.RDMCell(190,5, title)
582 pdf.ln
584 pdf.ln
583 pdf.SetFontStyle('I',8)
585 pdf.SetFontStyle('I',8)
584 details_to_strings(journal.visible_details, true).each do |string|
586 details_to_strings(journal.visible_details, true).each do |string|
585 pdf.RDMMultiCell(190,5, "- " + string)
587 pdf.RDMMultiCell(190,5, "- " + string)
586 end
588 end
587 if journal.notes?
589 if journal.notes?
588 pdf.ln unless journal.details.empty?
590 pdf.ln unless journal.details.empty?
589 pdf.SetFontStyle('',8)
591 pdf.SetFontStyle('',8)
590 pdf.RDMwriteHTMLCell(190,5,'','',
592 pdf.RDMwriteHTMLCell(190,5,'','',
591 journal.notes.to_s, issue.attachments, "")
593 journal.notes.to_s, issue.attachments, "")
592 end
594 end
593 pdf.ln
595 pdf.ln
594 end
596 end
595 end
597 end
596
598
597 if issue.attachments.any?
599 if issue.attachments.any?
598 pdf.SetFontStyle('B',9)
600 pdf.SetFontStyle('B',9)
599 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
601 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
600 pdf.ln
602 pdf.ln
601 for attachment in issue.attachments
603 for attachment in issue.attachments
602 pdf.SetFontStyle('',8)
604 pdf.SetFontStyle('',8)
603 pdf.RDMCell(80,5, attachment.filename)
605 pdf.RDMCell(80,5, attachment.filename)
604 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
606 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
605 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
607 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
606 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
608 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
607 pdf.ln
609 pdf.ln
608 end
610 end
609 end
611 end
610 pdf.output
612 pdf.output
611 end
613 end
612
614
613 # Returns a PDF string of a set of wiki pages
615 # Returns a PDF string of a set of wiki pages
614 def wiki_pages_to_pdf(pages, project)
616 def wiki_pages_to_pdf(pages, project)
615 pdf = ITCPDF.new(current_language)
617 pdf = ITCPDF.new(current_language)
616 pdf.set_title(project.name)
618 pdf.set_title(project.name)
617 pdf.alias_nb_pages
619 pdf.alias_nb_pages
618 pdf.footer_date = format_date(Date.today)
620 pdf.footer_date = format_date(Date.today)
619 pdf.add_page
621 pdf.add_page
620 pdf.SetFontStyle('B',11)
622 pdf.SetFontStyle('B',11)
621 pdf.RDMMultiCell(190,5, project.name)
623 pdf.RDMMultiCell(190,5, project.name)
622 pdf.ln
624 pdf.ln
623 # Set resize image scale
625 # Set resize image scale
624 pdf.set_image_scale(1.6)
626 pdf.set_image_scale(1.6)
625 pdf.SetFontStyle('',9)
627 pdf.SetFontStyle('',9)
626 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
628 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
627 pdf.output
629 pdf.output
628 end
630 end
629
631
630 # Returns a PDF string of a single wiki page
632 # Returns a PDF string of a single wiki page
631 def wiki_page_to_pdf(page, project)
633 def wiki_page_to_pdf(page, project)
632 pdf = ITCPDF.new(current_language)
634 pdf = ITCPDF.new(current_language)
633 pdf.set_title("#{project} - #{page.title}")
635 pdf.set_title("#{project} - #{page.title}")
634 pdf.alias_nb_pages
636 pdf.alias_nb_pages
635 pdf.footer_date = format_date(Date.today)
637 pdf.footer_date = format_date(Date.today)
636 pdf.add_page
638 pdf.add_page
637 pdf.SetFontStyle('B',11)
639 pdf.SetFontStyle('B',11)
638 pdf.RDMMultiCell(190,5,
640 pdf.RDMMultiCell(190,5,
639 "#{project} - #{page.title} - # #{page.content.version}")
641 "#{project} - #{page.title} - # #{page.content.version}")
640 pdf.ln
642 pdf.ln
641 # Set resize image scale
643 # Set resize image scale
642 pdf.set_image_scale(1.6)
644 pdf.set_image_scale(1.6)
643 pdf.SetFontStyle('',9)
645 pdf.SetFontStyle('',9)
644 write_wiki_page(pdf, page)
646 write_wiki_page(pdf, page)
645 pdf.output
647 pdf.output
646 end
648 end
647
649
648 def write_page_hierarchy(pdf, pages, node=nil, level=0)
650 def write_page_hierarchy(pdf, pages, node=nil, level=0)
649 if pages[node]
651 if pages[node]
650 pages[node].each do |page|
652 pages[node].each do |page|
651 if @new_page
653 if @new_page
652 pdf.add_page
654 pdf.add_page
653 else
655 else
654 @new_page = true
656 @new_page = true
655 end
657 end
656 pdf.bookmark page.title, level
658 pdf.bookmark page.title, level
657 write_wiki_page(pdf, page)
659 write_wiki_page(pdf, page)
658 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
660 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
659 end
661 end
660 end
662 end
661 end
663 end
662
664
663 def write_wiki_page(pdf, page)
665 def write_wiki_page(pdf, page)
664 pdf.RDMwriteHTMLCell(190,5,'','',
666 pdf.RDMwriteHTMLCell(190,5,'','',
665 page.content.text.to_s, page.attachments, 0)
667 page.content.text.to_s, page.attachments, 0)
666 if page.attachments.any?
668 if page.attachments.any?
667 pdf.ln(5)
669 pdf.ln(5)
668 pdf.SetFontStyle('B',9)
670 pdf.SetFontStyle('B',9)
669 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
671 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
670 pdf.ln
672 pdf.ln
671 for attachment in page.attachments
673 for attachment in page.attachments
672 pdf.SetFontStyle('',8)
674 pdf.SetFontStyle('',8)
673 pdf.RDMCell(80,5, attachment.filename)
675 pdf.RDMCell(80,5, attachment.filename)
674 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
676 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
675 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
677 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
676 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
678 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
677 pdf.ln
679 pdf.ln
678 end
680 end
679 end
681 end
680 end
682 end
681
683
682 class RDMPdfEncoding
684 class RDMPdfEncoding
683 def self.rdm_from_utf8(txt, encoding)
685 def self.rdm_from_utf8(txt, encoding)
684 txt ||= ''
686 txt ||= ''
685 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
687 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
686 if txt.respond_to?(:force_encoding)
688 if txt.respond_to?(:force_encoding)
687 txt.force_encoding('ASCII-8BIT')
689 txt.force_encoding('ASCII-8BIT')
688 end
690 end
689 txt
691 txt
690 end
692 end
691
693
692 def self.attach(attachments, filename, encoding)
694 def self.attach(attachments, filename, encoding)
693 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
695 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
694 atta = nil
696 atta = nil
695 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
697 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
696 atta = Attachment.latest_attach(attachments, filename_utf8)
698 atta = Attachment.latest_attach(attachments, filename_utf8)
697 end
699 end
698 if atta && atta.readable? && atta.visible?
700 if atta && atta.readable? && atta.visible?
699 return atta
701 return atta
700 else
702 else
701 return nil
703 return nil
702 end
704 end
703 end
705 end
704 end
706 end
705 end
707 end
706 end
708 end
707 end
709 end
General Comments 0
You need to be logged in to leave comments. Login now