##// END OF EJS Templates
Fix for ruby1.9.3....
Jean-Philippe Lang -
r8619:7abaa570c607
parent child
Show More
@@ -1,670 +1,680
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.chars.first == '<' # This means the string is hex-dumped.
101 if s =~ /^</ # 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 utf16 = Iconv.conv('UTF-16', 'UTF-8', txt)
150 149 if (y == -1)
151 150 y = GetY()
152 151 end
153 @outlines << {:t => utf16, :l => level, :p => PageNo(), :y => (@h - y)*@k}
152 @outlines << {:t => txt, :l => level, :p => PageNo(), :y => (@h - y)*@k}
153 end
154
155 def bookmark_title(txt)
156 txt = begin
157 utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt)
158 hextxt = "<FEFF" # FEFF is BOM
159 hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
160 hextxt << ">"
161 rescue
162 txt
163 end || ''
154 164 end
155 165
156 166 def putbookmarks
157 167 nb=@outlines.size
158 168 return if (nb==0)
159 169 lru=[]
160 170 level=0
161 171 @outlines.each_with_index do |o, i|
162 172 if(o[:l]>0)
163 173 parent=lru[o[:l]-1]
164 174 #Set parent and last pointers
165 175 @outlines[i][:parent]=parent
166 176 @outlines[parent][:last]=i
167 177 if (o[:l]>level)
168 178 #Level increasing: set first pointer
169 179 @outlines[parent][:first]=i
170 180 end
171 181 else
172 182 @outlines[i][:parent]=nb
173 183 end
174 184 if (o[:l]<=level && i>0)
175 185 #Set prev and next pointers
176 186 prev=lru[o[:l]]
177 187 @outlines[prev][:next]=i
178 188 @outlines[i][:prev]=prev
179 189 end
180 190 lru[o[:l]]=i
181 191 level=o[:l]
182 192 end
183 193 #Outline items
184 194 n=self.n+1
185 195 @outlines.each_with_index do |o, i|
186 196 newobj()
187 out('<</Title '+textstring(o[:t]))
197 out('<</Title '+bookmark_title(o[:t]))
188 198 out("/Parent #{n+o[:parent]} 0 R")
189 199 if (o[:prev])
190 200 out("/Prev #{n+o[:prev]} 0 R")
191 201 end
192 202 if (o[:next])
193 203 out("/Next #{n+o[:next]} 0 R")
194 204 end
195 205 if (o[:first])
196 206 out("/First #{n+o[:first]} 0 R")
197 207 end
198 208 if (o[:last])
199 209 out("/Last #{n+o[:last]} 0 R")
200 210 end
201 211 out("/Dest [%d 0 R /XYZ 0 %.2f null]" % [1+2*o[:p], o[:y]])
202 212 out('/Count 0>>')
203 213 out('endobj')
204 214 end
205 215 #Outline root
206 216 newobj()
207 217 @outlineRoot=self.n
208 218 out("<</Type /Outlines /First #{n} 0 R");
209 219 out("/Last #{n+lru[0]} 0 R>>");
210 220 out('endobj');
211 221 end
212 222
213 223 def putresources()
214 224 super
215 225 putbookmarks()
216 226 end
217 227
218 228 def putcatalog()
219 229 super
220 230 if(@outlines.size > 0)
221 231 out("/Outlines #{@outlineRoot} 0 R");
222 232 out('/PageMode /UseOutlines');
223 233 end
224 234 end
225 235 end
226 236
227 237 # Returns a PDF string of a list of issues
228 238 def issues_to_pdf(issues, project, query)
229 239 pdf = ITCPDF.new(current_language)
230 240 title = query.new_record? ? l(:label_issue_plural) : query.name
231 241 title = "#{project} - #{title}" if project
232 242 pdf.SetTitle(title)
233 243 pdf.alias_nb_pages
234 244 pdf.footer_date = format_date(Date.today)
235 245 pdf.SetAutoPageBreak(false)
236 246 pdf.AddPage("L")
237 247
238 248 # Landscape A4 = 210 x 297 mm
239 249 page_height = 210
240 250 page_width = 297
241 251 right_margin = 10
242 252 bottom_margin = 20
243 253 col_id_width = 10
244 254 row_height = 5
245 255
246 256 # column widths
247 257 table_width = page_width - right_margin - 10 # fixed left margin
248 258 col_width = []
249 259 unless query.columns.empty?
250 260 col_width = query.columns.collect do |c|
251 261 (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
252 262 ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
253 263 end
254 264 ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
255 265 col_width = col_width.collect {|w| w * ratio}
256 266 end
257 267
258 268 # title
259 269 pdf.SetFontStyle('B',11)
260 270 pdf.RDMCell(190,10, title)
261 271 pdf.Ln
262 272
263 273 # headers
264 274 pdf.SetFontStyle('B',8)
265 275 pdf.SetFillColor(230, 230, 230)
266 276
267 277 # render it background to find the max height used
268 278 base_x = pdf.GetX
269 279 base_y = pdf.GetY
270 280 max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
271 281 pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
272 282 pdf.SetXY(base_x, base_y);
273 283
274 284 # write the cells on page
275 285 pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
276 286 issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
277 287 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
278 288 pdf.SetY(base_y + max_height);
279 289
280 290 # rows
281 291 pdf.SetFontStyle('',8)
282 292 pdf.SetFillColor(255, 255, 255)
283 293 previous_group = false
284 294 issue_list(issues) do |issue, level|
285 295 if query.grouped? &&
286 296 (group = query.group_by_column.value(issue)) != previous_group
287 297 pdf.SetFontStyle('B',9)
288 298 group_label = group.blank? ? 'None' : group.to_s
289 299 group_label << " (#{query.issue_count_by_group[group]})"
290 300 pdf.Bookmark group_label, 0, -1
291 301 pdf.RDMCell(277, row_height, group_label, 1, 1, 'L')
292 302 pdf.SetFontStyle('',8)
293 303 previous_group = group
294 304 end
295 305 # fetch all the row values
296 306 col_values = query.columns.collect do |column|
297 307 s = if column.is_a?(QueryCustomFieldColumn)
298 308 cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
299 309 show_value(cv)
300 310 else
301 311 value = issue.send(column.name)
302 312 if column.name == :subject
303 313 value = " " * level + value
304 314 end
305 315 if value.is_a?(Date)
306 316 format_date(value)
307 317 elsif value.is_a?(Time)
308 318 format_time(value)
309 319 else
310 320 value
311 321 end
312 322 end
313 323 s.to_s
314 324 end
315 325
316 326 # render it off-page to find the max height used
317 327 base_x = pdf.GetX
318 328 base_y = pdf.GetY
319 329 pdf.SetY(2 * page_height)
320 330 max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
321 331 pdf.SetXY(base_x, base_y)
322 332
323 333 # make new page if it doesn't fit on the current one
324 334 space_left = page_height - base_y - bottom_margin
325 335 if max_height > space_left
326 336 pdf.AddPage("L")
327 337 base_x = pdf.GetX
328 338 base_y = pdf.GetY
329 339 end
330 340
331 341 # write the cells on page
332 342 pdf.RDMCell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
333 343 issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
334 344 issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
335 345 pdf.SetY(base_y + max_height);
336 346 end
337 347
338 348 if issues.size == Setting.issues_export_limit.to_i
339 349 pdf.SetFontStyle('B',10)
340 350 pdf.RDMCell(0, row_height, '...')
341 351 end
342 352 pdf.Output
343 353 end
344 354
345 355 # Renders MultiCells and returns the maximum height used
346 356 def issues_to_pdf_write_cells(pdf, col_values, col_widths,
347 357 row_height, head=false)
348 358 base_y = pdf.GetY
349 359 max_height = row_height
350 360 col_values.each_with_index do |column, i|
351 361 col_x = pdf.GetX
352 362 if head == true
353 363 pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
354 364 else
355 365 pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
356 366 end
357 367 max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
358 368 pdf.SetXY(col_x + col_widths[i], base_y);
359 369 end
360 370 return max_height
361 371 end
362 372
363 373 # Draw lines to close the row (MultiCell border drawing in not uniform)
364 374 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
365 375 id_width, col_widths)
366 376 col_x = top_x + id_width
367 377 pdf.Line(col_x, top_y, col_x, lower_y) # id right border
368 378 col_widths.each do |width|
369 379 col_x += width
370 380 pdf.Line(col_x, top_y, col_x, lower_y) # columns right border
371 381 end
372 382 pdf.Line(top_x, top_y, top_x, lower_y) # left border
373 383 pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border
374 384 end
375 385
376 386 # Returns a PDF string of a single issue
377 387 def issue_to_pdf(issue)
378 388 pdf = ITCPDF.new(current_language)
379 389 pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
380 390 pdf.alias_nb_pages
381 391 pdf.footer_date = format_date(Date.today)
382 392 pdf.AddPage
383 393 pdf.SetFontStyle('B',11)
384 394 buf = "#{issue.project} - #{issue.tracker} # #{issue.id}"
385 395 pdf.RDMMultiCell(190, 5, buf)
386 396 pdf.Ln
387 397 pdf.SetFontStyle('',8)
388 398 base_x = pdf.GetX
389 399 i = 1
390 400 issue.ancestors.each do |ancestor|
391 401 pdf.SetX(base_x + i)
392 402 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
393 403 pdf.RDMMultiCell(190 - i, 5, buf)
394 404 i += 1 if i < 35
395 405 end
396 406 pdf.Ln
397 407
398 408 pdf.SetFontStyle('B',9)
399 409 pdf.RDMCell(35,5, l(:field_status) + ":","LT")
400 410 pdf.SetFontStyle('',9)
401 411 pdf.RDMCell(60,5, issue.status.to_s,"RT")
402 412 pdf.SetFontStyle('B',9)
403 413 pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
404 414 pdf.SetFontStyle('',9)
405 415 pdf.RDMCell(60,5, issue.priority.to_s,"RT")
406 416 pdf.Ln
407 417
408 418 pdf.SetFontStyle('B',9)
409 419 pdf.RDMCell(35,5, l(:field_author) + ":","L")
410 420 pdf.SetFontStyle('',9)
411 421 pdf.RDMCell(60,5, issue.author.to_s,"R")
412 422 pdf.SetFontStyle('B',9)
413 423 pdf.RDMCell(35,5, l(:field_category) + ":","L")
414 424 pdf.SetFontStyle('',9)
415 425 pdf.RDMCell(60,5, issue.category.to_s,"R")
416 426 pdf.Ln
417 427
418 428 pdf.SetFontStyle('B',9)
419 429 pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
420 430 pdf.SetFontStyle('',9)
421 431 pdf.RDMCell(60,5, format_date(issue.created_on),"R")
422 432 pdf.SetFontStyle('B',9)
423 433 pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
424 434 pdf.SetFontStyle('',9)
425 435 pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
426 436 pdf.Ln
427 437
428 438 pdf.SetFontStyle('B',9)
429 439 pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
430 440 pdf.SetFontStyle('',9)
431 441 pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
432 442 pdf.SetFontStyle('B',9)
433 443 pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
434 444 pdf.SetFontStyle('',9)
435 445 pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
436 446 pdf.Ln
437 447
438 448 for custom_value in issue.custom_field_values
439 449 pdf.SetFontStyle('B',9)
440 450 pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
441 451 pdf.SetFontStyle('',9)
442 452 pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
443 453 end
444 454
445 455 y0 = pdf.GetY
446 456
447 457 pdf.SetFontStyle('B',9)
448 458 pdf.RDMCell(35,5, l(:field_subject) + ":","LT")
449 459 pdf.SetFontStyle('',9)
450 460 pdf.RDMMultiCell(155,5, issue.subject,"RT")
451 461 pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
452 462
453 463 pdf.SetFontStyle('B',9)
454 464 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
455 465 pdf.SetFontStyle('',9)
456 466
457 467 # Set resize image scale
458 468 pdf.SetImageScale(1.6)
459 469 pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
460 470 issue.description.to_s, issue.attachments, "LRB")
461 471
462 472 unless issue.leaf?
463 473 # for CJK
464 474 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
465 475
466 476 pdf.SetFontStyle('B',9)
467 477 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
468 478 pdf.Ln
469 479 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
470 480 buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}",
471 481 :length => truncate_length)
472 482 level = 10 if level >= 10
473 483 pdf.SetFontStyle('',8)
474 484 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L")
475 485 pdf.SetFontStyle('B',8)
476 486 pdf.RDMCell(20,5, child.status.to_s, "R")
477 487 pdf.Ln
478 488 end
479 489 end
480 490
481 491 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
482 492 unless relations.empty?
483 493 # for CJK
484 494 truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
485 495
486 496 pdf.SetFontStyle('B',9)
487 497 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
488 498 pdf.Ln
489 499 relations.each do |relation|
490 500 buf = ""
491 501 buf += "#{l(relation.label_for(issue))} "
492 502 if relation.delay && relation.delay != 0
493 503 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
494 504 end
495 505 if Setting.cross_project_issue_relations?
496 506 buf += "#{relation.other_issue(issue).project} - "
497 507 end
498 508 buf += "#{relation.other_issue(issue).tracker}" +
499 509 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
500 510 buf = truncate(buf, :length => truncate_length)
501 511 pdf.SetFontStyle('', 8)
502 512 pdf.RDMCell(35+155-60, 5, buf, "L")
503 513 pdf.SetFontStyle('B',8)
504 514 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
505 515 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
506 516 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
507 517 pdf.Ln
508 518 end
509 519 end
510 520 pdf.RDMCell(190,5, "", "T")
511 521 pdf.Ln
512 522
513 523 if issue.changesets.any? &&
514 524 User.current.allowed_to?(:view_changesets, issue.project)
515 525 pdf.SetFontStyle('B',9)
516 526 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
517 527 pdf.Ln
518 528 for changeset in issue.changesets
519 529 pdf.SetFontStyle('B',8)
520 530 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
521 531 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
522 532 pdf.RDMCell(190, 5, csstr)
523 533 pdf.Ln
524 534 unless changeset.comments.blank?
525 535 pdf.SetFontStyle('',8)
526 536 pdf.RDMwriteHTMLCell(190,5,0,0,
527 537 changeset.comments.to_s, issue.attachments, "")
528 538 end
529 539 pdf.Ln
530 540 end
531 541 end
532 542
533 543 pdf.SetFontStyle('B',9)
534 544 pdf.RDMCell(190,5, l(:label_history), "B")
535 545 pdf.Ln
536 546 indice = 0
537 547 for journal in issue.journals.find(
538 548 :all, :include => [:user, :details],
539 549 :order => "#{Journal.table_name}.created_on ASC")
540 550 indice = indice + 1
541 551 pdf.SetFontStyle('B',8)
542 552 pdf.RDMCell(190,5,
543 553 "#" + indice.to_s +
544 554 " - " + format_time(journal.created_on) +
545 555 " - " + journal.user.name)
546 556 pdf.Ln
547 557 pdf.SetFontStyle('I',8)
548 558 details_to_strings(journal.details, true).each do |string|
549 559 pdf.RDMMultiCell(190,5, "- " + string)
550 560 end
551 561 if journal.notes?
552 562 pdf.Ln unless journal.details.empty?
553 563 pdf.SetFontStyle('',8)
554 564 pdf.RDMwriteHTMLCell(190,5,0,0,
555 565 journal.notes.to_s, issue.attachments, "")
556 566 end
557 567 pdf.Ln
558 568 end
559 569
560 570 if issue.attachments.any?
561 571 pdf.SetFontStyle('B',9)
562 572 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
563 573 pdf.Ln
564 574 for attachment in issue.attachments
565 575 pdf.SetFontStyle('',8)
566 576 pdf.RDMCell(80,5, attachment.filename)
567 577 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
568 578 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
569 579 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
570 580 pdf.Ln
571 581 end
572 582 end
573 583 pdf.Output
574 584 end
575 585
576 586 # Returns a PDF string of a set of wiki pages
577 587 def wiki_pages_to_pdf(pages, project)
578 588 pdf = ITCPDF.new(current_language)
579 589 pdf.SetTitle(project.name)
580 590 pdf.alias_nb_pages
581 591 pdf.footer_date = format_date(Date.today)
582 592 pdf.AddPage
583 593 pdf.SetFontStyle('B',11)
584 594 pdf.RDMMultiCell(190,5, project.name)
585 595 pdf.Ln
586 596 # Set resize image scale
587 597 pdf.SetImageScale(1.6)
588 598 pdf.SetFontStyle('',9)
589 599 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
590 600 pdf.Output
591 601 end
592 602
593 603 # Returns a PDF string of a single wiki page
594 604 def wiki_page_to_pdf(page, project)
595 605 pdf = ITCPDF.new(current_language)
596 606 pdf.SetTitle("#{project} - #{page.title}")
597 607 pdf.alias_nb_pages
598 608 pdf.footer_date = format_date(Date.today)
599 609 pdf.AddPage
600 610 pdf.SetFontStyle('B',11)
601 611 pdf.RDMMultiCell(190,5,
602 612 "#{project} - #{page.title} - # #{page.content.version}")
603 613 pdf.Ln
604 614 # Set resize image scale
605 615 pdf.SetImageScale(1.6)
606 616 pdf.SetFontStyle('',9)
607 617 write_wiki_page(pdf, page)
608 618 pdf.Output
609 619 end
610 620
611 621 def write_page_hierarchy(pdf, pages, node=nil, level=0)
612 622 if pages[node]
613 623 pages[node].each do |page|
614 624 if @new_page
615 625 pdf.AddPage
616 626 else
617 627 @new_page = true
618 628 end
619 629 pdf.Bookmark page.title, level
620 630 write_wiki_page(pdf, page)
621 631 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
622 632 end
623 633 end
624 634 end
625 635
626 636 def write_wiki_page(pdf, page)
627 637 pdf.RDMwriteHTMLCell(190,5,0,0,
628 638 page.content.text.to_s, page.attachments, "TLRB")
629 639 if page.attachments.any?
630 640 pdf.Ln
631 641 pdf.SetFontStyle('B',9)
632 642 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
633 643 pdf.Ln
634 644 for attachment in page.attachments
635 645 pdf.SetFontStyle('',8)
636 646 pdf.RDMCell(80,5, attachment.filename)
637 647 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
638 648 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
639 649 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
640 650 pdf.Ln
641 651 end
642 652 end
643 653 end
644 654
645 655 class RDMPdfEncoding
646 656 def self.rdm_from_utf8(txt, encoding)
647 657 txt ||= ''
648 658 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
649 659 if txt.respond_to?(:force_encoding)
650 660 txt.force_encoding('ASCII-8BIT')
651 661 end
652 662 txt
653 663 end
654 664
655 665 def self.attach(attachments, filename, encoding)
656 666 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
657 667 atta = nil
658 668 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
659 669 atta = Attachment.latest_attach(attachments, filename_utf8)
660 670 end
661 671 if atta && atta.readable? && atta.visible?
662 672 return atta
663 673 else
664 674 return nil
665 675 end
666 676 end
667 677 end
668 678 end
669 679 end
670 680 end
General Comments 0
You need to be logged in to leave comments. Login now