##// END OF EJS Templates
pdf: expand relational issues status column width of issue pdf (#5634)...
Toshi MARUYAMA -
r7845:9dfaa562fc44
parent child
Show More
@@ -1,549 +1,549
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 require 'core/rmagick'
24 require 'core/rmagick'
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 include IssuesHelper
32
32
33 class ITCPDF < TCPDF
33 class ITCPDF < TCPDF
34 include Redmine::I18n
34 include Redmine::I18n
35 attr_accessor :footer_date
35 attr_accessor :footer_date
36
36
37 def initialize(lang)
37 def initialize(lang)
38 @@k_path_cache = Rails.root.join('tmp', 'pdf')
38 @@k_path_cache = Rails.root.join('tmp', 'pdf')
39 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
39 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
40 set_language_if_valid lang
40 set_language_if_valid lang
41 pdf_encoding = l(:general_pdf_encoding).upcase
41 pdf_encoding = l(:general_pdf_encoding).upcase
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_from_utf8(txt, l(:general_pdf_encoding))
107 RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
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, txt='', attachments=[], border=0, ln=1, fill=0)
118 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
119 @attachments = attachments
119 @attachments = attachments
120 writeHTMLCell(w, h, x, y,
120 writeHTMLCell(w, h, x, y,
121 fix_text_encoding(
121 fix_text_encoding(
122 Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
122 Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
123 border, ln, fill)
123 border, ln, fill)
124 end
124 end
125
125
126 def getImageFilename(attrname)
126 def getImageFilename(attrname)
127 # attrname: general_pdf_encoding string file/uri name
127 # attrname: general_pdf_encoding string file/uri name
128 atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
128 atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
129 if atta
129 if atta
130 return atta.diskfile
130 return atta.diskfile
131 else
131 else
132 return nil
132 return nil
133 end
133 end
134 end
134 end
135
135
136 def Footer
136 def Footer
137 SetFont(@font_for_footer, 'I', 8)
137 SetFont(@font_for_footer, 'I', 8)
138 SetY(-15)
138 SetY(-15)
139 SetX(15)
139 SetX(15)
140 RDMCell(0, 5, @footer_date, 0, 0, 'L')
140 RDMCell(0, 5, @footer_date, 0, 0, 'L')
141 SetY(-15)
141 SetY(-15)
142 SetX(-30)
142 SetX(-30)
143 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
143 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
144 end
144 end
145 end
145 end
146
146
147 # Returns a PDF string of a list of issues
147 # Returns a PDF string of a list of issues
148 def issues_to_pdf(issues, project, query)
148 def issues_to_pdf(issues, project, query)
149 pdf = ITCPDF.new(current_language)
149 pdf = ITCPDF.new(current_language)
150 title = query.new_record? ? l(:label_issue_plural) : query.name
150 title = query.new_record? ? l(:label_issue_plural) : query.name
151 title = "#{project} - #{title}" if project
151 title = "#{project} - #{title}" if project
152 pdf.SetTitle(title)
152 pdf.SetTitle(title)
153 pdf.alias_nb_pages
153 pdf.alias_nb_pages
154 pdf.footer_date = format_date(Date.today)
154 pdf.footer_date = format_date(Date.today)
155 pdf.SetAutoPageBreak(false)
155 pdf.SetAutoPageBreak(false)
156 pdf.AddPage("L")
156 pdf.AddPage("L")
157
157
158 # Landscape A4 = 210 x 297 mm
158 # Landscape A4 = 210 x 297 mm
159 page_height = 210
159 page_height = 210
160 page_width = 297
160 page_width = 297
161 right_margin = 10
161 right_margin = 10
162 bottom_margin = 20
162 bottom_margin = 20
163 col_id_width = 10
163 col_id_width = 10
164 row_height = 5
164 row_height = 5
165
165
166 # column widths
166 # column widths
167 table_width = page_width - right_margin - 10 # fixed left margin
167 table_width = page_width - right_margin - 10 # fixed left margin
168 col_width = []
168 col_width = []
169 unless query.columns.empty?
169 unless query.columns.empty?
170 col_width = query.columns.collect do |c|
170 col_width = query.columns.collect do |c|
171 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
171 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
172 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
172 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
173 end
173 end
174 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
174 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
175 col_width = col_width.collect {|w| w * ratio}
175 col_width = col_width.collect {|w| w * ratio}
176 end
176 end
177
177
178 # title
178 # title
179 pdf.SetFontStyle('B',11)
179 pdf.SetFontStyle('B',11)
180 pdf.RDMCell(190,10, title)
180 pdf.RDMCell(190,10, title)
181 pdf.Ln
181 pdf.Ln
182
182
183 # headers
183 # headers
184 pdf.SetFontStyle('B',8)
184 pdf.SetFontStyle('B',8)
185 pdf.SetFillColor(230, 230, 230)
185 pdf.SetFillColor(230, 230, 230)
186
186
187 # render it background to find the max height used
187 # render it background to find the max height used
188 base_x = pdf.GetX
188 base_x = pdf.GetX
189 base_y = pdf.GetY
189 base_y = pdf.GetY
190 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
190 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
191 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
191 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
192 pdf.SetXY(base_x, base_y);
192 pdf.SetXY(base_x, base_y);
193
193
194 # write the cells on page
194 # write the cells on page
195 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
195 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
196 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
196 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
197 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
197 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
198 pdf.SetY(base_y + max_height);
198 pdf.SetY(base_y + max_height);
199
199
200 # rows
200 # rows
201 pdf.SetFontStyle('',8)
201 pdf.SetFontStyle('',8)
202 pdf.SetFillColor(255, 255, 255)
202 pdf.SetFillColor(255, 255, 255)
203 previous_group = false
203 previous_group = false
204 issue_list(issues) do |issue, level|
204 issue_list(issues) do |issue, level|
205 if query.grouped? &&
205 if query.grouped? &&
206 (group = query.group_by_column.value(issue)) != previous_group
206 (group = query.group_by_column.value(issue)) != previous_group
207 pdf.SetFontStyle('B',9)
207 pdf.SetFontStyle('B',9)
208 pdf.RDMCell(277, row_height,
208 pdf.RDMCell(277, row_height,
209 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
209 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
210 1, 1, 'L')
210 1, 1, 'L')
211 pdf.SetFontStyle('',8)
211 pdf.SetFontStyle('',8)
212 previous_group = group
212 previous_group = group
213 end
213 end
214 # fetch all the row values
214 # fetch all the row values
215 col_values = query.columns.collect do |column|
215 col_values = query.columns.collect do |column|
216 s = if column.is_a?(QueryCustomFieldColumn)
216 s = if column.is_a?(QueryCustomFieldColumn)
217 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
217 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
218 show_value(cv)
218 show_value(cv)
219 else
219 else
220 value = issue.send(column.name)
220 value = issue.send(column.name)
221 if column.name == :subject
221 if column.name == :subject
222 value = " " * level + value
222 value = " " * level + value
223 end
223 end
224 if value.is_a?(Date)
224 if value.is_a?(Date)
225 format_date(value)
225 format_date(value)
226 elsif value.is_a?(Time)
226 elsif value.is_a?(Time)
227 format_time(value)
227 format_time(value)
228 else
228 else
229 value
229 value
230 end
230 end
231 end
231 end
232 s.to_s
232 s.to_s
233 end
233 end
234
234
235 # render it off-page to find the max height used
235 # render it off-page to find the max height used
236 base_x = pdf.GetX
236 base_x = pdf.GetX
237 base_y = pdf.GetY
237 base_y = pdf.GetY
238 pdf.SetY(2 * page_height)
238 pdf.SetY(2 * page_height)
239 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
239 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
240 pdf.SetXY(base_x, base_y)
240 pdf.SetXY(base_x, base_y)
241
241
242 # make new page if it doesn't fit on the current one
242 # make new page if it doesn't fit on the current one
243 space_left = page_height - base_y - bottom_margin
243 space_left = page_height - base_y - bottom_margin
244 if max_height > space_left
244 if max_height > space_left
245 pdf.AddPage("L")
245 pdf.AddPage("L")
246 base_x = pdf.GetX
246 base_x = pdf.GetX
247 base_y = pdf.GetY
247 base_y = pdf.GetY
248 end
248 end
249
249
250 # write the cells on page
250 # write the cells on page
251 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
251 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
252 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
252 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
253 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
253 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
254 pdf.SetY(base_y + max_height);
254 pdf.SetY(base_y + max_height);
255 end
255 end
256
256
257 if issues.size == Setting.issues_export_limit.to_i
257 if issues.size == Setting.issues_export_limit.to_i
258 pdf.SetFontStyle('B',10)
258 pdf.SetFontStyle('B',10)
259 pdf.RDMCell(0, row_height, '...')
259 pdf.RDMCell(0, row_height, '...')
260 end
260 end
261 pdf.Output
261 pdf.Output
262 end
262 end
263
263
264 # Renders MultiCells and returns the maximum height used
264 # Renders MultiCells and returns the maximum height used
265 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
265 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
266 row_height, head=false)
266 row_height, head=false)
267 base_y = pdf.GetY
267 base_y = pdf.GetY
268 max_height = row_height
268 max_height = row_height
269 col_values.each_with_index do |column, i|
269 col_values.each_with_index do |column, i|
270 col_x = pdf.GetX
270 col_x = pdf.GetX
271 if head == true
271 if head == true
272 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
272 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
273 else
273 else
274 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
274 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
275 end
275 end
276 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
276 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
277 pdf.SetXY(col_x + col_widths[i], base_y);
277 pdf.SetXY(col_x + col_widths[i], base_y);
278 end
278 end
279 return max_height
279 return max_height
280 end
280 end
281
281
282 # Draw lines to close the row (MultiCell border drawing in not uniform)
282 # Draw lines to close the row (MultiCell border drawing in not uniform)
283 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
283 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
284 id_width, col_widths)
284 id_width, col_widths)
285 col_x = top_x + id_width
285 col_x = top_x + id_width
286 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
286 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
287 col_widths.each do |width|
287 col_widths.each do |width|
288 col_x += width
288 col_x += width
289 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
289 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
290 end
290 end
291 pdf.Line(top_x, top_y, top_x, lower_y) # left border
291 pdf.Line(top_x, top_y, top_x, lower_y) # left border
292 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
292 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
293 end
293 end
294
294
295 # Returns a PDF string of a single issue
295 # Returns a PDF string of a single issue
296 def issue_to_pdf(issue)
296 def issue_to_pdf(issue)
297 pdf = ITCPDF.new(current_language)
297 pdf = ITCPDF.new(current_language)
298 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
298 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
299 pdf.alias_nb_pages
299 pdf.alias_nb_pages
300 pdf.footer_date = format_date(Date.today)
300 pdf.footer_date = format_date(Date.today)
301 pdf.AddPage
301 pdf.AddPage
302 pdf.SetFontStyle('B',11)
302 pdf.SetFontStyle('B',11)
303 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
303 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
304 pdf.RDMMultiCell(190, 5, buf)
304 pdf.RDMMultiCell(190, 5, buf)
305 pdf.Ln
305 pdf.Ln
306 pdf.SetFontStyle('',8)
306 pdf.SetFontStyle('',8)
307 base_x = pdf.GetX
307 base_x = pdf.GetX
308 i = 1
308 i = 1
309 issue.ancestors.each do |ancestor|
309 issue.ancestors.each do |ancestor|
310 pdf.SetX(base_x + i)
310 pdf.SetX(base_x + i)
311 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
311 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
312 pdf.RDMMultiCell(190 - i, 5, buf)
312 pdf.RDMMultiCell(190 - i, 5, buf)
313 i += 1 if i < 35
313 i += 1 if i < 35
314 end
314 end
315 pdf.Ln
315 pdf.Ln
316
316
317 pdf.SetFontStyle('B',9)
317 pdf.SetFontStyle('B',9)
318 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
318 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
319 pdf.SetFontStyle('',9)
319 pdf.SetFontStyle('',9)
320 pdf.RDMCell(60,5, issue.status.to_s,"RT")
320 pdf.RDMCell(60,5, issue.status.to_s,"RT")
321 pdf.SetFontStyle('B',9)
321 pdf.SetFontStyle('B',9)
322 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
322 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
323 pdf.SetFontStyle('',9)
323 pdf.SetFontStyle('',9)
324 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
324 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
325 pdf.Ln
325 pdf.Ln
326
326
327 pdf.SetFontStyle('B',9)
327 pdf.SetFontStyle('B',9)
328 pdf.RDMCell(35,5, l(:field_author) + ":","L")
328 pdf.RDMCell(35,5, l(:field_author) + ":","L")
329 pdf.SetFontStyle('',9)
329 pdf.SetFontStyle('',9)
330 pdf.RDMCell(60,5, issue.author.to_s,"R")
330 pdf.RDMCell(60,5, issue.author.to_s,"R")
331 pdf.SetFontStyle('B',9)
331 pdf.SetFontStyle('B',9)
332 pdf.RDMCell(35,5, l(:field_category) + ":","L")
332 pdf.RDMCell(35,5, l(:field_category) + ":","L")
333 pdf.SetFontStyle('',9)
333 pdf.SetFontStyle('',9)
334 pdf.RDMCell(60,5, issue.category.to_s,"R")
334 pdf.RDMCell(60,5, issue.category.to_s,"R")
335 pdf.Ln
335 pdf.Ln
336
336
337 pdf.SetFontStyle('B',9)
337 pdf.SetFontStyle('B',9)
338 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
338 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
339 pdf.SetFontStyle('',9)
339 pdf.SetFontStyle('',9)
340 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
340 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
341 pdf.SetFontStyle('B',9)
341 pdf.SetFontStyle('B',9)
342 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
342 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
343 pdf.SetFontStyle('',9)
343 pdf.SetFontStyle('',9)
344 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
344 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
345 pdf.Ln
345 pdf.Ln
346
346
347 pdf.SetFontStyle('B',9)
347 pdf.SetFontStyle('B',9)
348 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
348 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
349 pdf.SetFontStyle('',9)
349 pdf.SetFontStyle('',9)
350 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
350 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
351 pdf.SetFontStyle('B',9)
351 pdf.SetFontStyle('B',9)
352 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
352 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
353 pdf.SetFontStyle('',9)
353 pdf.SetFontStyle('',9)
354 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
354 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
355 pdf.Ln
355 pdf.Ln
356
356
357 for custom_value in issue.custom_field_values
357 for custom_value in issue.custom_field_values
358 pdf.SetFontStyle('B',9)
358 pdf.SetFontStyle('B',9)
359 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
359 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
360 pdf.SetFontStyle('',9)
360 pdf.SetFontStyle('',9)
361 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
361 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
362 end
362 end
363
363
364 y0 = pdf.GetY
364 y0 = pdf.GetY
365
365
366 pdf.SetFontStyle('B',9)
366 pdf.SetFontStyle('B',9)
367 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
367 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
368 pdf.SetFontStyle('',9)
368 pdf.SetFontStyle('',9)
369 pdf.RDMMultiCell(155,5, issue.subject,"RT")
369 pdf.RDMMultiCell(155,5, issue.subject,"RT")
370 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
370 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
371
371
372 pdf.SetFontStyle('B',9)
372 pdf.SetFontStyle('B',9)
373 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
373 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
374 pdf.SetFontStyle('',9)
374 pdf.SetFontStyle('',9)
375
375
376 # Set resize image scale
376 # Set resize image scale
377 pdf.SetImageScale(1.6)
377 pdf.SetImageScale(1.6)
378 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
378 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
379 issue.description.to_s, issue.attachments, "LRB")
379 issue.description.to_s, issue.attachments, "LRB")
380
380
381 unless issue.leaf?
381 unless issue.leaf?
382 # for CJK
382 # for CJK
383 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
383 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
384
384
385 pdf.SetFontStyle('B',9)
385 pdf.SetFontStyle('B',9)
386 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
386 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
387 pdf.Ln
387 pdf.Ln
388 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
388 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
389 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
389 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
390 :length => truncate_length)
390 :length => truncate_length)
391 level = 10 if level >= 10
391 level = 10 if level >= 10
392 pdf.SetFontStyle('',8)
392 pdf.SetFontStyle('',8)
393 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
393 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
394 pdf.SetFontStyle('B',8)
394 pdf.SetFontStyle('B',8)
395 pdf.RDMCell(20,5, child.status.to_s, "R")
395 pdf.RDMCell(20,5, child.status.to_s, "R")
396 pdf.Ln
396 pdf.Ln
397 end
397 end
398 end
398 end
399
399
400 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
400 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
401 unless relations.empty?
401 unless relations.empty?
402 # for CJK
402 # for CJK
403 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
403 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
404
404
405 pdf.SetFontStyle('B',9)
405 pdf.SetFontStyle('B',9)
406 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
406 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
407 pdf.Ln
407 pdf.Ln
408 relations.each do |relation|
408 relations.each do |relation|
409 buf = ""
409 buf = ""
410 buf += "#{l(relation.label_for(issue))} "
410 buf += "#{l(relation.label_for(issue))} "
411 if relation.delay && relation.delay != 0
411 if relation.delay && relation.delay != 0
412 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
412 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
413 end
413 end
414 if Setting.cross_project_issue_relations?
414 if Setting.cross_project_issue_relations?
415 buf += "#{relation.other_issue(issue).project} - "
415 buf += "#{relation.other_issue(issue).project} - "
416 end
416 end
417 buf += "#{relation.other_issue(issue).tracker}" +
417 buf += "#{relation.other_issue(issue).tracker}" +
418 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
418 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
419 buf = truncate(buf, :length => truncate_length)
419 buf = truncate(buf, :length => truncate_length)
420 pdf.SetFontStyle('', 8)
420 pdf.SetFontStyle('', 8)
421 pdf.RDMCell(35+155-50,5, buf, "L")
421 pdf.RDMCell(35+155-60, 5, buf, "L")
422 pdf.SetFontStyle('B',8)
422 pdf.SetFontStyle('B',8)
423 pdf.RDMCell(10,5, relation.other_issue(issue).status.to_s, "")
423 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
424 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
424 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
425 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
425 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
426 pdf.Ln
426 pdf.Ln
427 end
427 end
428 end
428 end
429 pdf.RDMCell(190,5, "", "T")
429 pdf.RDMCell(190,5, "", "T")
430 pdf.Ln
430 pdf.Ln
431
431
432 if issue.changesets.any? &&
432 if issue.changesets.any? &&
433 User.current.allowed_to?(:view_changesets, issue.project)
433 User.current.allowed_to?(:view_changesets, issue.project)
434 pdf.SetFontStyle('B',9)
434 pdf.SetFontStyle('B',9)
435 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
435 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
436 pdf.Ln
436 pdf.Ln
437 for changeset in issue.changesets
437 for changeset in issue.changesets
438 pdf.SetFontStyle('B',8)
438 pdf.SetFontStyle('B',8)
439 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
439 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
440 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
440 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
441 pdf.RDMCell(190, 5, csstr)
441 pdf.RDMCell(190, 5, csstr)
442 pdf.Ln
442 pdf.Ln
443 unless changeset.comments.blank?
443 unless changeset.comments.blank?
444 pdf.SetFontStyle('',8)
444 pdf.SetFontStyle('',8)
445 pdf.RDMwriteHTMLCell(190,5,0,0,
445 pdf.RDMwriteHTMLCell(190,5,0,0,
446 changeset.comments.to_s, issue.attachments, "")
446 changeset.comments.to_s, issue.attachments, "")
447 end
447 end
448 pdf.Ln
448 pdf.Ln
449 end
449 end
450 end
450 end
451
451
452 pdf.SetFontStyle('B',9)
452 pdf.SetFontStyle('B',9)
453 pdf.RDMCell(190,5, l(:label_history), "B")
453 pdf.RDMCell(190,5, l(:label_history), "B")
454 pdf.Ln
454 pdf.Ln
455 for journal in issue.journals.find(
455 for journal in issue.journals.find(
456 :all, :include => [:user, :details],
456 :all, :include => [:user, :details],
457 :order => "#{Journal.table_name}.created_on ASC")
457 :order => "#{Journal.table_name}.created_on ASC")
458 pdf.SetFontStyle('B',8)
458 pdf.SetFontStyle('B',8)
459 pdf.RDMCell(190,5,
459 pdf.RDMCell(190,5,
460 format_time(journal.created_on) + " - " + journal.user.name)
460 format_time(journal.created_on) + " - " + journal.user.name)
461 pdf.Ln
461 pdf.Ln
462 pdf.SetFontStyle('I',8)
462 pdf.SetFontStyle('I',8)
463 for detail in journal.details
463 for detail in journal.details
464 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
464 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true))
465 end
465 end
466 if journal.notes?
466 if journal.notes?
467 pdf.Ln unless journal.details.empty?
467 pdf.Ln unless journal.details.empty?
468 pdf.SetFontStyle('',8)
468 pdf.SetFontStyle('',8)
469 pdf.RDMwriteHTMLCell(190,5,0,0,
469 pdf.RDMwriteHTMLCell(190,5,0,0,
470 journal.notes.to_s, issue.attachments, "")
470 journal.notes.to_s, issue.attachments, "")
471 end
471 end
472 pdf.Ln
472 pdf.Ln
473 end
473 end
474
474
475 if issue.attachments.any?
475 if issue.attachments.any?
476 pdf.SetFontStyle('B',9)
476 pdf.SetFontStyle('B',9)
477 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
477 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
478 pdf.Ln
478 pdf.Ln
479 for attachment in issue.attachments
479 for attachment in issue.attachments
480 pdf.SetFontStyle('',8)
480 pdf.SetFontStyle('',8)
481 pdf.RDMCell(80,5, attachment.filename)
481 pdf.RDMCell(80,5, attachment.filename)
482 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
482 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
483 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
483 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
484 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
484 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
485 pdf.Ln
485 pdf.Ln
486 end
486 end
487 end
487 end
488 pdf.Output
488 pdf.Output
489 end
489 end
490
490
491 # Returns a PDF string of a single wiki page
491 # Returns a PDF string of a single wiki page
492 def wiki_to_pdf(page, project)
492 def wiki_to_pdf(page, project)
493 pdf = ITCPDF.new(current_language)
493 pdf = ITCPDF.new(current_language)
494 pdf.SetTitle("#{project} - #{page.title}")
494 pdf.SetTitle("#{project} - #{page.title}")
495 pdf.alias_nb_pages
495 pdf.alias_nb_pages
496 pdf.footer_date = format_date(Date.today)
496 pdf.footer_date = format_date(Date.today)
497 pdf.AddPage
497 pdf.AddPage
498 pdf.SetFontStyle('B',11)
498 pdf.SetFontStyle('B',11)
499 pdf.RDMMultiCell(190,5,
499 pdf.RDMMultiCell(190,5,
500 "#{project} - #{page.title} - # #{page.content.version}")
500 "#{project} - #{page.title} - # #{page.content.version}")
501 pdf.Ln
501 pdf.Ln
502 # Set resize image scale
502 # Set resize image scale
503 pdf.SetImageScale(1.6)
503 pdf.SetImageScale(1.6)
504 pdf.SetFontStyle('',9)
504 pdf.SetFontStyle('',9)
505 pdf.RDMwriteHTMLCell(190,5,0,0,
505 pdf.RDMwriteHTMLCell(190,5,0,0,
506 page.content.text.to_s, page.attachments, "TLRB")
506 page.content.text.to_s, page.attachments, "TLRB")
507 if page.attachments.any?
507 if page.attachments.any?
508 pdf.Ln
508 pdf.Ln
509 pdf.SetFontStyle('B',9)
509 pdf.SetFontStyle('B',9)
510 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
510 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
511 pdf.Ln
511 pdf.Ln
512 for attachment in page.attachments
512 for attachment in page.attachments
513 pdf.SetFontStyle('',8)
513 pdf.SetFontStyle('',8)
514 pdf.RDMCell(80,5, attachment.filename)
514 pdf.RDMCell(80,5, attachment.filename)
515 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
515 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
516 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
516 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
517 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
517 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
518 pdf.Ln
518 pdf.Ln
519 end
519 end
520 end
520 end
521 pdf.Output
521 pdf.Output
522 end
522 end
523
523
524 class RDMPdfEncoding
524 class RDMPdfEncoding
525 def self.rdm_from_utf8(txt, encoding)
525 def self.rdm_from_utf8(txt, encoding)
526 txt ||= ''
526 txt ||= ''
527 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
527 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
528 if txt.respond_to?(:force_encoding)
528 if txt.respond_to?(:force_encoding)
529 txt.force_encoding('ASCII-8BIT')
529 txt.force_encoding('ASCII-8BIT')
530 end
530 end
531 txt
531 txt
532 end
532 end
533
533
534 def self.attach(attachments, filename, encoding)
534 def self.attach(attachments, filename, encoding)
535 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
535 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
536 atta = nil
536 atta = nil
537 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
537 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
538 atta = Attachment.latest_attach(attachments, filename_utf8)
538 atta = Attachment.latest_attach(attachments, filename_utf8)
539 end
539 end
540 if atta && atta.readable? && atta.visible?
540 if atta && atta.readable? && atta.visible?
541 return atta
541 return atta
542 else
542 else
543 return nil
543 return nil
544 end
544 end
545 end
545 end
546 end
546 end
547 end
547 end
548 end
548 end
549 end
549 end
General Comments 0
You need to be logged in to leave comments. Login now