Skip to content

Commit

Permalink
fixes colspan width calculations, e.g. #407
Browse files Browse the repository at this point in the history
  • Loading branch information
hbrandl authored and practicingruby committed Jan 2, 2014
1 parent 2c76ea7 commit a8026a5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 24 deletions.
31 changes: 9 additions & 22 deletions lib/prawn/table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
#
# This is free software. Please see the LICENSE and COPYING files for details.

require 'prawn/table/cells'
require 'prawn/table/cell'
require 'prawn/table/cell/in_table'
require 'prawn/table/cell/text'
require 'prawn/table/cell/subtable'
require 'prawn/table/cell/image'
require 'prawn/table/cell/span_dummy'
require_relative 'table/column_width_calculator'
require_relative 'table/cells'
require_relative 'table/cell'
require_relative 'table/cell/in_table'
require_relative 'table/cell/text'
require_relative 'table/cell/subtable'
require_relative 'table/cell/image'
require_relative 'table/cell/span_dummy'

module Prawn

Expand Down Expand Up @@ -549,21 +550,7 @@ def assert_proper_table_data(data)
# Returns an array of each column's natural (unconstrained) width.
#
def natural_column_widths
@natural_column_widths ||=
begin
widths_by_column = Hash.new(0)
cells.each do |cell|
next if cell.is_a?(Cell::SpanDummy)

# Split the width of colspanned cells evenly by columns
width_per_column = cell.width.to_f / cell.colspan
cell.colspan.times do |i|
widths_by_column[cell.column + i] =
[widths_by_column[cell.column + i], width_per_column].max
end
end
widths_by_column.sort_by { |col, _| col }.map { |_, w| w }
end
@natural_column_widths ||= ColumnWidthCalculator.new(cells).natural_widths
end

# Returns the "natural" (unconstrained) width of the table. This may be
Expand Down
55 changes: 55 additions & 0 deletions lib/prawn/table/column_width_calculator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module Prawn
class Table
class ColumnWidthCalculator
def initialize(cells)
@cells = cells

@widths_by_column = Hash.new(0)
@rows_with_a_span_dummy = Hash.new(false)
end

def natural_widths
@cells.each do |cell|
@rows_with_a_span_dummy[cell.row] = true if cell.is_a?(Cell::SpanDummy)
end

#calculate natural column width for all rows that do not include a span dummy
@cells.each do |cell|
unless @rows_with_a_span_dummy[cell.row]
@widths_by_column[cell.column] =
[@widths_by_column[cell.column], cell.width.to_f].max
end
end

#integrate natural column widths for all rows that do include a span dummy
@cells.each do |cell|
next unless @rows_with_a_span_dummy[cell.row]
#the width of a SpanDummy cell will be calculated by the "mother" cell
next if cell.is_a?(Cell::SpanDummy)

if cell.colspan == 1
@widths_by_column[cell.column] =
[@widths_by_column[cell.column], cell.width.to_f].max
else
#calculate the current with of all cells that will be spanned by the current cell
current_width_of_spanned_cells =
@widths_by_column.to_a[cell.column..(cell.column + cell.colspan - 1)]
.collect{|key, value| value}.inject(0, :+)

#update the Hash only if the new with is at least equal to the old one
if cell.width.to_f > current_width_of_spanned_cells
# Split the width of colspanned cells evenly by columns
width_per_column = cell.width.to_f / cell.colspan
# Update the Hash
cell.colspan.times do |i|
@widths_by_column[cell.column + i] = width_per_column
end
end
end
end

@widths_by_column.sort_by { |col, _| col }.map { |_, w| w }
end
end
end
end
25 changes: 23 additions & 2 deletions spec/table_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,36 @@
pdf = Prawn::Document.new
first = {:content=>"Foooo fo foooooo",:width=>50,:align=>:center}
second = {:content=>"Foooo",:colspan=>2,:width=>70,:align=>:center}
third = {:content=>"fooooooooooo, fooooooooooooo, fooo, foooooo fooooo",:width=>55,:align=>:center}
fourth = {:content=>"Bar",:width=>15,:align=>:center}
third = {:content=>"fooooooooooo, fooooooooooooo, fooo, foooooo fooooo",:width=>50,:align=>:center}
fourth = {:content=>"Bar",:width=>20,:align=>:center}
table_content = [[
first,
[[second],[third,fourth]]
]]
pdf.move_down(20)
table = Prawn::Table.new table_content, pdf
pdf.table(table_content)
end

#https://github.com/prawnpdf/prawn/issues/407#issuecomment-28556698
it "correctly computes column widths with empty cells + colspan" do
data = [['', ''],
[{:content => '', :colspan => 2}]
]
pdf = Prawn::Document.new

table = Prawn::Table.new data, pdf, :column_widths => [50, 200]
table.column_widths.should == [50.0, 200.0]
end

it "illustrates a variant of problem in issue #407 - comment 28556698" do
pdf = Prawn::Document.new
table_data = [["a", "b", "c"], [{:content=>"d", :colspan=>3}]]
column_widths = [50, 60, 400]

# Before we fixed #407, this line incorrectly raise a CannotFit error
pdf.table(table_data, :column_widths => column_widths)
end
end

describe "#initialize" do
Expand Down

0 comments on commit a8026a5

Please sign in to comment.