##// END OF EJS Templates
pdf: lib: add a method to export wiki (#401)...
Toshi MARUYAMA -
r7620:1713432ab009
parent child
Show More
@@ -1,452 +1,486
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
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 issues.each do |issue|
189 issues.each do |issue|
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 value.is_a?(Date)
206 if value.is_a?(Date)
207 format_date(value)
207 format_date(value)
208 elsif value.is_a?(Time)
208 elsif value.is_a?(Time)
209 format_time(value)
209 format_time(value)
210 else
210 else
211 value
211 value
212 end
212 end
213 end
213 end
214 s.to_s
214 s.to_s
215 end
215 end
216
216
217 # render it off-page to find the max height used
217 # render it off-page to find the max height used
218 base_x = pdf.GetX
218 base_x = pdf.GetX
219 base_y = pdf.GetY
219 base_y = pdf.GetY
220 pdf.SetY(2 * page_height)
220 pdf.SetY(2 * page_height)
221 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
221 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
222 pdf.SetXY(base_x, base_y)
222 pdf.SetXY(base_x, base_y)
223
223
224 # make new page if it doesn't fit on the current one
224 # make new page if it doesn't fit on the current one
225 space_left = page_height - base_y - bottom_margin
225 space_left = page_height - base_y - bottom_margin
226 if max_height > space_left
226 if max_height > space_left
227 pdf.AddPage("L")
227 pdf.AddPage("L")
228 base_x = pdf.GetX
228 base_x = pdf.GetX
229 base_y = pdf.GetY
229 base_y = pdf.GetY
230 end
230 end
231
231
232 # write the cells on page
232 # write the cells on page
233 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
233 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)
234 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)
235 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);
236 pdf.SetY(base_y + max_height);
237 end
237 end
238
238
239 if issues.size == Setting.issues_export_limit.to_i
239 if issues.size == Setting.issues_export_limit.to_i
240 pdf.SetFontStyle('B',10)
240 pdf.SetFontStyle('B',10)
241 pdf.RDMCell(0, row_height, '...')
241 pdf.RDMCell(0, row_height, '...')
242 end
242 end
243 pdf.Output
243 pdf.Output
244 end
244 end
245
245
246 # Renders MultiCells and returns the maximum height used
246 # Renders MultiCells and returns the maximum height used
247 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
247 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
248 row_height, head=false)
248 row_height, head=false)
249 base_y = pdf.GetY
249 base_y = pdf.GetY
250 max_height = row_height
250 max_height = row_height
251 col_values.each_with_index do |column, i|
251 col_values.each_with_index do |column, i|
252 col_x = pdf.GetX
252 col_x = pdf.GetX
253 if head == true
253 if head == true
254 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
254 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
255 else
255 else
256 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
256 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
257 end
257 end
258 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
258 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
259 pdf.SetXY(col_x + col_widths[i], base_y);
259 pdf.SetXY(col_x + col_widths[i], base_y);
260 end
260 end
261 return max_height
261 return max_height
262 end
262 end
263
263
264 # Draw lines to close the row (MultiCell border drawing in not uniform)
264 # 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,
265 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
266 id_width, col_widths)
266 id_width, col_widths)
267 col_x = top_x + id_width
267 col_x = top_x + id_width
268 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
268 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
269 col_widths.each do |width|
269 col_widths.each do |width|
270 col_x += width
270 col_x += width
271 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
271 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
272 end
272 end
273 pdf.Line(top_x, top_y, top_x, lower_y) # left border
273 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
274 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
275 end
275 end
276
276
277 # Returns a PDF string of a single issue
277 # Returns a PDF string of a single issue
278 def issue_to_pdf(issue)
278 def issue_to_pdf(issue)
279 pdf = ITCPDF.new(current_language)
279 pdf = ITCPDF.new(current_language)
280 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
280 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
281 pdf.alias_nb_pages
281 pdf.alias_nb_pages
282 pdf.footer_date = format_date(Date.today)
282 pdf.footer_date = format_date(Date.today)
283 pdf.AddPage
283 pdf.AddPage
284 pdf.SetFontStyle('B',11)
284 pdf.SetFontStyle('B',11)
285 pdf.RDMMultiCell(190,5,
285 pdf.RDMMultiCell(190,5,
286 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
286 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
287 pdf.Ln
287 pdf.Ln
288
288
289 pdf.SetFontStyle('B',9)
289 pdf.SetFontStyle('B',9)
290 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
290 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
291 pdf.SetFontStyle('',9)
291 pdf.SetFontStyle('',9)
292 pdf.RDMCell(60,5, issue.status.to_s,"RT")
292 pdf.RDMCell(60,5, issue.status.to_s,"RT")
293 pdf.SetFontStyle('B',9)
293 pdf.SetFontStyle('B',9)
294 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
294 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
295 pdf.SetFontStyle('',9)
295 pdf.SetFontStyle('',9)
296 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
296 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
297 pdf.Ln
297 pdf.Ln
298
298
299 pdf.SetFontStyle('B',9)
299 pdf.SetFontStyle('B',9)
300 pdf.RDMCell(35,5, l(:field_author) + ":","L")
300 pdf.RDMCell(35,5, l(:field_author) + ":","L")
301 pdf.SetFontStyle('',9)
301 pdf.SetFontStyle('',9)
302 pdf.RDMCell(60,5, issue.author.to_s,"R")
302 pdf.RDMCell(60,5, issue.author.to_s,"R")
303 pdf.SetFontStyle('B',9)
303 pdf.SetFontStyle('B',9)
304 pdf.RDMCell(35,5, l(:field_category) + ":","L")
304 pdf.RDMCell(35,5, l(:field_category) + ":","L")
305 pdf.SetFontStyle('',9)
305 pdf.SetFontStyle('',9)
306 pdf.RDMCell(60,5, issue.category.to_s,"R")
306 pdf.RDMCell(60,5, issue.category.to_s,"R")
307 pdf.Ln
307 pdf.Ln
308
308
309 pdf.SetFontStyle('B',9)
309 pdf.SetFontStyle('B',9)
310 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
310 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
311 pdf.SetFontStyle('',9)
311 pdf.SetFontStyle('',9)
312 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
312 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
313 pdf.SetFontStyle('B',9)
313 pdf.SetFontStyle('B',9)
314 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
314 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
315 pdf.SetFontStyle('',9)
315 pdf.SetFontStyle('',9)
316 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
316 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
317 pdf.Ln
317 pdf.Ln
318
318
319 pdf.SetFontStyle('B',9)
319 pdf.SetFontStyle('B',9)
320 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
320 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
321 pdf.SetFontStyle('',9)
321 pdf.SetFontStyle('',9)
322 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
322 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
323 pdf.SetFontStyle('B',9)
323 pdf.SetFontStyle('B',9)
324 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
324 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
325 pdf.SetFontStyle('',9)
325 pdf.SetFontStyle('',9)
326 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
326 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
327 pdf.Ln
327 pdf.Ln
328
328
329 for custom_value in issue.custom_field_values
329 for custom_value in issue.custom_field_values
330 pdf.SetFontStyle('B',9)
330 pdf.SetFontStyle('B',9)
331 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
331 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
332 pdf.SetFontStyle('',9)
332 pdf.SetFontStyle('',9)
333 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
333 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
334 end
334 end
335
335
336 y0 = pdf.GetY
336 y0 = pdf.GetY
337
337
338 pdf.SetFontStyle('B',9)
338 pdf.SetFontStyle('B',9)
339 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
339 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
340 pdf.SetFontStyle('',9)
340 pdf.SetFontStyle('',9)
341 pdf.RDMMultiCell(155,5, issue.subject,"RT")
341 pdf.RDMMultiCell(155,5, issue.subject,"RT")
342 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
342 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
343
343
344 pdf.SetFontStyle('B',9)
344 pdf.SetFontStyle('B',9)
345 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
345 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
346 pdf.SetFontStyle('',9)
346 pdf.SetFontStyle('',9)
347 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
347 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
348 Redmine::WikiFormatting.to_html(
348 Redmine::WikiFormatting.to_html(
349 Setting.text_formatting, issue.description.to_s),"LRB")
349 Setting.text_formatting, issue.description.to_s),"LRB")
350 pdf.Ln
350 pdf.Ln
351
351
352 if issue.changesets.any? &&
352 if issue.changesets.any? &&
353 User.current.allowed_to?(:view_changesets, issue.project)
353 User.current.allowed_to?(:view_changesets, issue.project)
354 pdf.SetFontStyle('B',9)
354 pdf.SetFontStyle('B',9)
355 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
355 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
356 pdf.Ln
356 pdf.Ln
357 for changeset in issue.changesets
357 for changeset in issue.changesets
358 pdf.SetFontStyle('B',8)
358 pdf.SetFontStyle('B',8)
359 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
359 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
360 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
360 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
361 pdf.RDMCell(190, 5, csstr)
361 pdf.RDMCell(190, 5, csstr)
362 pdf.Ln
362 pdf.Ln
363 unless changeset.comments.blank?
363 unless changeset.comments.blank?
364 pdf.SetFontStyle('',8)
364 pdf.SetFontStyle('',8)
365 pdf.RDMwriteHTMLCell(190,5,0,0,
365 pdf.RDMwriteHTMLCell(190,5,0,0,
366 Redmine::WikiFormatting.to_html(
366 Redmine::WikiFormatting.to_html(
367 Setting.text_formatting, changeset.comments.to_s), "")
367 Setting.text_formatting, changeset.comments.to_s), "")
368 end
368 end
369 pdf.Ln
369 pdf.Ln
370 end
370 end
371 end
371 end
372
372
373 pdf.SetFontStyle('B',9)
373 pdf.SetFontStyle('B',9)
374 pdf.RDMCell(190,5, l(:label_history), "B")
374 pdf.RDMCell(190,5, l(:label_history), "B")
375 pdf.Ln
375 pdf.Ln
376 for journal in issue.journals.find(
376 for journal in issue.journals.find(
377 :all, :include => [:user, :details],
377 :all, :include => [:user, :details],
378 :order => "#{Journal.table_name}.created_on ASC")
378 :order => "#{Journal.table_name}.created_on ASC")
379 pdf.SetFontStyle('B',8)
379 pdf.SetFontStyle('B',8)
380 pdf.RDMCell(190,5,
380 pdf.RDMCell(190,5,
381 format_time(journal.created_on) + " - " + journal.user.name)
381 format_time(journal.created_on) + " - " + journal.user.name)
382 pdf.Ln
382 pdf.Ln
383 pdf.SetFontStyle('I',8)
383 pdf.SetFontStyle('I',8)
384 for detail in journal.details
384 for detail in journal.details
385 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
385 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
386 end
386 end
387 if journal.notes?
387 if journal.notes?
388 pdf.Ln unless journal.details.empty?
388 pdf.Ln unless journal.details.empty?
389 pdf.SetFontStyle('',8)
389 pdf.SetFontStyle('',8)
390 pdf.RDMwriteHTMLCell(190,5,0,0,
390 pdf.RDMwriteHTMLCell(190,5,0,0,
391 Redmine::WikiFormatting.to_html(
391 Redmine::WikiFormatting.to_html(
392 Setting.text_formatting, journal.notes.to_s), "")
392 Setting.text_formatting, journal.notes.to_s), "")
393 end
393 end
394 pdf.Ln
394 pdf.Ln
395 end
395 end
396
396
397 if issue.attachments.any?
397 if issue.attachments.any?
398 pdf.SetFontStyle('B',9)
398 pdf.SetFontStyle('B',9)
399 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
399 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
400 pdf.Ln
400 pdf.Ln
401 for attachment in issue.attachments
401 for attachment in issue.attachments
402 pdf.SetFontStyle('',8)
402 pdf.SetFontStyle('',8)
403 pdf.RDMCell(80,5, attachment.filename)
403 pdf.RDMCell(80,5, attachment.filename)
404 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
404 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")
405 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
406 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
406 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
407 pdf.Ln
407 pdf.Ln
408 end
408 end
409 end
409 end
410 pdf.Output
410 pdf.Output
411 end
411 end
412
412
413 # Returns a PDF string of a single wiki page
414 def wiki_to_pdf(page, project)
415 pdf = ITCPDF.new(current_language)
416 pdf.SetTitle("#{project} - #{page.title}")
417 pdf.alias_nb_pages
418 pdf.footer_date = format_date(Date.today)
419 pdf.AddPage
420 pdf.SetFontStyle('B',11)
421 pdf.RDMMultiCell(190,5,
422 "#{project} - #{page.title} - # #{page.content.version}")
423 pdf.Ln
424 # Set resize image scale
425 pdf.SetImageScale(1.6)
426 pdf.SetFontStyle('',9)
427 pdf.RDMwriteHTMLCell(190,5,0,0,
428 Redmine::WikiFormatting.to_html(
429 Setting.text_formatting, page.content.text.to_s), "TLRB")
430 if page.attachments.any?
431 pdf.Ln
432 pdf.SetFontStyle('B',9)
433 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
434 pdf.Ln
435 for attachment in page.attachments
436 pdf.SetFontStyle('',8)
437 pdf.RDMCell(80,5, attachment.filename)
438 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")
440 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
441 pdf.Ln
442 end
443 end
444 pdf.Output
445 end
446
413 class RDMPdfEncoding
447 class RDMPdfEncoding
414 include Redmine::I18n
448 include Redmine::I18n
415 def self.rdm_pdf_iconv(ic, txt)
449 def self.rdm_pdf_iconv(ic, txt)
416 txt ||= ''
450 txt ||= ''
417 if txt.respond_to?(:force_encoding)
451 if txt.respond_to?(:force_encoding)
418 txt.force_encoding('UTF-8')
452 txt.force_encoding('UTF-8')
419 if l(:general_pdf_encoding).upcase != 'UTF-8'
453 if l(:general_pdf_encoding).upcase != 'UTF-8'
420 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
454 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace,
421 :undef => :replace, :replace => '?')
455 :undef => :replace, :replace => '?')
422 else
456 else
423 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
457 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt)
424 end
458 end
425 txt.force_encoding('ASCII-8BIT')
459 txt.force_encoding('ASCII-8BIT')
426 elsif RUBY_PLATFORM == 'java'
460 elsif RUBY_PLATFORM == 'java'
427 begin
461 begin
428 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
462 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
429 txt = ic.iconv(txt)
463 txt = ic.iconv(txt)
430 rescue
464 rescue
431 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
465 txt = txt.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
432 end
466 end
433 else
467 else
434 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
468 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
435 txtar = ""
469 txtar = ""
436 begin
470 begin
437 txtar += ic.iconv(txt)
471 txtar += ic.iconv(txt)
438 rescue Iconv::IllegalSequence
472 rescue Iconv::IllegalSequence
439 txtar += $!.success
473 txtar += $!.success
440 txt = '?' + $!.failed[1,$!.failed.length]
474 txt = '?' + $!.failed[1,$!.failed.length]
441 retry
475 retry
442 rescue
476 rescue
443 txtar += $!.success
477 txtar += $!.success
444 end
478 end
445 txt = txtar
479 txt = txtar
446 end
480 end
447 txt
481 txt
448 end
482 end
449 end
483 end
450 end
484 end
451 end
485 end
452 end
486 end
General Comments 0
You need to be logged in to leave comments. Login now