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