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