##// END OF EJS Templates
Fixed: zh-TW PDF export broken by new locales (#2940)....
Jean-Philippe Lang -
r2507:73eb1580ae73
parent child
Show More
@@ -1,463 +1,463
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require 'iconv'
19 19 require 'rfpdf/fpdf'
20 20 require 'rfpdf/chinese'
21 21
22 22 module Redmine
23 23 module Export
24 24 module PDF
25 25 include ActionView::Helpers::TextHelper
26 26 include ActionView::Helpers::NumberHelper
27 27
28 28 class IFPDF < FPDF
29 29 include Redmine::I18n
30 30 attr_accessor :footer_date
31 31
32 32 def initialize(lang)
33 33 super()
34 34 set_language_if_valid lang
35 case current_language.to_s
35 case current_language.to_s.downcase
36 36 when 'ja'
37 37 extend(PDF_Japanese)
38 38 AddSJISFont()
39 39 @font_for_content = 'SJIS'
40 40 @font_for_footer = 'SJIS'
41 41 when 'zh'
42 42 extend(PDF_Chinese)
43 43 AddGBFont()
44 44 @font_for_content = 'GB'
45 45 @font_for_footer = 'GB'
46 46 when 'zh-tw'
47 47 extend(PDF_Chinese)
48 48 AddBig5Font()
49 49 @font_for_content = 'Big5'
50 50 @font_for_footer = 'Big5'
51 51 else
52 52 @font_for_content = 'Arial'
53 53 @font_for_footer = 'Helvetica'
54 54 end
55 55 SetCreator(Redmine::Info.app_name)
56 56 SetFont(@font_for_content)
57 57 end
58 58
59 59 def SetFontStyle(style, size)
60 60 SetFont(@font_for_content, style, size)
61 61 end
62 62
63 63 def SetTitle(txt)
64 64 txt = begin
65 65 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
66 66 hextxt = "<FEFF" # FEFF is BOM
67 67 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
68 68 hextxt << ">"
69 69 rescue
70 70 txt
71 71 end || ''
72 72 super(txt)
73 73 end
74 74
75 75 def textstring(s)
76 76 # Format a text string
77 77 if s =~ /^</ # This means the string is hex-dumped.
78 78 return s
79 79 else
80 80 return '('+escape(s)+')'
81 81 end
82 82 end
83 83
84 84 def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
85 85 @ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
86 86 # these quotation marks are not correctly rendered in the pdf
87 87 txt = txt.gsub(/[Ò€œÒ€�]/, '"') if txt
88 88 txt = begin
89 89 # 0x5c char handling
90 90 txtar = txt.split('\\')
91 91 txtar << '' if txt[-1] == ?\\
92 92 txtar.collect {|x| @ic.iconv(x)}.join('\\').gsub(/\\/, "\\\\\\\\")
93 93 rescue
94 94 txt
95 95 end || ''
96 96 super w,h,txt,border,ln,align,fill,link
97 97 end
98 98
99 99 def Footer
100 100 SetFont(@font_for_footer, 'I', 8)
101 101 SetY(-15)
102 102 SetX(15)
103 103 Cell(0, 5, @footer_date, 0, 0, 'L')
104 104 SetY(-15)
105 105 SetX(-30)
106 106 Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
107 107 end
108 108 end
109 109
110 110 # Returns a PDF string of a list of issues
111 111 def issues_to_pdf(issues, project)
112 112 pdf = IFPDF.new(current_language)
113 113 title = project ? "#{project} - #{l(:label_issue_plural)}" : "#{l(:label_issue_plural)}"
114 114 pdf.SetTitle(title)
115 115 pdf.AliasNbPages
116 116 pdf.footer_date = format_date(Date.today)
117 117 pdf.AddPage("L")
118 118 row_height = 7
119 119
120 120 # title
121 121 pdf.SetFontStyle('B',11)
122 122 pdf.Cell(190,10, title)
123 123 pdf.Ln
124 124
125 125 # headers
126 126 pdf.SetFontStyle('B',10)
127 127 pdf.SetFillColor(230, 230, 230)
128 128 pdf.Cell(15, row_height, "#", 0, 0, 'L', 1)
129 129 pdf.Cell(30, row_height, l(:field_tracker), 0, 0, 'L', 1)
130 130 pdf.Cell(30, row_height, l(:field_status), 0, 0, 'L', 1)
131 131 pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1)
132 132 pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1)
133 133 pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1)
134 134 pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1)
135 135 pdf.Line(10, pdf.GetY, 287, pdf.GetY)
136 136 pdf.Ln
137 137 pdf.Line(10, pdf.GetY, 287, pdf.GetY)
138 138 pdf.SetY(pdf.GetY() + 1)
139 139
140 140 # rows
141 141 pdf.SetFontStyle('',9)
142 142 pdf.SetFillColor(255, 255, 255)
143 143 issues.each do |issue|
144 144 pdf.Cell(15, row_height, issue.id.to_s, 0, 0, 'L', 1)
145 145 pdf.Cell(30, row_height, issue.tracker.name, 0, 0, 'L', 1)
146 146 pdf.Cell(30, row_height, issue.status.name, 0, 0, 'L', 1)
147 147 pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1)
148 148 pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.to_s : '', 0, 0, 'L', 1)
149 149 pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1)
150 150 pdf.MultiCell(0, row_height, (project == issue.project ? issue.subject : "#{issue.project} - #{issue.subject}"))
151 151 pdf.Line(10, pdf.GetY, 287, pdf.GetY)
152 152 pdf.SetY(pdf.GetY() + 1)
153 153 end
154 154 pdf.Output
155 155 end
156 156
157 157 # Returns a PDF string of a single issue
158 158 def issue_to_pdf(issue)
159 159 pdf = IFPDF.new(current_language)
160 160 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
161 161 pdf.AliasNbPages
162 162 pdf.footer_date = format_date(Date.today)
163 163 pdf.AddPage
164 164
165 165 pdf.SetFontStyle('B',11)
166 166 pdf.Cell(190,10, "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
167 167 pdf.Ln
168 168
169 169 y0 = pdf.GetY
170 170
171 171 pdf.SetFontStyle('B',9)
172 172 pdf.Cell(35,5, l(:field_status) + ":","LT")
173 173 pdf.SetFontStyle('',9)
174 174 pdf.Cell(60,5, issue.status.to_s,"RT")
175 175 pdf.SetFontStyle('B',9)
176 176 pdf.Cell(35,5, l(:field_priority) + ":","LT")
177 177 pdf.SetFontStyle('',9)
178 178 pdf.Cell(60,5, issue.priority.to_s,"RT")
179 179 pdf.Ln
180 180
181 181 pdf.SetFontStyle('B',9)
182 182 pdf.Cell(35,5, l(:field_author) + ":","L")
183 183 pdf.SetFontStyle('',9)
184 184 pdf.Cell(60,5, issue.author.to_s,"R")
185 185 pdf.SetFontStyle('B',9)
186 186 pdf.Cell(35,5, l(:field_category) + ":","L")
187 187 pdf.SetFontStyle('',9)
188 188 pdf.Cell(60,5, issue.category.to_s,"R")
189 189 pdf.Ln
190 190
191 191 pdf.SetFontStyle('B',9)
192 192 pdf.Cell(35,5, l(:field_created_on) + ":","L")
193 193 pdf.SetFontStyle('',9)
194 194 pdf.Cell(60,5, format_date(issue.created_on),"R")
195 195 pdf.SetFontStyle('B',9)
196 196 pdf.Cell(35,5, l(:field_assigned_to) + ":","L")
197 197 pdf.SetFontStyle('',9)
198 198 pdf.Cell(60,5, issue.assigned_to.to_s,"R")
199 199 pdf.Ln
200 200
201 201 pdf.SetFontStyle('B',9)
202 202 pdf.Cell(35,5, l(:field_updated_on) + ":","LB")
203 203 pdf.SetFontStyle('',9)
204 204 pdf.Cell(60,5, format_date(issue.updated_on),"RB")
205 205 pdf.SetFontStyle('B',9)
206 206 pdf.Cell(35,5, l(:field_due_date) + ":","LB")
207 207 pdf.SetFontStyle('',9)
208 208 pdf.Cell(60,5, format_date(issue.due_date),"RB")
209 209 pdf.Ln
210 210
211 211 for custom_value in issue.custom_values
212 212 pdf.SetFontStyle('B',9)
213 213 pdf.Cell(35,5, custom_value.custom_field.name + ":","L")
214 214 pdf.SetFontStyle('',9)
215 215 pdf.MultiCell(155,5, (show_value custom_value),"R")
216 216 end
217 217
218 218 pdf.SetFontStyle('B',9)
219 219 pdf.Cell(35,5, l(:field_subject) + ":","LTB")
220 220 pdf.SetFontStyle('',9)
221 221 pdf.Cell(155,5, issue.subject,"RTB")
222 222 pdf.Ln
223 223
224 224 pdf.SetFontStyle('B',9)
225 225 pdf.Cell(35,5, l(:field_description) + ":")
226 226 pdf.SetFontStyle('',9)
227 227 pdf.MultiCell(155,5, @issue.description,"BR")
228 228
229 229 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
230 230 pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY)
231 231 pdf.Ln
232 232
233 233 if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project)
234 234 pdf.SetFontStyle('B',9)
235 235 pdf.Cell(190,5, l(:label_associated_revisions), "B")
236 236 pdf.Ln
237 237 for changeset in issue.changesets
238 238 pdf.SetFontStyle('B',8)
239 239 pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s)
240 240 pdf.Ln
241 241 unless changeset.comments.blank?
242 242 pdf.SetFontStyle('',8)
243 243 pdf.MultiCell(190,5, changeset.comments)
244 244 end
245 245 pdf.Ln
246 246 end
247 247 end
248 248
249 249 pdf.SetFontStyle('B',9)
250 250 pdf.Cell(190,5, l(:label_history), "B")
251 251 pdf.Ln
252 252 for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
253 253 pdf.SetFontStyle('B',8)
254 254 pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name)
255 255 pdf.Ln
256 256 pdf.SetFontStyle('I',8)
257 257 for detail in journal.details
258 258 pdf.Cell(190,5, "- " + show_detail(detail, true))
259 259 pdf.Ln
260 260 end
261 261 if journal.notes?
262 262 pdf.SetFontStyle('',8)
263 263 pdf.MultiCell(190,5, journal.notes)
264 264 end
265 265 pdf.Ln
266 266 end
267 267
268 268 if issue.attachments.any?
269 269 pdf.SetFontStyle('B',9)
270 270 pdf.Cell(190,5, l(:label_attachment_plural), "B")
271 271 pdf.Ln
272 272 for attachment in issue.attachments
273 273 pdf.SetFontStyle('',8)
274 274 pdf.Cell(80,5, attachment.filename)
275 275 pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
276 276 pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R")
277 277 pdf.Cell(65,5, attachment.author.name,0,0,"R")
278 278 pdf.Ln
279 279 end
280 280 end
281 281 pdf.Output
282 282 end
283 283
284 284 # Returns a PDF string of a gantt chart
285 285 def gantt_to_pdf(gantt, project)
286 286 pdf = IFPDF.new(current_language)
287 287 pdf.SetTitle("#{l(:label_gantt)} #{project}")
288 288 pdf.AliasNbPages
289 289 pdf.footer_date = format_date(Date.today)
290 290 pdf.AddPage("L")
291 291 pdf.SetFontStyle('B',12)
292 292 pdf.SetX(15)
293 293 pdf.Cell(70, 20, project.to_s)
294 294 pdf.Ln
295 295 pdf.SetFontStyle('B',9)
296 296
297 297 subject_width = 70
298 298 header_heigth = 5
299 299
300 300 headers_heigth = header_heigth
301 301 show_weeks = false
302 302 show_days = false
303 303
304 304 if gantt.months < 7
305 305 show_weeks = true
306 306 headers_heigth = 2*header_heigth
307 307 if gantt.months < 3
308 308 show_days = true
309 309 headers_heigth = 3*header_heigth
310 310 end
311 311 end
312 312
313 313 g_width = 210
314 314 zoom = (g_width) / (gantt.date_to - gantt.date_from + 1)
315 315 g_height = 120
316 316 t_height = g_height + headers_heigth
317 317
318 318 y_start = pdf.GetY
319 319
320 320 # Months headers
321 321 month_f = gantt.date_from
322 322 left = subject_width
323 323 height = header_heigth
324 324 gantt.months.times do
325 325 width = ((month_f >> 1) - month_f) * zoom
326 326 pdf.SetY(y_start)
327 327 pdf.SetX(left)
328 328 pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C")
329 329 left = left + width
330 330 month_f = month_f >> 1
331 331 end
332 332
333 333 # Weeks headers
334 334 if show_weeks
335 335 left = subject_width
336 336 height = header_heigth
337 337 if gantt.date_from.cwday == 1
338 338 # gantt.date_from is monday
339 339 week_f = gantt.date_from
340 340 else
341 341 # find next monday after gantt.date_from
342 342 week_f = gantt.date_from + (7 - gantt.date_from.cwday + 1)
343 343 width = (7 - gantt.date_from.cwday + 1) * zoom-1
344 344 pdf.SetY(y_start + header_heigth)
345 345 pdf.SetX(left)
346 346 pdf.Cell(width + 1, height, "", "LTR")
347 347 left = left + width+1
348 348 end
349 349 while week_f <= gantt.date_to
350 350 width = (week_f + 6 <= gantt.date_to) ? 7 * zoom : (gantt.date_to - week_f + 1) * zoom
351 351 pdf.SetY(y_start + header_heigth)
352 352 pdf.SetX(left)
353 353 pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C")
354 354 left = left + width
355 355 week_f = week_f+7
356 356 end
357 357 end
358 358
359 359 # Days headers
360 360 if show_days
361 361 left = subject_width
362 362 height = header_heigth
363 363 wday = gantt.date_from.cwday
364 364 pdf.SetFontStyle('B',7)
365 365 (gantt.date_to - gantt.date_from + 1).to_i.times do
366 366 width = zoom
367 367 pdf.SetY(y_start + 2 * header_heigth)
368 368 pdf.SetX(left)
369 369 pdf.Cell(width, height, day_name(wday).first, "LTR", 0, "C")
370 370 left = left + width
371 371 wday = wday + 1
372 372 wday = 1 if wday > 7
373 373 end
374 374 end
375 375
376 376 pdf.SetY(y_start)
377 377 pdf.SetX(15)
378 378 pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1)
379 379
380 380 # Tasks
381 381 top = headers_heigth + y_start
382 382 pdf.SetFontStyle('B',7)
383 383 gantt.events.each do |i|
384 384 pdf.SetY(top)
385 385 pdf.SetX(15)
386 386
387 387 if i.is_a? Issue
388 388 pdf.Cell(subject_width-15, 5, "#{i.tracker} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR")
389 389 else
390 390 pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR")
391 391 end
392 392
393 393 pdf.SetY(top)
394 394 pdf.SetX(subject_width)
395 395 pdf.Cell(g_width, 5, "", "LR")
396 396
397 397 pdf.SetY(top+1.5)
398 398
399 399 if i.is_a? Issue
400 400 i_start_date = (i.start_date >= gantt.date_from ? i.start_date : gantt.date_from )
401 401 i_end_date = (i.due_before <= gantt.date_to ? i.due_before : gantt.date_to )
402 402
403 403 i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor
404 404 i_done_date = (i_done_date <= gantt.date_from ? gantt.date_from : i_done_date )
405 405 i_done_date = (i_done_date >= gantt.date_to ? gantt.date_to : i_done_date )
406 406
407 407 i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
408 408
409 409 i_left = ((i_start_date - gantt.date_from)*zoom)
410 410 i_width = ((i_end_date - i_start_date + 1)*zoom)
411 411 d_width = ((i_done_date - i_start_date)*zoom)
412 412 l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date
413 413 l_width ||= 0
414 414
415 415 pdf.SetX(subject_width + i_left)
416 416 pdf.SetFillColor(200,200,200)
417 417 pdf.Cell(i_width, 2, "", 0, 0, "", 1)
418 418
419 419 if l_width > 0
420 420 pdf.SetY(top+1.5)
421 421 pdf.SetX(subject_width + i_left)
422 422 pdf.SetFillColor(255,100,100)
423 423 pdf.Cell(l_width, 2, "", 0, 0, "", 1)
424 424 end
425 425 if d_width > 0
426 426 pdf.SetY(top+1.5)
427 427 pdf.SetX(subject_width + i_left)
428 428 pdf.SetFillColor(100,100,255)
429 429 pdf.Cell(d_width, 2, "", 0, 0, "", 1)
430 430 end
431 431
432 432 pdf.SetY(top+1.5)
433 433 pdf.SetX(subject_width + i_left + i_width)
434 434 pdf.Cell(30, 2, "#{i.status} #{i.done_ratio}%")
435 435 else
436 436 i_left = ((i.start_date - gantt.date_from)*zoom)
437 437
438 438 pdf.SetX(subject_width + i_left)
439 439 pdf.SetFillColor(50,200,50)
440 440 pdf.Cell(2, 2, "", 0, 0, "", 1)
441 441
442 442 pdf.SetY(top+1.5)
443 443 pdf.SetX(subject_width + i_left + 3)
444 444 pdf.Cell(30, 2, "#{i.name}")
445 445 end
446 446
447 447 top = top + 5
448 448 pdf.SetDrawColor(200, 200, 200)
449 449 pdf.Line(15, top, subject_width+g_width, top)
450 450 if pdf.GetY() > 180
451 451 pdf.AddPage("L")
452 452 top = 20
453 453 pdf.Line(15, top, subject_width+g_width, top)
454 454 end
455 455 pdf.SetDrawColor(0, 0, 0)
456 456 end
457 457
458 458 pdf.Line(15, top, subject_width+g_width, top)
459 459 pdf.Output
460 460 end
461 461 end
462 462 end
463 463 end
General Comments 0
You need to be logged in to leave comments. Login now