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