comparison lib/redmine/export/pdf.rb @ 1295:622f24f53b42 redmine-2.3

Update to Redmine SVN revision 11972 on 2.3-stable branch
author Chris Cannam
date Fri, 14 Jun 2013 09:02:21 +0100
parents 3e4c3460b6ca
children
comparison
equal deleted inserted replaced
1294:3e4c3460b6ca 1295:622f24f53b42
1 # encoding: utf-8 1 # encoding: utf-8
2 # 2 #
3 # Redmine - project management software 3 # Redmine - project management software
4 # Copyright (C) 2006-2012 Jean-Philippe Lang 4 # Copyright (C) 2006-2013 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.
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'
21 require 'tcpdf' 20 require 'tcpdf'
22 require 'fpdf/chinese' 21 require 'fpdf/chinese'
23 require 'fpdf/japanese' 22 require 'fpdf/japanese'
24 require 'fpdf/korean' 23 require 'fpdf/korean'
24
25 if RUBY_VERSION < '1.9'
26 require 'iconv'
27 end
25 28
26 module Redmine 29 module Redmine
27 module Export 30 module Export
28 module PDF 31 module PDF
29 include ActionView::Helpers::TextHelper 32 include ActionView::Helpers::TextHelper
84 SetFont(@font_for_content, style, size) 87 SetFont(@font_for_content, style, size)
85 end 88 end
86 89
87 def SetTitle(txt) 90 def SetTitle(txt)
88 txt = begin 91 txt = begin
89 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) 92 utf16txt = to_utf16(txt)
90 hextxt = "<FEFF" # FEFF is BOM 93 hextxt = "<FEFF" # FEFF is BOM
91 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join 94 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
92 hextxt << ">" 95 hextxt << ">"
93 rescue 96 rescue
94 txt 97 txt
112 def formatted_text(text) 115 def formatted_text(text)
113 html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) 116 html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text)
114 # Strip {{toc}} tags 117 # Strip {{toc}} tags
115 html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '') 118 html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '')
116 html 119 html
120 end
121
122 # Encodes an UTF-8 string to UTF-16BE
123 def to_utf16(str)
124 if str.respond_to?(:encode)
125 str.encode('UTF-16BE')
126 else
127 Iconv.conv('UTF-16BE', 'UTF-8', str)
128 end
117 end 129 end
118 130
119 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='') 131 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
120 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link) 132 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
121 end 133 end
158 @outlines << {:t => txt, :l => level, :p => PageNo(), :y => (@h - y)*@k} 170 @outlines << {:t => txt, :l => level, :p => PageNo(), :y => (@h - y)*@k}
159 end 171 end
160 172
161 def bookmark_title(txt) 173 def bookmark_title(txt)
162 txt = begin 174 txt = begin
163 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) 175 utf16txt = to_utf16(txt)
164 hextxt = "<FEFF" # FEFF is BOM 176 hextxt = "<FEFF" # FEFF is BOM
165 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join 177 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
166 hextxt << ">" 178 hextxt << ">"
167 rescue 179 rescue
168 txt 180 txt
366 end 378 end
367 end 379 end
368 col_width 380 col_width
369 end 381 end
370 382
371 def render_table_header(pdf, query, col_width, row_height, col_id_width, table_width) 383 def render_table_header(pdf, query, col_width, row_height, table_width)
372 # headers 384 # headers
373 pdf.SetFontStyle('B',8) 385 pdf.SetFontStyle('B',8)
374 pdf.SetFillColor(230, 230, 230) 386 pdf.SetFillColor(230, 230, 230)
375 387
376 # render it background to find the max height used 388 # render it background to find the max height used
377 base_x = pdf.GetX 389 base_x = pdf.GetX
378 base_y = pdf.GetY 390 base_y = pdf.GetY
379 max_height = issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true) 391 max_height = issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
380 pdf.Rect(base_x, base_y, table_width + col_id_width, max_height, 'FD'); 392 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
381 pdf.SetXY(base_x, base_y); 393 pdf.SetXY(base_x, base_y);
382 394
383 # write the cells on page 395 # write the cells on page
384 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
385 issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true) 396 issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
386 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) 397 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width)
387 pdf.SetY(base_y + max_height); 398 pdf.SetY(base_y + max_height);
388 399
389 # rows 400 # rows
390 pdf.SetFontStyle('',8) 401 pdf.SetFontStyle('',8)
391 pdf.SetFillColor(255, 255, 255) 402 pdf.SetFillColor(255, 255, 255)
403 pdf.AddPage("L") 414 pdf.AddPage("L")
404 415
405 # Landscape A4 = 210 x 297 mm 416 # Landscape A4 = 210 x 297 mm
406 page_height = 210 417 page_height = 210
407 page_width = 297 418 page_width = 297
419 left_margin = 10
408 right_margin = 10 420 right_margin = 10
409 bottom_margin = 20 421 bottom_margin = 20
410 col_id_width = 10
411 row_height = 4 422 row_height = 4
412 423
413 # column widths 424 # column widths
414 table_width = page_width - right_margin - 10 # fixed left margin 425 table_width = page_width - right_margin - left_margin
415 col_width = [] 426 col_width = []
416 unless query.inline_columns.empty? 427 unless query.inline_columns.empty?
417 col_width = calc_col_width(issues, query, table_width - col_id_width, pdf) 428 col_width = calc_col_width(issues, query, table_width, pdf)
418 table_width = col_width.inject(0) {|s,v| s += v} 429 table_width = col_width.inject(0) {|s,v| s += v}
419 end 430 end
420 431
421 # use full width if the description is displayed 432 # use full width if the description is displayed
422 if table_width > 0 && query.has_column?(:description) 433 if table_width > 0 && query.has_column?(:description)
423 col_width = col_width.map {|w| w = w * (page_width - right_margin - 10 - col_id_width) / table_width} 434 col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width}
424 table_width = col_width.inject(0) {|s,v| s += v} 435 table_width = col_width.inject(0) {|s,v| s += v}
425 end 436 end
426 437
427 # title 438 # title
428 pdf.SetFontStyle('B',11) 439 pdf.SetFontStyle('B',11)
429 pdf.RDMCell(190,10, title) 440 pdf.RDMCell(190,10, title)
430 pdf.Ln 441 pdf.Ln
431 render_table_header(pdf, query, col_width, row_height, col_id_width, table_width) 442 render_table_header(pdf, query, col_width, row_height, table_width)
432 previous_group = false 443 previous_group = false
433 issue_list(issues) do |issue, level| 444 issue_list(issues) do |issue, level|
434 if query.grouped? && 445 if query.grouped? &&
435 (group = query.group_by_column.value(issue)) != previous_group 446 (group = query.group_by_column.value(issue)) != previous_group
436 pdf.SetFontStyle('B',10) 447 pdf.SetFontStyle('B',10)
437 group_label = group.blank? ? 'None' : group.to_s.dup 448 group_label = group.blank? ? 'None' : group.to_s.dup
438 group_label << " (#{query.issue_count_by_group[group]})" 449 group_label << " (#{query.issue_count_by_group[group]})"
439 pdf.Bookmark group_label, 0, -1 450 pdf.Bookmark group_label, 0, -1
440 pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L') 451 pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L')
441 pdf.SetFontStyle('',8) 452 pdf.SetFontStyle('',8)
442 previous_group = group 453 previous_group = group
443 end 454 end
444 455
445 # fetch row values 456 # fetch row values
454 465
455 # make new page if it doesn't fit on the current one 466 # make new page if it doesn't fit on the current one
456 space_left = page_height - base_y - bottom_margin 467 space_left = page_height - base_y - bottom_margin
457 if max_height > space_left 468 if max_height > space_left
458 pdf.AddPage("L") 469 pdf.AddPage("L")
459 render_table_header(pdf, query, col_width, row_height, col_id_width, table_width) 470 render_table_header(pdf, query, col_width, row_height, table_width)
460 base_x = pdf.GetX 471 base_x = pdf.GetX
461 base_y = pdf.GetY 472 base_y = pdf.GetY
462 end 473 end
463 474
464 # write the cells on page 475 # write the cells on page
465 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
466 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) 476 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
467 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width) 477 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width)
468 pdf.SetY(base_y + max_height); 478 pdf.SetY(base_y + max_height);
469 479
470 if query.has_column?(:description) && issue.description? 480 if query.has_column?(:description) && issue.description?
471 pdf.SetX(10) 481 pdf.SetX(10)
472 pdf.SetAutoPageBreak(true, 20) 482 pdf.SetAutoPageBreak(true, 20)
499 end 509 end
500 return max_height 510 return max_height
501 end 511 end
502 512
503 # Draw lines to close the row (MultiCell border drawing in not uniform) 513 # Draw lines to close the row (MultiCell border drawing in not uniform)
514 #
515 # parameter "col_id_width" is not used. it is kept for compatibility.
504 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, 516 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
505 id_width, col_widths) 517 col_id_width, col_widths)
506 col_x = top_x + id_width 518 col_x = top_x
507 pdf.Line(col_x, top_y, col_x, lower_y) # id right border 519 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
508 col_widths.each do |width| 520 col_widths.each do |width|
509 col_x += width 521 col_x += width
510 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border 522 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
511 end 523 end