##// END OF EJS Templates
Use IssueRelation#to_s in PDF export....
Jean-Philippe Lang -
r13182:78cc63e52cba
parent child
Show More
@@ -1,700 +1,698
1 1 # encoding: utf-8
2 2 #
3 3 # Redmine - project management software
4 4 # Copyright (C) 2006-2014 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 'rbpdf'
21 21
22 22 module Redmine
23 23 module Export
24 24 module PDF
25 25 include ActionView::Helpers::TextHelper
26 26 include ActionView::Helpers::NumberHelper
27 27 include IssuesHelper
28 28
29 29 class ITCPDF < RBPDF
30 30 include Redmine::I18n
31 31 attr_accessor :footer_date
32 32
33 33 def initialize(lang, orientation='P')
34 34 @@k_path_cache = Rails.root.join('tmp', 'pdf')
35 35 FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
36 36 set_language_if_valid lang
37 37 super(orientation, 'mm', 'A4')
38 38 set_print_header(false)
39 39 set_rtl(l(:direction) == 'rtl')
40 40 set_temp_rtl(l(:direction) == 'rtl' ? 'R' : 'L')
41 41
42 42 @font_for_content = l(:general_pdf_fontname)
43 43 @font_for_footer = l(:general_pdf_fontname)
44 44 set_creator(Redmine::Info.app_name)
45 45 set_font(@font_for_content)
46 46
47 47 set_header_font([@font_for_content, '', 10])
48 48 set_footer_font([@font_for_content, '', 8])
49 49 set_default_monospaced_font(@font_for_content)
50 50 end
51 51
52 52 def SetFontStyle(style, size)
53 53 style.delete!('B') if current_language.to_s.downcase == 'th' # FreeSerif Bold Thai font has problem.
54 54 set_font(@font_for_content, style, size)
55 55 end
56 56
57 57 def fix_text_encoding(txt)
58 58 RDMPdfEncoding::rdm_from_utf8(txt, "UTF-8")
59 59 end
60 60
61 61 def formatted_text(text)
62 62 html = Redmine::WikiFormatting.to_html(Setting.text_formatting, text)
63 63 # Strip {{toc}} tags
64 64 html.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i, '')
65 65 html
66 66 end
67 67
68 68 def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
69 69 cell(w, h, txt, border, ln, align, fill, link)
70 70 end
71 71
72 72 def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
73 73 multi_cell(w, h, txt, border, align, fill, ln)
74 74 end
75 75
76 76 def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
77 77 @attachments = attachments
78 78
79 79 css_tag = ' <style>
80 80 table, td {
81 81 border: 2px #ff0000 solid;
82 82 }
83 83 th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; text-align: center; font-style: bold;}
84 84 pre {
85 85 background-color: #fafafa;
86 86 }
87 87 </style>'
88 88
89 89 writeHTMLCell(w, h, x, y,
90 90 css_tag + formatted_text(txt),
91 91 border, ln, fill)
92 92 end
93 93
94 94 def get_image_filename(attrname)
95 95 atta = RDMPdfEncoding.attach(@attachments, attrname, "UTF-8")
96 96 if atta
97 97 return atta.diskfile
98 98 else
99 99 return nil
100 100 end
101 101 end
102 102
103 103 def get_sever_url(url)
104 104 if !empty_string(url) and (url[0, 1] == '/')
105 105 Setting.host_name.split('/')[0] + url
106 106 else
107 107 url
108 108 end
109 109 end
110 110
111 111 def Footer
112 112 set_font(@font_for_footer, 'I', 8)
113 113 set_x(15)
114 114 if get_rtl
115 115 RDMCell(0, 5, @footer_date, 0, 0, 'R')
116 116 else
117 117 RDMCell(0, 5, @footer_date, 0, 0, 'L')
118 118 end
119 119 set_x(-30)
120 120 RDMCell(0, 5, get_alias_num_page() + '/' + get_alias_nb_pages(), 0, 0, 'C')
121 121 end
122 122 end
123 123
124 124 def is_cjk?
125 125 case current_language.to_s.downcase
126 126 when 'ja', 'zh-tw', 'zh', 'ko'
127 127 true
128 128 else
129 129 false
130 130 end
131 131 end
132 132
133 133 # fetch row values
134 134 def fetch_row_values(issue, query, level)
135 135 query.inline_columns.collect do |column|
136 136 s = if column.is_a?(QueryCustomFieldColumn)
137 137 cv = issue.visible_custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
138 138 show_value(cv, false)
139 139 else
140 140 value = issue.send(column.name)
141 141 if column.name == :subject
142 142 value = " " * level + value
143 143 end
144 144 if value.is_a?(Date)
145 145 format_date(value)
146 146 elsif value.is_a?(Time)
147 147 format_time(value)
148 148 else
149 149 value
150 150 end
151 151 end
152 152 s.to_s
153 153 end
154 154 end
155 155
156 156 # calculate columns width
157 157 def calc_col_width(issues, query, table_width, pdf)
158 158 # calculate statistics
159 159 # by captions
160 160 pdf.SetFontStyle('B',8)
161 161 margins = pdf.get_margins
162 162 col_padding = margins['cell']
163 163 col_width_min = query.inline_columns.map {|v| pdf.get_string_width(v.caption) + col_padding}
164 164 col_width_max = Array.new(col_width_min)
165 165 col_width_avg = Array.new(col_width_min)
166 166 col_min = pdf.get_string_width('OO') + col_padding * 2
167 167 if table_width > col_min * col_width_avg.length
168 168 table_width -= col_min * col_width_avg.length
169 169 else
170 170 col_min = pdf.get_string_width('O') + col_padding * 2
171 171 if table_width > col_min * col_width_avg.length
172 172 table_width -= col_min * col_width_avg.length
173 173 else
174 174 ratio = table_width / col_width_avg.inject(0, :+)
175 175 return col_width = col_width_avg.map {|w| w * ratio}
176 176 end
177 177 end
178 178 word_width_max = query.inline_columns.map {|c|
179 179 n = 10
180 180 c.caption.split.each {|w|
181 181 x = pdf.get_string_width(w) + col_padding
182 182 n = x if n < x
183 183 }
184 184 n
185 185 }
186 186
187 187 # by properties of issues
188 188 pdf.SetFontStyle('',8)
189 189 k = 1
190 190 issue_list(issues) {|issue, level|
191 191 k += 1
192 192 values = fetch_row_values(issue, query, level)
193 193 values.each_with_index {|v,i|
194 194 n = pdf.get_string_width(v) + col_padding * 2
195 195 col_width_max[i] = n if col_width_max[i] < n
196 196 col_width_min[i] = n if col_width_min[i] > n
197 197 col_width_avg[i] += n
198 198 v.split.each {|w|
199 199 x = pdf.get_string_width(w) + col_padding
200 200 word_width_max[i] = x if word_width_max[i] < x
201 201 }
202 202 }
203 203 }
204 204 col_width_avg.map! {|x| x / k}
205 205
206 206 # calculate columns width
207 207 ratio = table_width / col_width_avg.inject(0, :+)
208 208 col_width = col_width_avg.map {|w| w * ratio}
209 209
210 210 # correct max word width if too many columns
211 211 ratio = table_width / word_width_max.inject(0, :+)
212 212 word_width_max.map! {|v| v * ratio} if ratio < 1
213 213
214 214 # correct and lock width of some columns
215 215 done = 1
216 216 col_fix = []
217 217 col_width.each_with_index do |w,i|
218 218 if w > col_width_max[i]
219 219 col_width[i] = col_width_max[i]
220 220 col_fix[i] = 1
221 221 done = 0
222 222 elsif w < word_width_max[i]
223 223 col_width[i] = word_width_max[i]
224 224 col_fix[i] = 1
225 225 done = 0
226 226 else
227 227 col_fix[i] = 0
228 228 end
229 229 end
230 230
231 231 # iterate while need to correct and lock coluns width
232 232 while done == 0
233 233 # calculate free & locked columns width
234 234 done = 1
235 235 ratio = table_width / col_width.inject(0, :+)
236 236
237 237 # correct columns width
238 238 col_width.each_with_index do |w,i|
239 239 if col_fix[i] == 0
240 240 col_width[i] = w * ratio
241 241
242 242 # check if column width less then max word width
243 243 if col_width[i] < word_width_max[i]
244 244 col_width[i] = word_width_max[i]
245 245 col_fix[i] = 1
246 246 done = 0
247 247 elsif col_width[i] > col_width_max[i]
248 248 col_width[i] = col_width_max[i]
249 249 col_fix[i] = 1
250 250 done = 0
251 251 end
252 252 end
253 253 end
254 254 end
255 255
256 256 ratio = table_width / col_width.inject(0, :+)
257 257 col_width.map! {|v| v * ratio + col_min}
258 258 col_width
259 259 end
260 260
261 261 def render_table_header(pdf, query, col_width, row_height, table_width)
262 262 # headers
263 263 pdf.SetFontStyle('B',8)
264 264 pdf.set_fill_color(230, 230, 230)
265 265
266 266 base_x = pdf.get_x
267 267 base_y = pdf.get_y
268 268 max_height = get_issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, true)
269 269
270 270 # write the cells on page
271 271 issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, max_height, true)
272 272 pdf.set_xy(base_x, base_y + max_height)
273 273
274 274 # rows
275 275 pdf.SetFontStyle('',8)
276 276 pdf.set_fill_color(255, 255, 255)
277 277 end
278 278
279 279 # Returns a PDF string of a list of issues
280 280 def issues_to_pdf(issues, project, query)
281 281 pdf = ITCPDF.new(current_language, "L")
282 282 title = query.new_record? ? l(:label_issue_plural) : query.name
283 283 title = "#{project} - #{title}" if project
284 284 pdf.set_title(title)
285 285 pdf.alias_nb_pages
286 286 pdf.footer_date = format_date(Date.today)
287 287 pdf.set_auto_page_break(false)
288 288 pdf.add_page("L")
289 289
290 290 # Landscape A4 = 210 x 297 mm
291 291 page_height = pdf.get_page_height # 210
292 292 page_width = pdf.get_page_width # 297
293 293 left_margin = pdf.get_original_margins['left'] # 10
294 294 right_margin = pdf.get_original_margins['right'] # 10
295 295 bottom_margin = pdf.get_footer_margin
296 296 row_height = 4
297 297
298 298 # column widths
299 299 table_width = page_width - right_margin - left_margin
300 300 col_width = []
301 301 unless query.inline_columns.empty?
302 302 col_width = calc_col_width(issues, query, table_width, pdf)
303 303 table_width = col_width.inject(0, :+)
304 304 end
305 305
306 306 # use full width if the description is displayed
307 307 if table_width > 0 && query.has_column?(:description)
308 308 col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width}
309 309 table_width = col_width.inject(0, :+)
310 310 end
311 311
312 312 # title
313 313 pdf.SetFontStyle('B',11)
314 314 pdf.RDMCell(190,10, title)
315 315 pdf.ln
316 316
317 317 render_table_header(pdf, query, col_width, row_height, table_width)
318 318 previous_group = false
319 319 issue_list(issues) do |issue, level|
320 320 if query.grouped? &&
321 321 (group = query.group_by_column.value(issue)) != previous_group
322 322 pdf.SetFontStyle('B',10)
323 323 group_label = group.blank? ? 'None' : group.to_s.dup
324 324 group_label << " (#{query.issue_count_by_group[group]})"
325 325 pdf.bookmark group_label, 0, -1
326 326 pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L')
327 327 pdf.SetFontStyle('',8)
328 328 previous_group = group
329 329 end
330 330
331 331 # fetch row values
332 332 col_values = fetch_row_values(issue, query, level)
333 333
334 334 # make new page if it doesn't fit on the current one
335 335 base_y = pdf.get_y
336 336 max_height = get_issues_to_pdf_write_cells(pdf, col_values, col_width)
337 337 space_left = page_height - base_y - bottom_margin
338 338 if max_height > space_left
339 339 pdf.add_page("L")
340 340 render_table_header(pdf, query, col_width, row_height, table_width)
341 341 base_y = pdf.get_y
342 342 end
343 343
344 344 # write the cells on page
345 345 issues_to_pdf_write_cells(pdf, col_values, col_width, max_height)
346 346 pdf.set_y(base_y + max_height)
347 347
348 348 if query.has_column?(:description) && issue.description?
349 349 pdf.set_x(10)
350 350 pdf.set_auto_page_break(true, bottom_margin)
351 351 pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.description.to_s, issue.attachments, "LRBT")
352 352 pdf.set_auto_page_break(false)
353 353 end
354 354 end
355 355
356 356 if issues.size == Setting.issues_export_limit.to_i
357 357 pdf.SetFontStyle('B',10)
358 358 pdf.RDMCell(0, row_height, '...')
359 359 end
360 360 pdf.output
361 361 end
362 362
363 363 # returns the maximum height of MultiCells
364 364 def get_issues_to_pdf_write_cells(pdf, col_values, col_widths, head=false)
365 365 heights = []
366 366 col_values.each_with_index do |column, i|
367 367 heights << pdf.get_string_height(col_widths[i], head ? column.caption : column)
368 368 end
369 369 return heights.max
370 370 end
371 371
372 372 # Renders MultiCells and returns the maximum height used
373 373 def issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height, head=false)
374 374 col_values.each_with_index do |column, i|
375 375 pdf.RDMMultiCell(col_widths[i], row_height, head ? column.caption : column.strip, 1, '', 1, 0)
376 376 end
377 377 end
378 378
379 379 # Draw lines to close the row (MultiCell border drawing in not uniform)
380 380 #
381 381 # parameter "col_id_width" is not used. it is kept for compatibility.
382 382 def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
383 383 col_id_width, col_widths, rtl=false)
384 384 col_x = top_x
385 385 pdf.line(col_x, top_y, col_x, lower_y) # id right border
386 386 col_widths.each do |width|
387 387 if rtl
388 388 col_x -= width
389 389 else
390 390 col_x += width
391 391 end
392 392 pdf.line(col_x, top_y, col_x, lower_y) # columns right border
393 393 end
394 394 pdf.line(top_x, top_y, top_x, lower_y) # left border
395 395 pdf.line(top_x, lower_y, col_x, lower_y) # bottom border
396 396 end
397 397
398 398 # Returns a PDF string of a single issue
399 399 def issue_to_pdf(issue, assoc={})
400 400 pdf = ITCPDF.new(current_language)
401 401 pdf.set_title("#{issue.project} - #{issue.tracker} ##{issue.id}")
402 402 pdf.alias_nb_pages
403 403 pdf.footer_date = format_date(Date.today)
404 404 pdf.add_page
405 405 pdf.SetFontStyle('B',11)
406 406 buf = "#{issue.project} - #{issue.tracker} ##{issue.id}"
407 407 pdf.RDMMultiCell(190, 5, buf)
408 408 pdf.SetFontStyle('',8)
409 409 base_x = pdf.get_x
410 410 i = 1
411 411 issue.ancestors.visible.each do |ancestor|
412 412 pdf.set_x(base_x + i)
413 413 buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
414 414 pdf.RDMMultiCell(190 - i, 5, buf)
415 415 i += 1 if i < 35
416 416 end
417 417 pdf.SetFontStyle('B',11)
418 418 pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s)
419 419 pdf.SetFontStyle('',8)
420 420 pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}")
421 421 pdf.ln
422 422
423 423 left = []
424 424 left << [l(:field_status), issue.status]
425 425 left << [l(:field_priority), issue.priority]
426 426 left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id')
427 427 left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id')
428 428 left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id')
429 429
430 430 right = []
431 431 right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date')
432 432 right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date')
433 433 right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio')
434 434 right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours')
435 435 right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project)
436 436
437 437 rows = left.size > right.size ? left.size : right.size
438 438 while left.size < rows
439 439 left << nil
440 440 end
441 441 while right.size < rows
442 442 right << nil
443 443 end
444 444
445 445 half = (issue.visible_custom_field_values.size / 2.0).ceil
446 446 issue.visible_custom_field_values.each_with_index do |custom_value, i|
447 447 (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value, false)]
448 448 end
449 449
450 450 if pdf.get_rtl
451 451 border_first_top = 'RT'
452 452 border_last_top = 'LT'
453 453 border_first = 'R'
454 454 border_last = 'L'
455 455 else
456 456 border_first_top = 'LT'
457 457 border_last_top = 'RT'
458 458 border_first = 'L'
459 459 border_last = 'R'
460 460 end
461 461
462 462 rows = left.size > right.size ? left.size : right.size
463 463 rows.times do |i|
464 464 heights = []
465 465 pdf.SetFontStyle('B',9)
466 466 item = left[i]
467 467 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
468 468 item = right[i]
469 469 heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
470 470 pdf.SetFontStyle('',9)
471 471 item = left[i]
472 472 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
473 473 item = right[i]
474 474 heights << pdf.get_string_height(60, item ? item.last.to_s : "")
475 475 height = heights.max
476 476
477 477 item = left[i]
478 478 pdf.SetFontStyle('B',9)
479 479 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
480 480 pdf.SetFontStyle('',9)
481 481 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 0)
482 482
483 483 item = right[i]
484 484 pdf.SetFontStyle('B',9)
485 485 pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
486 486 pdf.SetFontStyle('',9)
487 487 pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 2)
488 488
489 489 pdf.set_x(base_x)
490 490 end
491 491
492 492 pdf.SetFontStyle('B',9)
493 493 pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1)
494 494 pdf.SetFontStyle('',9)
495 495
496 496 # Set resize image scale
497 497 pdf.set_image_scale(1.6)
498 498 pdf.RDMwriteHTMLCell(35+155, 5, '', '',
499 499 issue.description.to_s, issue.attachments, "LRB")
500 500
501 501 unless issue.leaf?
502 502 truncate_length = (!is_cjk? ? 90 : 65)
503 503 pdf.SetFontStyle('B',9)
504 504 pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
505 505 pdf.ln
506 506 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
507 507 buf = "#{child.tracker} # #{child.id}: #{child.subject}".
508 508 truncate(truncate_length)
509 509 level = 10 if level >= 10
510 510 pdf.SetFontStyle('',8)
511 511 pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, border_first)
512 512 pdf.SetFontStyle('B',8)
513 513 pdf.RDMCell(20,5, child.status.to_s, border_last)
514 514 pdf.ln
515 515 end
516 516 end
517 517
518 518 relations = issue.relations.select { |r| r.other_issue(issue).visible? }
519 519 unless relations.empty?
520 520 truncate_length = (!is_cjk? ? 80 : 60)
521 521 pdf.SetFontStyle('B',9)
522 522 pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
523 523 pdf.ln
524 524 relations.each do |relation|
525 buf = ""
526 buf += "#{l(relation.label_for(issue))} "
527 if relation.delay && relation.delay != 0
528 buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) "
529 end
530 if Setting.cross_project_issue_relations?
531 buf += "#{relation.other_issue(issue).project} - "
532 end
533 buf += "#{relation.other_issue(issue).tracker}" +
534 " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
525 buf = relation.to_s(issue) {|other|
526 text = ""
527 if Setting.cross_project_issue_relations?
528 text += "#{relation.other_issue(issue).project} - "
529 end
530 text += "#{other.tracker} ##{other.id}: #{other.subject}"
531 text
532 }
535 533 buf = buf.truncate(truncate_length)
536 534 pdf.SetFontStyle('', 8)
537 535 pdf.RDMCell(35+155-60, 5, buf, border_first)
538 536 pdf.SetFontStyle('B',8)
539 537 pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
540 538 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
541 539 pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), border_last)
542 540 pdf.ln
543 541 end
544 542 end
545 543 pdf.RDMCell(190,5, "", "T")
546 544 pdf.ln
547 545
548 546 if issue.changesets.any? &&
549 547 User.current.allowed_to?(:view_changesets, issue.project)
550 548 pdf.SetFontStyle('B',9)
551 549 pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
552 550 pdf.ln
553 551 for changeset in issue.changesets
554 552 pdf.SetFontStyle('B',8)
555 553 csstr = "#{l(:label_revision)} #{changeset.format_identifier} - "
556 554 csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
557 555 pdf.RDMCell(190, 5, csstr)
558 556 pdf.ln
559 557 unless changeset.comments.blank?
560 558 pdf.SetFontStyle('',8)
561 559 pdf.RDMwriteHTMLCell(190,5,'','',
562 560 changeset.comments.to_s, issue.attachments, "")
563 561 end
564 562 pdf.ln
565 563 end
566 564 end
567 565
568 566 if assoc[:journals].present?
569 567 pdf.SetFontStyle('B',9)
570 568 pdf.RDMCell(190,5, l(:label_history), "B")
571 569 pdf.ln
572 570 assoc[:journals].each do |journal|
573 571 pdf.SetFontStyle('B',8)
574 572 title = "##{journal.indice} - #{format_time(journal.created_on)} - #{journal.user}"
575 573 title << " (#{l(:field_private_notes)})" if journal.private_notes?
576 574 pdf.RDMCell(190,5, title)
577 575 pdf.ln
578 576 pdf.SetFontStyle('I',8)
579 577 details_to_strings(journal.visible_details, true).each do |string|
580 578 pdf.RDMMultiCell(190,5, "- " + string)
581 579 end
582 580 if journal.notes?
583 581 pdf.ln unless journal.details.empty?
584 582 pdf.SetFontStyle('',8)
585 583 pdf.RDMwriteHTMLCell(190,5,'','',
586 584 journal.notes.to_s, issue.attachments, "")
587 585 end
588 586 pdf.ln
589 587 end
590 588 end
591 589
592 590 if issue.attachments.any?
593 591 pdf.SetFontStyle('B',9)
594 592 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
595 593 pdf.ln
596 594 for attachment in issue.attachments
597 595 pdf.SetFontStyle('',8)
598 596 pdf.RDMCell(80,5, attachment.filename)
599 597 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
600 598 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
601 599 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
602 600 pdf.ln
603 601 end
604 602 end
605 603 pdf.output
606 604 end
607 605
608 606 # Returns a PDF string of a set of wiki pages
609 607 def wiki_pages_to_pdf(pages, project)
610 608 pdf = ITCPDF.new(current_language)
611 609 pdf.set_title(project.name)
612 610 pdf.alias_nb_pages
613 611 pdf.footer_date = format_date(Date.today)
614 612 pdf.add_page
615 613 pdf.SetFontStyle('B',11)
616 614 pdf.RDMMultiCell(190,5, project.name)
617 615 pdf.ln
618 616 # Set resize image scale
619 617 pdf.set_image_scale(1.6)
620 618 pdf.SetFontStyle('',9)
621 619 write_page_hierarchy(pdf, pages.group_by(&:parent_id))
622 620 pdf.output
623 621 end
624 622
625 623 # Returns a PDF string of a single wiki page
626 624 def wiki_page_to_pdf(page, project)
627 625 pdf = ITCPDF.new(current_language)
628 626 pdf.set_title("#{project} - #{page.title}")
629 627 pdf.alias_nb_pages
630 628 pdf.footer_date = format_date(Date.today)
631 629 pdf.add_page
632 630 pdf.SetFontStyle('B',11)
633 631 pdf.RDMMultiCell(190,5,
634 632 "#{project} - #{page.title} - # #{page.content.version}")
635 633 pdf.ln
636 634 # Set resize image scale
637 635 pdf.set_image_scale(1.6)
638 636 pdf.SetFontStyle('',9)
639 637 write_wiki_page(pdf, page)
640 638 pdf.output
641 639 end
642 640
643 641 def write_page_hierarchy(pdf, pages, node=nil, level=0)
644 642 if pages[node]
645 643 pages[node].each do |page|
646 644 if @new_page
647 645 pdf.add_page
648 646 else
649 647 @new_page = true
650 648 end
651 649 pdf.bookmark page.title, level
652 650 write_wiki_page(pdf, page)
653 651 write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
654 652 end
655 653 end
656 654 end
657 655
658 656 def write_wiki_page(pdf, page)
659 657 pdf.RDMwriteHTMLCell(190,5,'','',
660 658 page.content.text.to_s, page.attachments, 0)
661 659 if page.attachments.any?
662 660 pdf.ln(5)
663 661 pdf.SetFontStyle('B',9)
664 662 pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
665 663 pdf.ln
666 664 for attachment in page.attachments
667 665 pdf.SetFontStyle('',8)
668 666 pdf.RDMCell(80,5, attachment.filename)
669 667 pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
670 668 pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
671 669 pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
672 670 pdf.ln
673 671 end
674 672 end
675 673 end
676 674
677 675 class RDMPdfEncoding
678 676 def self.rdm_from_utf8(txt, encoding)
679 677 txt ||= ''
680 678 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
681 679 txt.force_encoding('ASCII-8BIT')
682 680 txt
683 681 end
684 682
685 683 def self.attach(attachments, filename, encoding)
686 684 filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding)
687 685 atta = nil
688 686 if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i
689 687 atta = Attachment.latest_attach(attachments, filename_utf8)
690 688 end
691 689 if atta && atta.readable? && atta.visible?
692 690 return atta
693 691 else
694 692 return nil
695 693 end
696 694 end
697 695 end
698 696 end
699 697 end
700 698 end
General Comments 0
You need to be logged in to leave comments. Login now