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