Chris@0: # encoding: utf-8 Chris@0: # Chris@0: # Redmine - project management software Chris@0: # Copyright (C) 2006-2009 Jean-Philippe Lang Chris@0: # Chris@0: # This program is free software; you can redistribute it and/or Chris@0: # modify it under the terms of the GNU General Public License Chris@0: # as published by the Free Software Foundation; either version 2 Chris@0: # of the License, or (at your option) any later version. Chris@0: # Chris@0: # This program is distributed in the hope that it will be useful, Chris@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: # GNU General Public License for more details. Chris@0: # Chris@0: # You should have received a copy of the GNU General Public License Chris@0: # along with this program; if not, write to the Free Software Chris@0: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@0: Chris@0: require 'iconv' Chris@0: require 'rfpdf/fpdf' Chris@0: require 'rfpdf/chinese' Chris@0: Chris@0: module Redmine Chris@0: module Export Chris@0: module PDF Chris@0: include ActionView::Helpers::TextHelper Chris@0: include ActionView::Helpers::NumberHelper Chris@0: Chris@0: class IFPDF < FPDF Chris@0: include Redmine::I18n Chris@0: attr_accessor :footer_date Chris@0: Chris@0: def initialize(lang) Chris@0: super() Chris@0: set_language_if_valid lang Chris@0: case current_language.to_s.downcase Chris@0: when 'ko' Chris@0: extend(PDF_Korean) Chris@0: AddUHCFont() Chris@0: @font_for_content = 'UHC' Chris@0: @font_for_footer = 'UHC' Chris@0: when 'ja' Chris@0: extend(PDF_Japanese) Chris@0: AddSJISFont() Chris@0: @font_for_content = 'SJIS' Chris@0: @font_for_footer = 'SJIS' Chris@0: when 'zh' Chris@0: extend(PDF_Chinese) Chris@0: AddGBFont() Chris@0: @font_for_content = 'GB' Chris@0: @font_for_footer = 'GB' Chris@0: when 'zh-tw' Chris@0: extend(PDF_Chinese) Chris@0: AddBig5Font() Chris@0: @font_for_content = 'Big5' Chris@0: @font_for_footer = 'Big5' Chris@0: else Chris@0: @font_for_content = 'Arial' Chris@0: @font_for_footer = 'Helvetica' Chris@0: end Chris@0: SetCreator(Redmine::Info.app_name) Chris@0: SetFont(@font_for_content) Chris@0: end Chris@0: Chris@0: def SetFontStyle(style, size) Chris@0: SetFont(@font_for_content, style, size) Chris@0: end Chris@0: Chris@0: def SetTitle(txt) Chris@0: txt = begin Chris@0: utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) Chris@0: hextxt = "" Chris@0: rescue Chris@0: txt Chris@0: end || '' Chris@0: super(txt) Chris@0: end Chris@0: Chris@0: def textstring(s) Chris@0: # Format a text string Chris@0: if s =~ /^ [:user, :details], :order => "#{Journal.table_name}.created_on ASC") Chris@0: pdf.SetFontStyle('B',8) Chris@0: pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) Chris@0: pdf.Ln Chris@0: pdf.SetFontStyle('I',8) Chris@0: for detail in journal.details Chris@0: pdf.Cell(190,5, "- " + show_detail(detail, true)) Chris@0: pdf.Ln Chris@0: end Chris@0: if journal.notes? Chris@0: pdf.SetFontStyle('',8) Chris@0: pdf.MultiCell(190,5, journal.notes) Chris@0: end Chris@0: pdf.Ln Chris@0: end Chris@0: Chris@0: if issue.attachments.any? Chris@0: pdf.SetFontStyle('B',9) Chris@0: pdf.Cell(190,5, l(:label_attachment_plural), "B") Chris@0: pdf.Ln Chris@0: for attachment in issue.attachments Chris@0: pdf.SetFontStyle('',8) Chris@0: pdf.Cell(80,5, attachment.filename) Chris@0: pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R") Chris@0: pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R") Chris@0: pdf.Cell(65,5, attachment.author.name,0,0,"R") Chris@0: pdf.Ln Chris@0: end Chris@0: end Chris@0: pdf.Output Chris@0: end Chris@0: Chris@0: # Returns a PDF string of a gantt chart Chris@0: def gantt_to_pdf(gantt, project) Chris@0: pdf = IFPDF.new(current_language) Chris@0: pdf.SetTitle("#{l(:label_gantt)} #{project}") Chris@0: pdf.AliasNbPages Chris@0: pdf.footer_date = format_date(Date.today) Chris@0: pdf.AddPage("L") Chris@0: pdf.SetFontStyle('B',12) Chris@0: pdf.SetX(15) Chris@0: pdf.Cell(70, 20, project.to_s) Chris@0: pdf.Ln Chris@0: pdf.SetFontStyle('B',9) Chris@0: Chris@1: subject_width = 100 Chris@0: header_heigth = 5 Chris@0: Chris@0: headers_heigth = header_heigth Chris@0: show_weeks = false Chris@0: show_days = false Chris@0: Chris@0: if gantt.months < 7 Chris@0: show_weeks = true Chris@0: headers_heigth = 2*header_heigth Chris@0: if gantt.months < 3 Chris@0: show_days = true Chris@0: headers_heigth = 3*header_heigth Chris@0: end Chris@0: end Chris@0: Chris@1: g_width = 280 - subject_width Chris@0: zoom = (g_width) / (gantt.date_to - gantt.date_from + 1) Chris@0: g_height = 120 Chris@0: t_height = g_height + headers_heigth Chris@0: Chris@0: y_start = pdf.GetY Chris@0: Chris@0: # Months headers Chris@0: month_f = gantt.date_from Chris@0: left = subject_width Chris@0: height = header_heigth Chris@0: gantt.months.times do Chris@0: width = ((month_f >> 1) - month_f) * zoom Chris@0: pdf.SetY(y_start) Chris@0: pdf.SetX(left) Chris@0: pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") Chris@0: left = left + width Chris@0: month_f = month_f >> 1 Chris@0: end Chris@0: Chris@0: # Weeks headers Chris@0: if show_weeks Chris@0: left = subject_width Chris@0: height = header_heigth Chris@0: if gantt.date_from.cwday == 1 Chris@0: # gantt.date_from is monday Chris@0: week_f = gantt.date_from Chris@0: else Chris@0: # find next monday after gantt.date_from Chris@0: week_f = gantt.date_from + (7 - gantt.date_from.cwday + 1) Chris@0: width = (7 - gantt.date_from.cwday + 1) * zoom-1 Chris@0: pdf.SetY(y_start + header_heigth) Chris@0: pdf.SetX(left) Chris@0: pdf.Cell(width + 1, height, "", "LTR") Chris@0: left = left + width+1 Chris@0: end Chris@0: while week_f <= gantt.date_to Chris@0: width = (week_f + 6 <= gantt.date_to) ? 7 * zoom : (gantt.date_to - week_f + 1) * zoom Chris@0: pdf.SetY(y_start + header_heigth) Chris@0: pdf.SetX(left) Chris@0: pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C") Chris@0: left = left + width Chris@0: week_f = week_f+7 Chris@0: end Chris@0: end Chris@0: Chris@0: # Days headers Chris@0: if show_days Chris@0: left = subject_width Chris@0: height = header_heigth Chris@0: wday = gantt.date_from.cwday Chris@0: pdf.SetFontStyle('B',7) Chris@0: (gantt.date_to - gantt.date_from + 1).to_i.times do Chris@0: width = zoom Chris@0: pdf.SetY(y_start + 2 * header_heigth) Chris@0: pdf.SetX(left) Chris@0: pdf.Cell(width, height, day_name(wday).first, "LTR", 0, "C") Chris@0: left = left + width Chris@0: wday = wday + 1 Chris@0: wday = 1 if wday > 7 Chris@0: end Chris@0: end Chris@0: Chris@0: pdf.SetY(y_start) Chris@0: pdf.SetX(15) Chris@0: pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1) Chris@0: Chris@0: # Tasks Chris@0: top = headers_heigth + y_start Chris@0: pdf.SetFontStyle('B',7) Chris@0: gantt.events.each do |i| Chris@0: pdf.SetY(top) Chris@0: pdf.SetX(15) Chris@0: Chris@1: text = "" Chris@0: if i.is_a? Issue Chris@1: text = "#{i.tracker} #{i.id}: #{i.subject}" Chris@0: else Chris@1: text = i.name Chris@0: end Chris@1: text = "#{i.project} - #{text}" unless project && project == i.project Chris@1: pdf.Cell(subject_width-15, 5, text, "LR") Chris@0: Chris@1: pdf.SetY(top + 0.2) Chris@0: pdf.SetX(subject_width) Chris@1: pdf.SetFillColor(255, 255, 255) Chris@1: pdf.Cell(g_width, 4.6, "", "LR", 0, "", 1) Chris@0: pdf.SetY(top+1.5) Chris@0: Chris@0: if i.is_a? Issue Chris@0: i_start_date = (i.start_date >= gantt.date_from ? i.start_date : gantt.date_from ) Chris@0: i_end_date = (i.due_before <= gantt.date_to ? i.due_before : gantt.date_to ) Chris@0: Chris@0: i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor Chris@0: i_done_date = (i_done_date <= gantt.date_from ? gantt.date_from : i_done_date ) Chris@0: i_done_date = (i_done_date >= gantt.date_to ? gantt.date_to : i_done_date ) Chris@0: Chris@0: i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today Chris@0: Chris@0: i_left = ((i_start_date - gantt.date_from)*zoom) Chris@0: i_width = ((i_end_date - i_start_date + 1)*zoom) Chris@0: d_width = ((i_done_date - i_start_date)*zoom) Chris@0: l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date Chris@0: l_width ||= 0 Chris@0: Chris@0: pdf.SetX(subject_width + i_left) Chris@0: pdf.SetFillColor(200,200,200) Chris@0: pdf.Cell(i_width, 2, "", 0, 0, "", 1) Chris@0: Chris@0: if l_width > 0 Chris@0: pdf.SetY(top+1.5) Chris@0: pdf.SetX(subject_width + i_left) Chris@0: pdf.SetFillColor(255,100,100) Chris@0: pdf.Cell(l_width, 2, "", 0, 0, "", 1) Chris@0: end Chris@0: if d_width > 0 Chris@0: pdf.SetY(top+1.5) Chris@0: pdf.SetX(subject_width + i_left) Chris@0: pdf.SetFillColor(100,100,255) Chris@0: pdf.Cell(d_width, 2, "", 0, 0, "", 1) Chris@0: end Chris@0: Chris@0: pdf.SetY(top+1.5) Chris@0: pdf.SetX(subject_width + i_left + i_width) Chris@0: pdf.Cell(30, 2, "#{i.status} #{i.done_ratio}%") Chris@0: else Chris@0: i_left = ((i.start_date - gantt.date_from)*zoom) Chris@0: Chris@0: pdf.SetX(subject_width + i_left) Chris@0: pdf.SetFillColor(50,200,50) Chris@0: pdf.Cell(2, 2, "", 0, 0, "", 1) Chris@0: Chris@0: pdf.SetY(top+1.5) Chris@0: pdf.SetX(subject_width + i_left + 3) Chris@0: pdf.Cell(30, 2, "#{i.name}") Chris@0: end Chris@0: Chris@0: top = top + 5 Chris@0: pdf.SetDrawColor(200, 200, 200) Chris@0: pdf.Line(15, top, subject_width+g_width, top) Chris@0: if pdf.GetY() > 180 Chris@0: pdf.AddPage("L") Chris@0: top = 20 Chris@0: pdf.Line(15, top, subject_width+g_width, top) Chris@0: end Chris@0: pdf.SetDrawColor(0, 0, 0) Chris@0: end Chris@0: Chris@0: pdf.Line(15, top, subject_width+g_width, top) Chris@0: pdf.Output Chris@0: end Chris@0: end Chris@0: end Chris@0: end