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