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