issues-pdf-r9244.diff

Toshi MARUYAMA, 2012-03-18 09:02

Download (10.2 KB)

View differences:

lib/redmine/export/pdf.rb
234 234
        end
235 235
      end
236 236

  
237
      # fetch row values
238
      def fetch_row_values(issue, query, level)
239
        query.columns.collect do |column|
240
          s = if column.is_a?(QueryCustomFieldColumn)
241
            cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
242
            show_value(cv)
243
          else
244
            value = issue.send(column.name)
245
            if column.name == :subject
246
              value = "  " * level + value
247
            end
248
            if value.is_a?(Date)
249
              format_date(value)
250
            elsif value.is_a?(Time)
251
              format_time(value)
252
            else
253
              value
254
            end
255
          end
256
          s.to_s
257
        end
258
      end
259

  
260
      # calculate columns width
261
      def calc_col_width(issues, query, table_width, pdf)
262
        # calculate statistics
263
        #  by captions
264
        col_width_min = query.columns.map {|v| pdf.GetStringWidth(v.caption)}
265
        col_width_max = Array.new(col_width_min)
266
        col_width_avg = Array.new(col_width_min)
267
        word_width_max = query.columns.map {|c| 
268
          n = 10
269
          c.caption.split.each {|w| 
270
            x = pdf.GetStringWidth(w)
271
            n = x if n < x
272
          }
273
          n
274
        }
275

  
276
        #  by properties of issues
277
        k = 1
278
        issue_list(issues) {|issue, level|
279
          k += 1
280
          values = fetch_row_values(issue, query, level)
281
          values.each_with_index {|v,i| 
282
            n = pdf.GetStringWidth(v.rstrip)
283
            col_width_max[i] = n if col_width_max[i] < n
284
            col_width_min[i] = n if col_width_min[i] > n
285
            col_width_avg[i] += n
286
            v.split.each {|w| 
287
              x = pdf.GetStringWidth(w); 
288
              word_width_max[i] = x if word_width_max[i] < x
289
            }
290
          }
291
        }
292
        col_width_avg.map! {|x| x / k}
293

  
294
        # calculate columns width
295
        ratio = table_width / col_width_avg.inject(0) {|s,w| s += w}
296
        col_width = col_width_avg.map {|w| w * ratio}
297

  
298
        # correct max word width if too many columns
299
        ratio = table_width / word_width_max.inject(0) {|s,w| s += w}
300
        word_width_max.map! {|v| v * ratio} if ratio < 1
301

  
302
        # correct and lock width of some columns
303
        done = 1
304
        col_fix = []
305
        col_width.each_with_index do |w,i| 
306
          if w > col_width_max[i]
307
            col_width[i] = col_width_max[i]
308
            col_fix[i] = 1
309
            done = 0
310
          elsif w < word_width_max[i]
311
            col_width[i] = word_width_max[i]
312
            col_fix[i] = 1
313
            done = 0
314
          else
315
            col_fix[i] = 0
316
          end
317
        end
318

  
319
        # iterate while need to correct and lock coluns width
320
        while done == 0 
321
          # calculate free & locked columns width
322
          done = 1
323
          fix_col_width = 0
324
          free_col_width = 0
325
          col_width.each_with_index do |w,i|
326
            if col_fix[i] == 1
327
              fix_col_width += w
328
            else
329
              free_col_width += w
330
            end
331
          end
332

  
333
          # calculate column normalizing ratio
334
          if free_col_width == 0
335
            ratio = table_width / col_width.inject(0) {|s,w| s += w}
336
          else
337
            ratio = (table_width - fix_col_width) / free_col_width
338
          end
339

  
340
          # correct columns width
341
          col_width.each_with_index do |w,i| 
342
            if col_fix[i] == 0
343
              col_width[i] = w * ratio
344

  
345
              # check if column width less then max word width
346
              if col_width[i] < word_width_max[i]
347
                col_width[i] = word_width_max[i]
348
                col_fix[i] = 1
349
                done = 0
350
              end
351
            end
352
          end
353
        end 
354
        col_width
355
      end
356

  
357
      def render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
358
        # headers
359
        pdf.SetFontStyle('B',8)
360
        pdf.SetFillColor(230, 230, 230)
361

  
362
        # render it background to find the max height used
363
        base_x = pdf.GetX
364
        base_y = pdf.GetY
365
        max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
366
        pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
367
        pdf.SetXY(base_x, base_y);
368

  
369
        # write the cells on page
370
        pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
371
        issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
372
        issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
373
        pdf.SetY(base_y + max_height);
374

  
375
        # rows
376
        pdf.SetFontStyle('',8)
377
        pdf.SetFillColor(255, 255, 255)
378
      end
379

  
237 380
      # Returns a PDF string of a list of issues
238 381
      def issues_to_pdf(issues, project, query)
239 382
        pdf = ITCPDF.new(current_language)
......
257 400
        table_width = page_width - right_margin - 10  # fixed left margin
258 401
        col_width = []
259 402
        unless query.columns.empty?
260
          col_width = query.columns.collect do |c|
261
            (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
262
              ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
263
          end
264
          ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
265
          col_width = col_width.collect {|w| w * ratio}
403
          col_width = calc_col_width(issues, query, table_width - col_id_width, pdf)
404
          table_width = col_width.inject(0) {|s,v| s += v}
266 405
        end
267 406

  
268 407
        # title
......
270 409
        pdf.RDMCell(190,10, title)
271 410
        pdf.Ln
272 411

  
273
        # headers
274
        pdf.SetFontStyle('B',8)
275
        pdf.SetFillColor(230, 230, 230)
412
        render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
276 413

  
277
        # render it background to find the max height used
278
        base_x = pdf.GetX
279
        base_y = pdf.GetY
280
        max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
281
        pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
282
        pdf.SetXY(base_x, base_y);
283

  
284
        # write the cells on page
285
        pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
286
        issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
287
        issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
288
        pdf.SetY(base_y + max_height);
289

  
290
        # rows
291
        pdf.SetFontStyle('',8)
292
        pdf.SetFillColor(255, 255, 255)
293 414
        previous_group = false
294 415
        issue_list(issues) do |issue, level|
295 416
          if query.grouped? &&
296 417
               (group = query.group_by_column.value(issue)) != previous_group
297
            pdf.SetFontStyle('B',9)
418
            pdf.SetFontStyle('B',10)
298 419
            group_label = group.blank? ? 'None' : group.to_s
299 420
            group_label << " (#{query.issue_count_by_group[group]})"
300 421
            pdf.Bookmark group_label, 0, -1
301
            pdf.RDMCell(277, row_height, group_label, 1, 1, 'L')
422
            pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L')
302 423
            pdf.SetFontStyle('',8)
303 424
            previous_group = group
304 425
          end
305
          # fetch all the row values
306
          col_values = query.columns.collect do |column|
307
            s = if column.is_a?(QueryCustomFieldColumn)
308
              cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
309
              show_value(cv)
310
            else
311
              value = issue.send(column.name)
312
              if column.name == :subject
313
                value = "  " * level + value
314
              end
315
              if value.is_a?(Date)
316
                format_date(value)
317
              elsif value.is_a?(Time)
318
                format_time(value)
319
              else
320
                value
321
              end
322
            end
323
            s.to_s
324
          end
426

  
427
          # fetch row values
428
          col_values = fetch_row_values(issue, query, level)
325 429

  
326 430
          # render it off-page to find the max height used
327 431
          base_x = pdf.GetX
......
336 440
            pdf.AddPage("L")
337 441
            base_x = pdf.GetX
338 442
            base_y = pdf.GetY
443
            render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
339 444
          end
340 445

  
341 446
          # write the cells on page
lib/redmine/export/pdf.rb
351 351
            end
352 352
          end
353 353
        end 
354
        # calculate columns alignment
355
        @col_align = col_width.map {|x| x < table_width / col_width.count ? 'C' : 'L'}
354 356
        col_width
355 357
      end
356 358

  
......
460 462
      # Renders MultiCells and returns the maximum height used
461 463
      def issues_to_pdf_write_cells(pdf, col_values, col_widths,
462 464
                                    row_height, head=false)
465
        @col_align ||= []
463 466
        base_y = pdf.GetY
464 467
        max_height = row_height
465 468
        col_values.each_with_index do |column, i|
466 469
          col_x = pdf.GetX
467 470
          if head == true
468
            pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
471
            pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'C', 1)
469 472
          else
470
            pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
473
            @col_align[i] = 'L' if @col_align[i].nil?
474
            pdf.RDMMultiCell(col_widths[i], row_height, column, "T", @col_align[i], 1)
471 475
          end
472 476
          max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
473 477
          pdf.SetXY(col_x + col_widths[i], base_y);