##// END OF EJS Templates
Fix for ruby1.9.3....
Jean-Philippe Lang -
r8616:7409963c9a69
parent child
Show More
@@ -1,670 +1,670
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2011 Jean-Philippe Lang
5 5 #
6 6 # This program is free software; you can redistribute it and/or
7 7 # modify it under the terms of the GNU General Public License
8 8 # as published by the Free Software Foundation; either version 2
9 9 # of the License, or (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software
18 18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 19
20 20 require 'iconv'
21 21 require 'fpdf/chinese'
22 22 require 'fpdf/japanese'
23 23 require 'fpdf/korean'
24 24 require 'core/rmagick'
25 25
26 26 module Redmine
27 27 module Export
28 28 module PDF
29 29 include ActionView::Helpers::TextHelper
30 30 include ActionView::Helpers::NumberHelper
31 31 include IssuesHelper
32 32
33 33 class ITCPDF < TCPDF
34 34 include Redmine::I18n
35 35 attr_accessor :footer_date
36 36
37 37 def initialize(lang)
38 38 @@k_path_cache = Rails.root.join('tmp', 'pdf')
39 39 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
40 40 set_language_if_valid lang
41 41 pdf_encoding = l(:general_pdf_encoding).upcase
42 42 super('P', 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
43 43 case current_language.to_s.downcase
44 44 when 'vi'
45 45 @font_for_content = 'DejaVuSans'
46 46 @font_for_footer = 'DejaVuSans'
47 47 else
48 48 case pdf_encoding
49 49 when 'UTF-8'
50 50 @font_for_content = 'FreeSans'
51 51 @font_for_footer = 'FreeSans'
52 52 when 'CP949'
53 53 extend(PDF_Korean)
54 54 AddUHCFont()
55 55 @font_for_content = 'UHC'
56 56 @font_for_footer = 'UHC'
57 57 when 'CP932', 'SJIS', 'SHIFT_JIS'
58 58 extend(PDF_Japanese)
59 59 AddSJISFont()
60 60 @font_for_content = 'SJIS'
61 61 @font_for_footer = 'SJIS'
62 62 when 'GB18030'
63 63 extend(PDF_Chinese)
64 64 AddGBFont()
65 65 @font_for_content = 'GB'
66 66 @font_for_footer = 'GB'
67 67 when 'BIG5'
68 68 extend(PDF_Chinese)
69 69 AddBig5Font()
70 70 @font_for_content = 'Big5'
71 71 @font_for_footer = 'Big5'
72 72 else
73 73 @font_for_content = 'Arial'
74 74 @font_for_footer = 'Helvetica'
75 75 end
76 76 end
77 77 SetCreator(Redmine::Info.app_name)
78 78 SetFont(@font_for_content)
79 79 @outlines = []
80 80 @outlineRoot = nil
81 81 end
82 82
83 83 def SetFontStyle(style, size)
84 84 SetFont(@font_for_content, style, size)
85 85 end
86 86
87 87 def SetTitle(txt)
88 88 txt = begin
89 89 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
90 90 hextxt = "<FEFF" # FEFF is BOM
91 91 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
92 92 hextxt << ">"
93 93 rescue
94 94 txt
95 95 end || ''
96 96 super(txt)
97 97 end
98 98
99 99 def textstring(s)
100 100 # Format a text string
101 if s =~ /^</ # This means the string is hex-dumped.
101 if s.chars.first == '<' # This means the string is hex-dumped.
102 102 return s
103 103 else
104 104 return '('+escape(s)+')'
105 105 end
106 106 end
107 107
108 108 def fix_text_encoding(txt)
109 109 RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
110 110 end
111 111
112 112 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
113 113 Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
114 114 end
115 115
116 116 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
117 117 MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
118 118 end
119 119
120 120 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
121 121 @attachments = attachments
122 122 writeHTMLCell(w, h, x, y,
123 123 fix_text_encoding(
124 124 Redmine::WikiFormatting.to_html(Setting.text_formatting, txt)),
125 125 border, ln, fill)
126 126 end
127 127
128 128 def getImageFilename(attrname)
129 129 # attrname: general_pdf_encoding string file/uri name
130 130 atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
131 131 if atta
132 132 return atta.diskfile
133 133 else
134 134 return nil
135 135 end
136 136 end
137 137
138 138 def Footer
139 139 SetFont(@font_for_footer, 'I', 8)
140 140 SetY(-15)
141 141 SetX(15)
142 142 RDMCell(0, 5, @footer_date, 0, 0, 'L')
143 143 SetY(-15)
144 144 SetX(-30)
145 145 RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
146 146 end
147 147
148 148 def Bookmark(txt, level=0, y=0)
149 149 utf16 = Iconv.conv('UTF-16', 'UTF-8', txt)
150 150 if (y == -1)
151 151 y = GetY()
152 152 end
153 153 @outlines << {:t => utf16, :l => level, :p => PageNo(), :y => (@h - y)*@k}
154 154 end
155 155
156 156 def putbookmarks
157 157 nb=@outlines.size
158 158 return if (nb==0)
159 159 lru=[]
160 160 level=0
161 161 @outlines.each_with_index do |o, i|
162 162 if(o[:l]>0)
163 163 parent=lru[o[:l]-1]
164 164 #Set parent and last pointers
165 165 @outlines[i][:parent]=parent
166 166 @outlines[parent][:last]=i
167 167 if (o[:l]>level)
168 168 #Level increasing: set first pointer
169 169 @outlines[parent][:first]=i
170 170 end
171 171 else
172 172 @outlines[i][:parent]=nb
173 173 end
174 174 if (o[:l]<=level && i>0)
175 175 #Set prev and next pointers
176 176 prev=lru[o[:l]]
177 177 @outlines[prev][:next]=i
178 178 @outlines[i][:prev]=prev
179 179 end
180 180 lru[o[:l]]=i
181 181 level=o[:l]
182 182 end
183 183 #Outline items
184 184 n=self.n+1
185 185 @outlines.each_with_index do |o, i|
186 186 newobj()
187 187 out('<</Title '+textstring(o[:t]))
188 188 out("/Parent #{n+o[:parent]} 0 R")
189 189 if (o[:prev])
190 190 out("/Prev #{n+o[:prev]} 0 R")
191 191 end
192 192 if (o[:next])
193 193 out("/Next #{n+o[:next]} 0 R")
194 194 end
195 195 if (o[:first])
196 196 out("/First #{n+o[:first]} 0 R")
197 197 end
198 198 if (o[:last])
199 199 out("/Last #{n+o[:last]} 0 R")
200 200 end
201 201 out("/Dest [%d 0 R /XYZ 0 %.2f null]" % [1+2*o[:p], o[:y]])
202 202 out('/Count 0>>')
203 203 out('endobj')
204 204 end
205 205 #Outline root
206 206 newobj()
207 207 @outlineRoot=self.n
208 208 out("<</Type /Outlines /First #{n} 0 R");
209 209 out("/Last #{n+lru[0]} 0 R>>");
210 210 out('endobj');
211 211 end
212 212
213 213 def putresources()
214 214 super
215 215 putbookmarks()
216 216 end
217 217
218 218 def putcatalog()
219 219 super
220 220 if(@outlines.size > 0)
221 221 out("/Outlines #{@outlineRoot} 0 R");
222 222 out('/PageMode /UseOutlines');
223 223 end
224 224 end
225 225 end
226 226
227 227 # Returns a PDF string of a list of issues
228 228 def issues_to_pdf(issues, project, query)
229 229 pdf = ITCPDF.new(current_language)
230 230 title = query.new_record? ? l(:label_issue_plural) : query.name
231 231 title = "#{project} - #{title}" if project
232 232 pdf.SetTitle(title)
233 233 pdf.alias_nb_pages
234 234 pdf.footer_date = format_date(Date.today)
235 235 pdf.SetAutoPageBreak(false)
236 236 pdf.AddPage("L")
237 237
238 238 # Landscape A4 = 210 x 297 mm
239 239 page_height = 210
240 240 page_width = 297
241 241 right_margin = 10
242 242 bottom_margin = 20
243 243 col_id_width = 10
244 244 row_height = 5
245 245
246 246 # column widths
247 247 table_width = page_width - right_margin - 10 # fixed left margin
248 248 col_width = []
249 249 unless query.columns.empty?
250 250 col_width = query.columns.collect do |c|
251 251 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
252 252 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
253 253 end
254 254 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
255 255 col_width = col_width.collect {|w| w * ratio}
256 256 end
257 257
258 258 # title
259 259 pdf.SetFontStyle('B',11)
260 260 pdf.RDMCell(190,10, title)
261 261 pdf.Ln
262 262
263 263 # headers
264 264 pdf.SetFontStyle('B',8)
265 265 pdf.SetFillColor(230, 230, 230)
266 266
267 267 # render it background to find the max height used
268 268 base_x = pdf.GetX
269 269 base_y = pdf.GetY
270 270 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
271 271 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
272 272 pdf.SetXY(base_x, base_y);
273 273
274 274 # write the cells on page
275 275 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
276 276 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
277 277 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
278 278 pdf.SetY(base_y + max_height);
279 279
280 280 # rows
281 281 pdf.SetFontStyle('',8)
282 282 pdf.SetFillColor(255, 255, 255)
283 283 previous_group = false
284 284 issue_list(issues) do |issue, level|
285 285 if query.grouped? &&
286 286 (group = query.group_by_column.value(issue)) != previous_group
287 287 pdf.SetFontStyle('B',9)
288 288 group_label = group.blank? ? 'None' : group.to_s
289 289 group_label << " (#{query.issue_count_by_group[group]})"
290 290 pdf.Bookmark group_label, 0, -1
291 291 pdf.RDMCell(277, row_height, group_label, 1, 1, 'L')
292 292 pdf.SetFontStyle('',8)
293 293 previous_group = group
294 294 end
295 295 # fetch all the row values
296 296 col_values = query.columns.collect do |column|
297 297 s = if column.is_a?(QueryCustomFieldColumn)
298 298 cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
299 299 show_value(cv)
300 300 else
301 301 value = issue.send(column.name)
302 302 if column.name == :subject
303 303 value = " " * level + value
304 304 end
305 305 if value.is_a?(Date)
306 306 format_date(value)
307 307 elsif value.is_a?(Time)
308 308 format_time(value)
309 309 else
310 310 value
311 311 end
312 312 end
313 313 s.to_s
314 314 end
315 315
316 316 # render it off-page to find the max height used
317 317 base_x = pdf.GetX
318 318 base_y = pdf.GetY
319 319 pdf.SetY(2 * page_height)
320 320 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
321 321 pdf.SetXY(base_x, base_y)
322 322
323 323 # make new page if it doesn't fit on the current one
324 324 space_left = page_height - base_y - bottom_margin
325 325 if max_height > space_left
326 326 pdf.AddPage("L")
327 327 base_x = pdf.GetX
328 328 base_y = pdf.GetY
329 329 end
330 330
331 331 # write the cells on page
332 332 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
333 333 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
334 334 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
335 335 pdf.SetY(base_y + max_height);
336 336 end
337 337
338 338 if issues.size == Setting.issues_export_limit.to_i
339 339 pdf.SetFontStyle('B',10)
340 340 pdf.RDMCell(0, row_height, '...')
341 341 end
342 342 pdf.Output
343 343 end
344 344
345 345 # Renders MultiCells and returns the maximum height used
346 346 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
347 347 row_height, head=false)
348 348 base_y = pdf.GetY
349 349 max_height = row_height
350 350 col_values.each_with_index do |column, i|
351 351 col_x = pdf.GetX
352 352 if head == true
353 353 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
354 354 else
355 355 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
356 356 end
357 357 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
358 358 pdf.SetXY(col_x + col_widths[i], base_y);
359 359 end
360 360 return max_height
361 361 end
362 362
363 363 # Draw lines to close the row (MultiCell border drawing in not uniform)
364 364 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
365 365 id_width, col_widths)
366 366 col_x = top_x + id_width
367 367 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
368 368 col_widths.each do |width|
369 369 col_x += width
370 370 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
371 371 end
372 372 pdf.Line(top_x, top_y, top_x, lower_y) # left border
373 373 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
374 374 end
375 375
376 376 # Returns a PDF string of a single issue
377 377 def issue_to_pdf(issue)
378 378 pdf = ITCPDF.new(current_language)
379 379 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
380 380 pdf.alias_nb_pages
381 381 pdf.footer_date = format_date(Date.today)
382 382 pdf.AddPage
383 383 pdf.SetFontStyle('B',11)
384 384 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
385 385 pdf.RDMMultiCell(190, 5, buf)
386 386 pdf.Ln
387 387 pdf.SetFontStyle('',8)
388 388 base_x = pdf.GetX
389 389 i = 1
390 390 issue.ancestors.each do |ancestor|
391 391 pdf.SetX(base_x + i)
392 392 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
393 393 pdf.RDMMultiCell(190 - i, 5, buf)
394 394 i += 1 if i < 35
395 395 end
396 396 pdf.Ln
397 397
398 398 pdf.SetFontStyle('B',9)
399 399 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
400 400 pdf.SetFontStyle('',9)
401 401 pdf.RDMCell(60,5, issue.status.to_s,"RT")
402 402 pdf.SetFontStyle('B',9)
403 403 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
404 404 pdf.SetFontStyle('',9)
405 405 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
406 406 pdf.Ln
407 407
408 408 pdf.SetFontStyle('B',9)
409 409 pdf.RDMCell(35,5, l(:field_author) + ":","L")
410 410 pdf.SetFontStyle('',9)
411 411 pdf.RDMCell(60,5, issue.author.to_s,"R")
412 412 pdf.SetFontStyle('B',9)
413 413 pdf.RDMCell(35,5, l(:field_category) + ":","L")
414 414 pdf.SetFontStyle('',9)
415 415 pdf.RDMCell(60,5, issue.category.to_s,"R")
416 416 pdf.Ln
417 417
418 418 pdf.SetFontStyle('B',9)
419 419 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
420 420 pdf.SetFontStyle('',9)
421 421 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
422 422 pdf.SetFontStyle('B',9)
423 423 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
424 424 pdf.SetFontStyle('',9)
425 425 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
426 426 pdf.Ln
427 427
428 428 pdf.SetFontStyle('B',9)
429 429 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
430 430 pdf.SetFontStyle('',9)
431 431 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
432 432 pdf.SetFontStyle('B',9)
433 433 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
434 434 pdf.SetFontStyle('',9)
435 435 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
436 436 pdf.Ln
437 437
438 438 for custom_value in issue.custom_field_values
439 439 pdf.SetFontStyle('B',9)
440 440 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
441 441 pdf.SetFontStyle('',9)
442 442 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
443 443 end
444 444
445 445 y0 = pdf.GetY
446 446
447 447 pdf.SetFontStyle('B',9)
448 448 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
449 449 pdf.SetFontStyle('',9)
450 450 pdf.RDMMultiCell(155,5, issue.subject,"RT")
451 451 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
452 452
453 453 pdf.SetFontStyle('B',9)
454 454 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
455 455 pdf.SetFontStyle('',9)
456 456
457 457 # Set resize image scale
458 458 pdf.SetImageScale(1.6)
459 459 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
460 460 issue.description.to_s, issue.attachments, "LRB")
461 461
462 462 unless issue.leaf?
463 463 # for CJK
464 464 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
465 465
466 466 pdf.SetFontStyle('B',9)
467 467 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
468 468 pdf.Ln
469 469 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
470 470 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
471 471 :length => truncate_length)
472 472 level = 10 if level >= 10
473 473 pdf.SetFontStyle('',8)
474 474 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
475 475 pdf.SetFontStyle('B',8)
476 476 pdf.RDMCell(20,5, child.status.to_s, "R")
477 477 pdf.Ln
478 478 end
479 479 end
480 480
481 481 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
482 482 unless relations.empty?
483 483 # for CJK
484 484 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
485 485
486 486 pdf.SetFontStyle('B',9)
487 487 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
488 488 pdf.Ln
489 489 relations.each do |relation|
490 490 buf = ""
491 491 buf += "#{l(relation.label_for(issue))} "
492 492 if relation.delay && relation.delay != 0
493 493 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
494 494 end
495 495 if Setting.cross_project_issue_relations?
496 496 buf += "#{relation.other_issue(issue).project} - "
497 497 end
498 498 buf += "#{relation.other_issue(issue).tracker}" +
499 499 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
500 500 buf = truncate(buf, :length => truncate_length)
501 501 pdf.SetFontStyle('', 8)
502 502 pdf.RDMCell(35+155-60, 5, buf, "L")
503 503 pdf.SetFontStyle('B',8)
504 504 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
505 505 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
506 506 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
507 507 pdf.Ln
508 508 end
509 509 end
510 510 pdf.RDMCell(190,5, "", "T")
511 511 pdf.Ln
512 512
513 513 if issue.changesets.any? &&
514 514 User.current.allowed_to?(:view_changesets, issue.project)
515 515 pdf.SetFontStyle('B',9)
516 516 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
517 517 pdf.Ln
518 518 for changeset in issue.changesets
519 519 pdf.SetFontStyle('B',8)
520 520 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
521 521 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
522 522 pdf.RDMCell(190, 5, csstr)
523 523 pdf.Ln
524 524 unless changeset.comments.blank?
525 525 pdf.SetFontStyle('',8)
526 526 pdf.RDMwriteHTMLCell(190,5,0,0,
527 527 changeset.comments.to_s, issue.attachments, "")
528 528 end
529 529 pdf.Ln
530 530 end
531 531 end
532 532
533 533 pdf.SetFontStyle('B',9)
534 534 pdf.RDMCell(190,5, l(:label_history), "B")
535 535 pdf.Ln
536 536 indice = 0
537 537 for journal in issue.journals.find(
538 538 :all, :include => [:user, :details],
539 539 :order => "#{Journal.table_name}.created_on ASC")
540 540 indice = indice + 1
541 541 pdf.SetFontStyle('B',8)
542 542 pdf.RDMCell(190,5,
543 543 "#" + indice.to_s +
544 544 " - " + format_time(journal.created_on) +
545 545 " - " + journal.user.name)
546 546 pdf.Ln
547 547 pdf.SetFontStyle('I',8)
548 548 details_to_strings(journal.details, true).each do |string|
549 549 pdf.RDMMultiCell(190,5, "- " + string)
550 550 end
551 551 if journal.notes?
552 552 pdf.Ln unless journal.details.empty?
553 553 pdf.SetFontStyle('',8)
554 554 pdf.RDMwriteHTMLCell(190,5,0,0,
555 555 journal.notes.to_s, issue.attachments, "")
556 556 end
557 557 pdf.Ln
558 558 end
559 559
560 560 if issue.attachments.any?
561 561 pdf.SetFontStyle('B',9)
562 562 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
563 563 pdf.Ln
564 564 for attachment in issue.attachments
565 565 pdf.SetFontStyle('',8)
566 566 pdf.RDMCell(80,5, attachment.filename)
567 567 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
568 568 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
569 569 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
570 570 pdf.Ln
571 571 end
572 572 end
573 573 pdf.Output
574 574 end
575 575
576 576 # Returns a PDF string of a set of wiki pages
577 577 def wiki_pages_to_pdf(pages, project)
578 578 pdf = ITCPDF.new(current_language)
579 579 pdf.SetTitle(project.name)
580 580 pdf.alias_nb_pages
581 581 pdf.footer_date = format_date(Date.today)
582 582 pdf.AddPage
583 583 pdf.SetFontStyle('B',11)
584 584 pdf.RDMMultiCell(190,5, project.name)
585 585 pdf.Ln
586 586 # Set resize image scale
587 587 pdf.SetImageScale(1.6)
588 588 pdf.SetFontStyle('',9)
589 589 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
590 590 pdf.Output
591 591 end
592 592
593 593 # Returns a PDF string of a single wiki page
594 594 def wiki_page_to_pdf(page, project)
595 595 pdf = ITCPDF.new(current_language)
596 596 pdf.SetTitle("#{project} - #{page.title}")
597 597 pdf.alias_nb_pages
598 598 pdf.footer_date = format_date(Date.today)
599 599 pdf.AddPage
600 600 pdf.SetFontStyle('B',11)
601 601 pdf.RDMMultiCell(190,5,
602 602 "#{project} - #{page.title} - # #{page.content.version}")
603 603 pdf.Ln
604 604 # Set resize image scale
605 605 pdf.SetImageScale(1.6)
606 606 pdf.SetFontStyle('',9)
607 607 write_wiki_page(pdf, page)
608 608 pdf.Output
609 609 end
610 610
611 611 def write_page_hierarchy(pdf, pages, node=nil, level=0)
612 612 if pages[node]
613 613 pages[node].each do |page|
614 614 if @new_page
615 615 pdf.AddPage
616 616 else
617 617 @new_page = true
618 618 end
619 619 pdf.Bookmark page.title, level
620 620 write_wiki_page(pdf, page)
621 621 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
622 622 end
623 623 end
624 624 end
625 625
626 626 def write_wiki_page(pdf, page)
627 627 pdf.RDMwriteHTMLCell(190,5,0,0,
628 628 page.content.text.to_s, page.attachments, "TLRB")
629 629 if page.attachments.any?
630 630 pdf.Ln
631 631 pdf.SetFontStyle('B',9)
632 632 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
633 633 pdf.Ln
634 634 for attachment in page.attachments
635 635 pdf.SetFontStyle('',8)
636 636 pdf.RDMCell(80,5, attachment.filename)
637 637 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
638 638 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
639 639 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
640 640 pdf.Ln
641 641 end
642 642 end
643 643 end
644 644
645 645 class RDMPdfEncoding
646 646 def self.rdm_from_utf8(txt, encoding)
647 647 txt ||= ''
648 648 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
649 649 if txt.respond_to?(:force_encoding)
650 650 txt.force_encoding('ASCII-8BIT')
651 651 end
652 652 txt
653 653 end
654 654
655 655 def self.attach(attachments, filename, encoding)
656 656 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
657 657 atta = nil
658 658 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
659 659 atta = Attachment.latest_attach(attachments, filename_utf8)
660 660 end
661 661 if atta && atta.readable? && atta.visible?
662 662 return atta
663 663 else
664 664 return nil
665 665 end
666 666 end
667 667 end
668 668 end
669 669 end
670 670 end
General Comments 0
You need to be logged in to leave comments. Login now