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