Module: Redmine::Export::PDF

Includes:
ActionView::Helpers::NumberHelper, ActionView::Helpers::TextHelper
Included in:
GanttsController, IssuesController
Defined in:
lib/redmine/export/pdf.rb

Defined Under Namespace

Classes: IFPDF, ITCPDF

Instance Method Summary (collapse)

Instance Method Details

- (Object) issue_to_pdf(issue)

Returns a PDF string of a single issue



314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/redmine/export/pdf.rb', line 314

def issue_to_pdf(issue)
  if ( current_language.to_s.downcase == 'ko'    ||
       current_language.to_s.downcase == 'ja'    ||
       current_language.to_s.downcase == 'zh'    ||
       current_language.to_s.downcase == 'zh-tw' ||
       current_language.to_s.downcase == 'th'    )
    pdf = IFPDF.new(current_language)
  else
    pdf = ITCPDF.new(current_language)
  end
  pdf.SetTitle("#{issue.project} - ##{issue.tracker} #{issue.id}")
  pdf.alias_nb_pages
  pdf.footer_date = format_date(Date.today)
  pdf.AddPage

  pdf.SetFontStyle('B',11)
  pdf.RDMMultiCell(190,5, "#{issue.project} - #{issue.tracker} # #{issue.id}: #{issue.subject}")
  pdf.Ln

  y0 = pdf.GetY

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_status) + ":","LT")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, issue.status.to_s,"RT")
  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_priority) + ":","LT")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, issue.priority.to_s,"RT")
  pdf.Ln

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_author) + ":","L")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, issue.author.to_s,"R")
  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_category) + ":","L")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, issue.category.to_s,"R")
  pdf.Ln

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_created_on) + ":","L")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, format_date(issue.created_on),"R")
  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_assigned_to) + ":","L")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, issue.assigned_to.to_s,"R")
  pdf.Ln

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_updated_on) + ":","LB")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, format_date(issue.updated_on),"RB")
  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_due_date) + ":","LB")
  pdf.SetFontStyle('',9)
  pdf.RDMCell(60,5, format_date(issue.due_date),"RB")
  pdf.Ln

  for custom_value in issue.custom_field_values
    pdf.SetFontStyle('B',9)
    pdf.RDMCell(35,5, custom_value.custom_field.name + ":","L")
    pdf.SetFontStyle('',9)
    pdf.RDMMultiCell(155,5, (show_value custom_value),"R")
  end

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(35,5, l(:field_description) + ":")
  pdf.SetFontStyle('',9)
  pdf.RDMMultiCell(155,5, issue.description.to_s,"BR")

  pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
  pdf.Line(pdf.GetX, pdf.GetY, pdf.GetX + 190, pdf.GetY)
  pdf.Ln

  if issue.changesets.any? && User.current.allowed_to?(:view_changesets, issue.project)
    pdf.SetFontStyle('B',9)
    pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
    pdf.Ln
    for changeset in issue.changesets
      pdf.SetFontStyle('B',8)
      pdf.RDMCell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s)
      pdf.Ln
      unless changeset.comments.blank?
        pdf.SetFontStyle('',8)
        pdf.RDMMultiCell(190,5, changeset.comments.to_s)
      end
      pdf.Ln
    end
  end

  pdf.SetFontStyle('B',9)
  pdf.RDMCell(190,5, l(:label_history), "B")
  pdf.Ln
  for journal in issue.journals.find(:all, :include => [:user], :order => "#{Journal.table_name}.created_at ASC")
    next if journal.initial?
    pdf.SetFontStyle('B',8)
    pdf.RDMCell(190,5, format_time(journal.created_at) + " - " + journal.user.name)
    pdf.Ln
    pdf.SetFontStyle('I',8)
    for detail in journal.details
      pdf.RDMMultiCell(190,5, "- " + journal.render_detail(detail, true))
      pdf.Ln
    end
    if journal.notes?
      pdf.Ln unless journal.details.empty?
      pdf.SetFontStyle('',8)
      pdf.RDMMultiCell(190,5, journal.notes.to_s)
    end
    pdf.Ln
  end

  if issue.attachments.any?
    pdf.SetFontStyle('B',9)
    pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
    pdf.Ln
    for attachment in issue.attachments
      pdf.SetFontStyle('',8)
      pdf.RDMCell(80,5, attachment.filename)
      pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
      pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
      pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
      pdf.Ln
    end
  end
  pdf.Output
end

- (Object) issues_to_pdf(issues, project, query)

Returns a PDF string of a list of issues



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/redmine/export/pdf.rb', line 176

def issues_to_pdf(issues, project, query)
  if ( current_language.to_s.downcase == 'ko'    ||
       current_language.to_s.downcase == 'ja'    ||
       current_language.to_s.downcase == 'zh'    ||
       current_language.to_s.downcase == 'zh-tw' ||
       current_language.to_s.downcase == 'th'    )
    pdf = IFPDF.new(current_language)
  else
    pdf = ITCPDF.new(current_language)
  end
  title = query.new_record? ? l(:label_issue_plural) : query.name
  title = "#{project} - #{title}" if project
  pdf.SetTitle(title)
  pdf.alias_nb_pages
  pdf.footer_date = format_date(Date.today)
  pdf.SetAutoPageBreak(false)
  pdf.AddPage("L")

  # Landscape A4 = 210 x 297 mm
  page_height = 210
  page_width = 297
  right_margin = 10
  bottom_margin = 20
  col_id_width = 10
  row_height = 5

  # column widths
  table_width = page_width - right_margin - 10  # fixed left margin
  col_width = []
  unless query.columns.empty?
    col_width = query.columns.collect do |c|
      (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) && ['string', 'text'].include?(c.custom_field.field_format)))? 4.0 : 1.0
    end
    ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
    col_width = col_width.collect {|w| w * ratio}
  end

  # title
  pdf.SetFontStyle('B',11)
  pdf.RDMCell(190,10, title)
  pdf.Ln

  # headers
  pdf.SetFontStyle('B',8)
  pdf.SetFillColor(230, 230, 230)
  pdf.RDMCell(col_id_width, row_height, "#", 1, 0, 'L', 1)
  query.columns.each_with_index do |column, i|
    pdf.RDMCell(col_width[i], row_height, column.caption, 1, 0, 'L', 1)
  end
  pdf.Ln

  # rows
  pdf.SetFontStyle('',8)
  pdf.SetFillColor(255, 255, 255)
  previous_group = false
  issues.each do |issue|
    if query.grouped? && (group = query.group_by_column.value(issue)) != previous_group
      pdf.SetFontStyle('B',9)
      pdf.RDMCell(277, row_height,
        (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
        1, 1, 'L')
      pdf.SetFontStyle('',8)
      previous_group = group
    end

    # fetch all the row values
    col_values = query.columns.collect do |column|
      s = if column.is_a?(QueryCustomFieldColumn)
        cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
        show_value(cv)
      else
        value = issue.send(column.name)
        if value.is_a?(Date)
          format_date(value)
        elsif value.is_a?(Time)
          format_time(value)
        else
          value
        end
          end
      s.to_s
    end

    # render it off-page to find the max height used
    base_x = pdf.GetX
    base_y = pdf.GetY
    pdf.SetY(2 * page_height)
    max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
    pdf.SetXY(base_x, base_y)

    # make new page if it doesn't fit on the current one
    space_left = page_height - base_y - bottom_margin
    if max_height > space_left
      pdf.AddPage("L")
      base_x = pdf.GetX
      base_y = pdf.GetY
    end

    # write the cells on page
    pdf.Cell(col_id_width, row_height, issue.id.to_s, "T", 0, 'C', 1)
    issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
    issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
    pdf.SetY(base_y + max_height);
  end

  if issues.size == Setting.issues_export_limit.to_i
    pdf.SetFontStyle('B',10)
    pdf.RDMCell(0, row_height, '...')
  end
  pdf.Output
end

- (Object) issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, id_width, col_widths)

Draw lines to close the row (MultiCell border drawing in not uniform)



302
303
304
305
306
307
308
309
310
311
# File 'lib/redmine/export/pdf.rb', line 302

def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, id_width, col_widths)
  col_x = top_x + id_width
  pdf.Line(col_x, top_y, col_x, lower_y)    # id right border
  col_widths.each do |width|
    col_x += width
    pdf.Line(col_x, top_y, col_x, lower_y)  # columns right border
  end
  pdf.Line(top_x, top_y, top_x, lower_y)    # left border
  pdf.Line(top_x, lower_y, col_x, lower_y)  # bottom border
end

- (Object) issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height)

Renders MultiCells and returns the maximum height used



289
290
291
292
293
294
295
296
297
298
299
# File 'lib/redmine/export/pdf.rb', line 289

def issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height)
  base_y = pdf.GetY
  max_height = row_height
  col_values.each_with_index do |column, i|
    col_x = pdf.GetX
    pdf.RDMMultiCell(col_widths[i], row_height, col_values[i], "T", 'L', 1)
    max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
    pdf.SetXY(col_x + col_widths[i], base_y);
  end
  return max_height
end