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