Mercurial > hg > soundsoftware-site
comparison lib/redmine/export/.svn/text-base/pdf.rb.svn-base @ 441:cbce1fd3b1b7 redmine-1.2
Update to Redmine 1.2-stable branch (Redmine SVN rev 6000)
author | Chris Cannam |
---|---|
date | Mon, 06 Jun 2011 14:24:13 +0100 |
parents | 0579821a129a |
children | 0c939c159af4 |
comparison
equal
deleted
inserted
replaced
245:051f544170fe | 441:cbce1fd3b1b7 |
---|---|
1 # encoding: utf-8 | 1 # encoding: utf-8 |
2 # | 2 # |
3 # Redmine - project management software | 3 # Redmine - project management software |
4 # Copyright (C) 2006-2009 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 'rfpdf/chinese' | 22 require 'fpdf/chinese' |
23 require 'fpdf/japanese' | |
24 require 'fpdf/korean' | |
23 | 25 |
24 module Redmine | 26 module Redmine |
25 module Export | 27 module Export |
26 module PDF | 28 module PDF |
27 include ActionView::Helpers::TextHelper | 29 include ActionView::Helpers::TextHelper |
28 include ActionView::Helpers::NumberHelper | 30 include ActionView::Helpers::NumberHelper |
29 | 31 |
30 class IFPDF < FPDF | 32 class ITCPDF < TCPDF |
31 include Redmine::I18n | 33 include Redmine::I18n |
32 attr_accessor :footer_date | 34 attr_accessor :footer_date |
33 | 35 |
34 def initialize(lang) | 36 def initialize(lang) |
35 super() | |
36 set_language_if_valid lang | 37 set_language_if_valid lang |
37 case current_language.to_s.downcase | 38 pdf_encoding = l(:general_pdf_encoding).upcase |
38 when 'ko' | 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) | |
43 case pdf_encoding | |
44 when 'UTF-8' | |
45 @font_for_content = 'FreeSans' | |
46 @font_for_footer = 'FreeSans' | |
47 when 'CP949' | |
39 extend(PDF_Korean) | 48 extend(PDF_Korean) |
40 AddUHCFont() | 49 AddUHCFont() |
41 @font_for_content = 'UHC' | 50 @font_for_content = 'UHC' |
42 @font_for_footer = 'UHC' | 51 @font_for_footer = 'UHC' |
43 when 'ja' | 52 when 'CP932' |
44 extend(PDF_Japanese) | 53 extend(PDF_Japanese) |
45 AddSJISFont() | 54 AddSJISFont() |
46 @font_for_content = 'SJIS' | 55 @font_for_content = 'SJIS' |
47 @font_for_footer = 'SJIS' | 56 @font_for_footer = 'SJIS' |
48 when 'zh' | 57 when 'GB18030' |
49 extend(PDF_Chinese) | 58 extend(PDF_Chinese) |
50 AddGBFont() | 59 AddGBFont() |
51 @font_for_content = 'GB' | 60 @font_for_content = 'GB' |
52 @font_for_footer = 'GB' | 61 @font_for_footer = 'GB' |
53 when 'zh-tw' | 62 when 'BIG5' |
54 extend(PDF_Chinese) | 63 extend(PDF_Chinese) |
55 AddBig5Font() | 64 AddBig5Font() |
56 @font_for_content = 'Big5' | 65 @font_for_content = 'Big5' |
57 @font_for_footer = 'Big5' | 66 @font_for_footer = 'Big5' |
58 else | 67 else |
59 @font_for_content = 'Arial' | 68 @font_for_content = 'Arial' |
60 @font_for_footer = 'Helvetica' | 69 @font_for_footer = 'Helvetica' |
61 end | 70 end |
62 SetCreator(Redmine::Info.app_name) | 71 SetCreator(Redmine::Info.app_name) |
63 SetFont(@font_for_content) | 72 SetFont(@font_for_content) |
64 end | 73 end |
65 | 74 |
66 def SetFontStyle(style, size) | 75 def SetFontStyle(style, size) |
67 SetFont(@font_for_content, style, size) | 76 SetFont(@font_for_content, style, size) |
68 end | 77 end |
69 | 78 |
70 def SetTitle(txt) | 79 def SetTitle(txt) |
71 txt = begin | 80 txt = begin |
72 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) | 81 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) |
73 hextxt = "<FEFF" # FEFF is BOM | 82 hextxt = "<FEFF" # FEFF is BOM |
74 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join | 83 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join |
76 rescue | 85 rescue |
77 txt | 86 txt |
78 end || '' | 87 end || '' |
79 super(txt) | 88 super(txt) |
80 end | 89 end |
81 | 90 |
82 def textstring(s) | 91 def textstring(s) |
83 # Format a text string | 92 # Format a text string |
84 if s =~ /^</ # This means the string is hex-dumped. | 93 if s =~ /^</ # This means the string is hex-dumped. |
85 return s | 94 return s |
86 else | 95 else |
87 return '('+escape(s)+')' | 96 return '('+escape(s)+')' |
88 end | 97 end |
89 end | 98 end |
90 | 99 |
91 def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') | 100 def fix_text_encoding(txt) |
92 @ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8') | 101 RDMPdfEncoding::rdm_pdf_iconv(@ic, txt) |
93 # these quotation marks are not correctly rendered in the pdf | 102 end |
94 txt = txt.gsub(/[“�]/, '"') if txt | 103 |
95 txt = begin | 104 def RDMCell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') |
96 # 0x5c char handling | 105 Cell(w,h,fix_text_encoding(txt),border,ln,align,fill,link) |
97 txtar = txt.split('\\') | 106 end |
98 txtar << '' if txt[-1] == ?\\ | 107 |
99 txtar.collect {|x| @ic.iconv(x)}.join('\\').gsub(/\\/, "\\\\\\\\") | 108 def RDMMultiCell(w,h=0,txt='',border=0,align='',fill=0) |
100 rescue | 109 MultiCell(w,h,fix_text_encoding(txt),border,align,fill) |
101 txt | 110 end |
102 end || '' | 111 |
103 super w,h,txt,border,ln,align,fill,link | |
104 end | |
105 | |
106 def Footer | 112 def Footer |
107 SetFont(@font_for_footer, 'I', 8) | 113 SetFont(@font_for_footer, 'I', 8) |
108 SetY(-15) | 114 SetY(-15) |
109 SetX(15) | 115 SetX(15) |
110 Cell(0, 5, @footer_date, 0, 0, 'L') | 116 RDMCell(0, 5, @footer_date, 0, 0, 'L') |
111 SetY(-15) | 117 SetY(-15) |
112 SetX(-30) | 118 SetX(-30) |
113 Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') | 119 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') |
114 end | 120 end |
115 end | 121 end |
116 | 122 |
117 # Returns a PDF string of a list of issues | 123 # Returns a PDF string of a list of issues |
118 def issues_to_pdf(issues, project, query) | 124 def issues_to_pdf(issues, project, query) |
119 pdf = IFPDF.new(current_language) | 125 pdf = ITCPDF.new(current_language) |
120 title = query.new_record? ? l(:label_issue_plural) : query.name | 126 title = query.new_record? ? l(:label_issue_plural) : query.name |
121 title = "#{project} - #{title}" if project | 127 title = "#{project} - #{title}" if project |
122 pdf.SetTitle(title) | 128 pdf.SetTitle(title) |
123 pdf.AliasNbPages | 129 pdf.alias_nb_pages |
124 pdf.footer_date = format_date(Date.today) | 130 pdf.footer_date = format_date(Date.today) |
131 pdf.SetAutoPageBreak(false) | |
125 pdf.AddPage("L") | 132 pdf.AddPage("L") |
126 | 133 |
127 row_height = 6 | 134 # Landscape A4 = 210 x 297 mm |
135 page_height = 210 | |
136 page_width = 297 | |
137 right_margin = 10 | |
138 bottom_margin = 20 | |
139 col_id_width = 10 | |
140 row_height = 5 | |
141 | |
142 # column widths | |
143 table_width = page_width - right_margin - 10 # fixed left margin | |
128 col_width = [] | 144 col_width = [] |
129 unless query.columns.empty? | 145 unless query.columns.empty? |
130 col_width = query.columns.collect {|column| column.name == :subject ? 4.0 : 1.0 } | 146 col_width = query.columns.collect do |c| |
131 ratio = 262.0 / col_width.inject(0) {|s,w| s += w} | 147 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) && ['string', 'text'].include?(c.custom_field.field_format)))? 4.0 : 1.0 |
148 end | |
149 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w} | |
132 col_width = col_width.collect {|w| w * ratio} | 150 col_width = col_width.collect {|w| w * ratio} |
133 end | 151 end |
134 | 152 |
135 # title | 153 # title |
136 pdf.SetFontStyle('B',11) | 154 pdf.SetFontStyle('B',11) |
137 pdf.Cell(190,10, title) | 155 pdf.RDMCell(190,10, title) |
138 pdf.Ln | 156 pdf.Ln |
139 | 157 |
140 # headers | 158 # headers |
141 pdf.SetFontStyle('B',8) | 159 pdf.SetFontStyle('B',8) |
142 pdf.SetFillColor(230, 230, 230) | 160 pdf.SetFillColor(230, 230, 230) |
143 pdf.Cell(15, row_height, "#", 1, 0, 'L', 1) | 161 |
144 query.columns.each_with_index do |column, i| | 162 # render it background to find the max height used |
145 pdf.Cell(col_width[i], row_height, column.caption, 1, 0, 'L', 1) | 163 base_x = pdf.GetX |
146 end | 164 base_y = pdf.GetY |
147 pdf.Ln | 165 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true) |
148 | 166 pdf.Rect(base_x, base_y, table_width, max_height, 'FD'); |
167 pdf.SetXY(base_x, base_y); | |
168 | |
169 # write the cells on page | |
170 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1) | |
171 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true) | |
172 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) | |
173 pdf.SetY(base_y + max_height); | |
174 | |
149 # rows | 175 # rows |
150 pdf.SetFontStyle('',8) | 176 pdf.SetFontStyle('',8) |
151 pdf.SetFillColor(255, 255, 255) | 177 pdf.SetFillColor(255, 255, 255) |
152 previous_group = false | 178 previous_group = false |
153 issues.each do |issue| | 179 issues.each do |issue| |
154 if query.grouped? && (group = query.group_by_column.value(issue)) != previous_group | 180 if query.grouped? && |
181 (group = query.group_by_column.value(issue)) != previous_group | |
155 pdf.SetFontStyle('B',9) | 182 pdf.SetFontStyle('B',9) |
156 pdf.Cell(277, row_height, | 183 pdf.RDMCell(277, row_height, |
157 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})", | 184 (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})", |
158 1, 1, 'L') | 185 1, 1, 'L') |
159 pdf.SetFontStyle('',8) | 186 pdf.SetFontStyle('',8) |
160 previous_group = group | 187 previous_group = group |
161 end | 188 end |
162 pdf.Cell(15, row_height, issue.id.to_s, 1, 0, 'L', 1) | 189 # fetch all the row values |
163 query.columns.each_with_index do |column, i| | 190 col_values = query.columns.collect do |column| |
164 s = if column.is_a?(QueryCustomFieldColumn) | 191 s = if column.is_a?(QueryCustomFieldColumn) |
165 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} | 192 cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} |
166 show_value(cv) | 193 show_value(cv) |
167 else | 194 else |
168 value = issue.send(column.name) | 195 value = issue.send(column.name) |
172 format_time(value) | 199 format_time(value) |
173 else | 200 else |
174 value | 201 value |
175 end | 202 end |
176 end | 203 end |
177 pdf.Cell(col_width[i], row_height, s.to_s, 1, 0, 'L', 1) | 204 s.to_s |
178 end | 205 end |
179 pdf.Ln | 206 |
180 end | 207 # render it off-page to find the max height used |
208 base_x = pdf.GetX | |
209 base_y = pdf.GetY | |
210 pdf.SetY(2 * page_height) | |
211 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) | |
212 pdf.SetXY(base_x, base_y) | |
213 | |
214 # make new page if it doesn't fit on the current one | |
215 space_left = page_height - base_y - bottom_margin | |
216 if max_height > space_left | |
217 pdf.AddPage("L") | |
218 base_x = pdf.GetX | |
219 base_y = pdf.GetY | |
220 end | |
221 | |
222 # write the cells on page | |
223 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1) | |
224 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) | |
225 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) | |
226 pdf.SetY(base_y + max_height); | |
227 end | |
228 | |
181 if issues.size == Setting.issues_export_limit.to_i | 229 if issues.size == Setting.issues_export_limit.to_i |
182 pdf.SetFontStyle('B',10) | 230 pdf.SetFontStyle('B',10) |
183 pdf.Cell(0, row_height, '...') | 231 pdf.RDMCell(0, row_height, '...') |
184 end | 232 end |
185 pdf.Output | 233 pdf.Output |
234 end | |
235 | |
236 # Renders MultiCells and returns the maximum height used | |
237 def issues_to_pdf_write_cells(pdf, col_values, col_widths, | |
238 row_height, head=false) | |
239 base_y = pdf.GetY | |
240 max_height = row_height | |
241 col_values.each_with_index do |column, i| | |
242 col_x = pdf.GetX | |
243 if head == true | |
244 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1) | |
245 else | |
246 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1) | |
247 end | |
248 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height | |
249 pdf.SetXY(col_x + col_widths[i], base_y); | |
250 end | |
251 return max_height | |
252 end | |
253 | |
254 # Draw lines to close the row (MultiCell border drawing in not uniform) | |
255 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, | |
256 id_width, col_widths) | |
257 col_x = top_x + id_width | |
258 pdf.Line(col_x, top_y, col_x, lower_y) # id right border | |
259 col_widths.each do |width| | |
260 col_x += width | |
261 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border | |
262 end | |
263 pdf.Line(top_x, top_y, top_x, lower_y) # left border | |
264 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border | |
186 end | 265 end |
187 | 266 |
188 # Returns a PDF string of a single issue | 267 # Returns a PDF string of a single issue |
189 def issue_to_pdf(issue) | 268 def issue_to_pdf(issue) |
190 pdf = IFPDF.new(current_language) | 269 pdf = ITCPDF.new(current_language) |
191 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}") | 270 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}") |
192 pdf.AliasNbPages | 271 pdf.alias_nb_pages |
193 pdf.footer_date = format_date(Date.today) | 272 pdf.footer_date = format_date(Date.today) |
194 pdf.AddPage | 273 pdf.AddPage |
195 | 274 pdf.SetFontStyle('B',11) |
196 pdf.SetFontStyle('B',11) | 275 pdf.RDMMultiCell(190,5, |
197 pdf.Cell(190,10, "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}") | 276 "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}") |
198 pdf.Ln | 277 pdf.Ln |
199 | 278 |
200 y0 = pdf.GetY | 279 y0 = pdf.GetY |
201 | 280 |
202 pdf.SetFontStyle('B',9) | 281 pdf.SetFontStyle('B',9) |
203 pdf.Cell(35,5, l(:field_status) + ":","LT") | 282 pdf.RDMCell(35,5, l(:field_status) + ":","LT") |
204 pdf.SetFontStyle('',9) | 283 pdf.SetFontStyle('',9) |
205 pdf.Cell(60,5, issue.status.to_s,"RT") | 284 pdf.RDMCell(60,5, issue.status.to_s,"RT") |
206 pdf.SetFontStyle('B',9) | 285 pdf.SetFontStyle('B',9) |
207 pdf.Cell(35,5, l(:field_priority) + ":","LT") | 286 pdf.RDMCell(35,5, l(:field_priority) + ":","LT") |
208 pdf.SetFontStyle('',9) | 287 pdf.SetFontStyle('',9) |
209 pdf.Cell(60,5, issue.priority.to_s,"RT") | 288 pdf.RDMCell(60,5, issue.priority.to_s,"RT") |
210 pdf.Ln | 289 pdf.Ln |
211 | 290 |
212 pdf.SetFontStyle('B',9) | 291 pdf.SetFontStyle('B',9) |
213 pdf.Cell(35,5, l(:field_author) + ":","L") | 292 pdf.RDMCell(35,5, l(:field_author) + ":","L") |
214 pdf.SetFontStyle('',9) | 293 pdf.SetFontStyle('',9) |
215 pdf.Cell(60,5, issue.author.to_s,"R") | 294 pdf.RDMCell(60,5, issue.author.to_s,"R") |
216 pdf.SetFontStyle('B',9) | 295 pdf.SetFontStyle('B',9) |
217 pdf.Cell(35,5, l(:field_category) + ":","L") | 296 pdf.RDMCell(35,5, l(:field_category) + ":","L") |
218 pdf.SetFontStyle('',9) | 297 pdf.SetFontStyle('',9) |
219 pdf.Cell(60,5, issue.category.to_s,"R") | 298 pdf.RDMCell(60,5, issue.category.to_s,"R") |
220 pdf.Ln | 299 pdf.Ln |
221 | 300 |
222 pdf.SetFontStyle('B',9) | 301 pdf.SetFontStyle('B',9) |
223 pdf.Cell(35,5, l(:field_created_on) + ":","L") | 302 pdf.RDMCell(35,5, l(:field_created_on) + ":","L") |
224 pdf.SetFontStyle('',9) | 303 pdf.SetFontStyle('',9) |
225 pdf.Cell(60,5, format_date(issue.created_on),"R") | 304 pdf.RDMCell(60,5, format_date(issue.created_on),"R") |
226 pdf.SetFontStyle('B',9) | 305 pdf.SetFontStyle('B',9) |
227 pdf.Cell(35,5, l(:field_assigned_to) + ":","L") | 306 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L") |
228 pdf.SetFontStyle('',9) | 307 pdf.SetFontStyle('',9) |
229 pdf.Cell(60,5, issue.assigned_to.to_s,"R") | 308 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R") |
230 pdf.Ln | 309 pdf.Ln |
231 | 310 |
232 pdf.SetFontStyle('B',9) | 311 pdf.SetFontStyle('B',9) |
233 pdf.Cell(35,5, l(:field_updated_on) + ":","LB") | 312 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB") |
234 pdf.SetFontStyle('',9) | 313 pdf.SetFontStyle('',9) |
235 pdf.Cell(60,5, format_date(issue.updated_on),"RB") | 314 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB") |
236 pdf.SetFontStyle('B',9) | 315 pdf.SetFontStyle('B',9) |
237 pdf.Cell(35,5, l(:field_due_date) + ":","LB") | 316 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB") |
238 pdf.SetFontStyle('',9) | 317 pdf.SetFontStyle('',9) |
239 pdf.Cell(60,5, format_date(issue.due_date),"RB") | 318 pdf.RDMCell(60,5, format_date(issue.due_date),"RB") |
240 pdf.Ln | 319 pdf.Ln |
241 | 320 |
242 for custom_value in issue.custom_field_values | 321 for custom_value in issue.custom_field_values |
243 pdf.SetFontStyle('B',9) | 322 pdf.SetFontStyle('B',9) |
244 pdf.Cell(35,5, custom_value.custom_field.name + ":","L") | 323 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L") |
245 pdf.SetFontStyle('',9) | 324 pdf.SetFontStyle('',9) |
246 pdf.MultiCell(155,5, (show_value custom_value),"R") | 325 pdf.RDMMultiCell(155,5, (show_value custom_value),"R") |
247 end | 326 end |
248 | 327 |
249 pdf.SetFontStyle('B',9) | 328 pdf.SetFontStyle('B',9) |
250 pdf.Cell(35,5, l(:field_subject) + ":","LTB") | 329 pdf.RDMCell(35,5, l(:field_subject) + ":","LT") |
251 pdf.SetFontStyle('',9) | 330 pdf.SetFontStyle('',9) |
252 pdf.Cell(155,5, issue.subject,"RTB") | 331 pdf.RDMMultiCell(155,5, issue.subject,"RT") |
253 pdf.Ln | 332 |
254 | 333 pdf.SetFontStyle('B',9) |
255 pdf.SetFontStyle('B',9) | 334 pdf.RDMCell(35,5, l(:field_description) + ":","LT") |
256 pdf.Cell(35,5, l(:field_description) + ":") | 335 pdf.SetFontStyle('',9) |
257 pdf.SetFontStyle('',9) | 336 pdf.RDMMultiCell(155,5, issue.description.to_s,"RT") |
258 pdf.MultiCell(155,5, issue.description.to_s,"BR") | 337 |
259 | |
260 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) | 338 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) |
261 pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY) | 339 pdf.Line(pdf.GetX, pdf.GetY, pdf.GetX + 190, pdf.GetY) |
262 pdf.Ln | 340 pdf.Ln |
263 | 341 |
264 if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project) | 342 if issue.changesets.any? && |
343 User.current.allowed_to?(:view_changesets, issue.project) | |
265 pdf.SetFontStyle('B',9) | 344 pdf.SetFontStyle('B',9) |
266 pdf.Cell(190,5, l(:label_associated_revisions), "B") | 345 pdf.RDMCell(190,5, l(:label_associated_revisions), "B") |
267 pdf.Ln | 346 pdf.Ln |
268 for changeset in issue.changesets | 347 for changeset in issue.changesets |
269 pdf.SetFontStyle('B',8) | 348 pdf.SetFontStyle('B',8) |
270 pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s) | 349 pdf.RDMCell(190,5, |
350 format_time(changeset.committed_on) + " - " + changeset.author.to_s) | |
271 pdf.Ln | 351 pdf.Ln |
272 unless changeset.comments.blank? | 352 unless changeset.comments.blank? |
273 pdf.SetFontStyle('',8) | 353 pdf.SetFontStyle('',8) |
274 pdf.MultiCell(190,5, changeset.comments.to_s) | 354 pdf.RDMMultiCell(190,5, changeset.comments.to_s) |
275 end | 355 end |
276 pdf.Ln | 356 pdf.Ln |
277 end | 357 end |
278 end | 358 end |
279 | 359 |
280 pdf.SetFontStyle('B',9) | 360 pdf.SetFontStyle('B',9) |
281 pdf.Cell(190,5, l(:label_history), "B") | 361 pdf.RDMCell(190,5, l(:label_history), "B") |
282 pdf.Ln | 362 pdf.Ln |
283 for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") | 363 for journal in issue.journals.find( |
364 :all, :include => [:user, :details], | |
365 :order => "#{Journal.table_name}.created_on ASC") | |
284 pdf.SetFontStyle('B',8) | 366 pdf.SetFontStyle('B',8) |
285 pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) | 367 pdf.RDMCell(190,5, |
368 format_time(journal.created_on) + " - " + journal.user.name) | |
286 pdf.Ln | 369 pdf.Ln |
287 pdf.SetFontStyle('I',8) | 370 pdf.SetFontStyle('I',8) |
288 for detail in journal.details | 371 for detail in journal.details |
289 pdf.Cell(190,5, "- " + show_detail(detail, true)) | 372 pdf.RDMMultiCell(190,5, "- " + show_detail(detail, true)) |
290 pdf.Ln | |
291 end | 373 end |
292 if journal.notes? | 374 if journal.notes? |
375 pdf.Ln unless journal.details.empty? | |
293 pdf.SetFontStyle('',8) | 376 pdf.SetFontStyle('',8) |
294 pdf.MultiCell(190,5, journal.notes.to_s) | 377 pdf.RDMMultiCell(190,5, journal.notes.to_s) |
295 end | 378 end |
296 pdf.Ln | 379 pdf.Ln |
297 end | 380 end |
298 | 381 |
299 if issue.attachments.any? | 382 if issue.attachments.any? |
300 pdf.SetFontStyle('B',9) | 383 pdf.SetFontStyle('B',9) |
301 pdf.Cell(190,5, l(:label_attachment_plural), "B") | 384 pdf.RDMCell(190,5, l(:label_attachment_plural), "B") |
302 pdf.Ln | 385 pdf.Ln |
303 for attachment in issue.attachments | 386 for attachment in issue.attachments |
304 pdf.SetFontStyle('',8) | 387 pdf.SetFontStyle('',8) |
305 pdf.Cell(80,5, attachment.filename) | 388 pdf.RDMCell(80,5, attachment.filename) |
306 pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R") | 389 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R") |
307 pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R") | 390 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R") |
308 pdf.Cell(65,5, attachment.author.name,0,0,"R") | 391 pdf.RDMCell(65,5, attachment.author.name,0,0,"R") |
309 pdf.Ln | 392 pdf.Ln |
310 end | 393 end |
311 end | 394 end |
312 pdf.Output | 395 pdf.Output |
313 end | 396 end |
314 | 397 |
398 class RDMPdfEncoding | |
399 include Redmine::I18n | |
400 def self.rdm_pdf_iconv(ic, txt) | |
401 txt ||= '' | |
402 if txt.respond_to?(:force_encoding) | |
403 txt.force_encoding('UTF-8') | |
404 if l(:general_pdf_encoding).upcase != 'UTF-8' | |
405 txt = txt.encode(l(:general_pdf_encoding), :invalid => :replace, | |
406 :undef => :replace, :replace => '?') | |
407 else | |
408 txt = Redmine::CodesetUtil.replace_invalid_utf8(txt) | |
409 end | |
410 txt.force_encoding('ASCII-8BIT') | |
411 else | |
412 ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8') | |
413 txtar = "" | |
414 begin | |
415 txtar += ic.iconv(txt) | |
416 rescue Iconv::IllegalSequence | |
417 txtar += $!.success | |
418 txt = '?' + $!.failed[1,$!.failed.length] | |
419 retry | |
420 rescue | |
421 txtar += $!.success | |
422 end | |
423 txt = txtar | |
424 end | |
425 txt | |
426 end | |
427 end | |
315 end | 428 end |
316 end | 429 end |
317 end | 430 end |