- # Scalars that hold sum of the maximum and minimum widths of all columns
- my ( $max_col_w , $min_col_w ) = ( 0,0 );
- my ( $row, $col_name, $col_fnt_size, $space_w );
-
- # Hash that will hold the width of every word from input text
- my $word_w = {};
- my $rows_counter = 0;
- my $first_row = 1;
-
- foreach $row ( @{$data} )
- {
- my $column_widths = []; #holds the width of each column
- for( my $j = 0; $j < scalar(@$row) ; $j++ )
- {
- # look for font information for this column
- $col_fnt_size = $col_props->[$j]->{'font_size'} || $fnt_size;
- if( !$rows_counter and ref $header_props)
- {
- $txt->font( $header_props->{'font'}, $header_props->{'font_size'} );
- }
- elsif( $col_props->[$j]->{'font'} )
- {
- $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size );
- }
- else
- {
- $txt->font( $fnt_name, $col_fnt_size );
- }
-
- # This should fix a bug with very long word like serial numbers etc.
- # $myone is used because $1 gets out of scope in while condition
- my $myone;
- do{
- $myone = 0;
- # This RegEx will split any word that is longer than {25} symbols
- $row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#;
- $myone = 1 if( defined $2 );
- }while( $myone );
-
- $space_w = $txt->advancewidth( "\x20" );
- $column_widths->[$j] = 0;
- $max_col_w = 0;
- $min_col_w = 0;
-
- my @words = split( /\s+/, $row->[$j] );
-
- foreach( @words )
- {
- unless( exists $word_w->{$_} )
- { # Calculate the width of every word and add the space width to it
- $word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
- }
- $column_widths->[$j] += $word_w->{$_};
- $min_col_w = $word_w->{$_} if $word_w->{$_} > $min_col_w;
- $max_col_w += $word_w->{$_};
- }
- $min_col_w += $pad_w;
- $max_col_w += $pad_w;
- $column_widths->[$j] += $pad_w;
-
- # Keep a running total of the overall min and max widths
- $col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0;
- $col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0;
-
- if( $min_col_w > $col_props->[$j]->{min_w} )
- { # Calculated Minimum Column Width is more than user-defined
- $col_props->[$j]->{min_w} = $min_col_w ;
- }
- if( $max_col_w > $col_props->[$j]->{max_w} )
- { # Calculated Maximum Column Width is more than user-defined
- $col_props->[$j]->{max_w} = $max_col_w ;
- }
- }#End of for(my $j....
- $row_props->[$rows_counter] = $column_widths;
- # Copy the calculated row properties of header row.
- @$header_row_props = @$column_widths if(!$rows_counter and ref $header_props);
- $rows_counter++;
- }
- # Calc real column widths and expand table width if needed.
- my $calc_column_widths;
- ($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width );
- my $num_cols = scalar @{ $calc_column_widths };
- my $comp_cnt = 1;
- $rows_counter = 0;
-
- my ( $gfx , $gfx_bg , $background_color , $font_color, );
- my ( $bot_marg, $table_top_y, $text_start , $record, $record_widths );
-
- # Each iteration adds a new page as neccessary
- while(scalar(@{$data}))
- {
- my $page_header;
- if($pg_cnt == 1)
- {
- $table_top_y = $ybase;
- $bot_marg = $table_top_y - $height;
- }
- else
- {
- if(ref $arg{'new_page_func'})
- {
- $page = &{$arg{'new_page_func'}};
- }
- else
- {
- $page = $pdf->page;
- }
-
- $table_top_y = $next_y;
- $bot_marg = $table_top_y - $next_h;
-
- if( ref $header_props and $header_props->{'repeat'})
- {
- # Copy Header Data
- @$page_header = @$header_row;
- my $hrp ;
- @$hrp = @$header_row_props ;
- # Then prepend it to master data array
- unshift @$data ,@$page_header ;
- unshift @$row_props ,$hrp ;
- $first_row = 1; # Means YES
- }
- }
-
- # Check for safety reasons
- if( $bot_marg < 0 )
- { # This warning should remain i think
-# print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
- $bot_marg = 0;
- }
-
- $gfx_bg = $page->gfx;
- $txt = $page->text;
- $txt->font($fnt_name, $fnt_size);
- $gfx = $page->gfx;
- $gfx->strokecolor($border_color);
- $gfx->linewidth($line_w);
-
- # Draw the top line
- $cur_y = $table_top_y;
- $gfx->move( $xbase , $cur_y );
- $gfx->hline($xbase + $width );
-
- # Each iteration adds a row to the current page until the page is full
- # or there are no more rows to add
- while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
- {
- # Remove the next item from $data
- $record = shift @{$data};
- # Added to resolve infite loop bug with returned undef values
- for(my $d = 0; $d < scalar(@{$record}) ; $d++)
- {
- $record->[$d] = '-' unless( defined $record->[$d]);
- }
-
- $record_widths = shift @$row_props;
- next unless $record;
-
- # Choose colors for this row
- $background_color = $rows_counter % 2 ? $background_color_even : $background_color_odd;
- $font_color = $rows_counter % 2 ? $font_color_even : $font_color_odd;
-
- if($first_row and ref $header_props)
- {
- $background_color = $header_props->{'bg_color'}
- }
- $text_start = $cur_y - $fnt_size - $pad_top;
- my $cur_x = $xbase;
- my $leftovers = undef; # Reference to text that is returned from textblock()
- my $do_leftovers = 0;
-
- my ($colspan, @vertical_lines);
-
- # Process every column from current row
- for( my $j = 0; $j < scalar( @$record); $j++ )
- {
- next unless $col_props->[$j]->{max_w};
- next unless $col_props->[$j]->{min_w};
- $leftovers->[$j] = undef;
-
- # Choose font color
- if( $first_row and ref $header_props )
- {
- $txt->fillcolor( $header_props->{'font_color'} );
- }
- elsif( $cell_props->[$row_cnt][$j]{font_color} )
- {
- $txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} );
- }
- elsif( $col_props->[$j]->{'font_color'} )
- {
- $txt->fillcolor( $col_props->[$j]->{'font_color'} );
- }
- else
- {
- $txt->fillcolor($font_color);
- }
-
- # Choose font size
- if( $first_row and ref $header_props )
- {
- $col_fnt_size = $header_props->{'font_size'};
- }
- elsif( $col_props->[$j]->{'font_size'} )
- {
- $col_fnt_size = $col_props->[$j]->{'font_size'};
- }
- else
- {
- $col_fnt_size = $fnt_size;
- }
-
- # Choose font family
- if( $first_row and ref $header_props )
- {
- $txt->font( $header_props->{'font'}, $header_props->{'font_size'});
- }
- elsif( $col_props->[$j]->{'font'} )
- {
- $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size);
- }
- else
- {
- $txt->font( $fnt_name, $col_fnt_size);
- }
- #TODO: Implement Center text align
- $col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left';
-
- my $this_width;
- if (!$first_row && $cell_props->[$row_cnt]->[$j]->{colspan}) {
- $colspan = -1 == $cell_props->[$row_cnt]->[$j]->{colspan} ? $num_cols - $j : $cell_props->[$row_cnt]->[$j]->{colspan};
- my $last_idx = $j + $colspan - 1;
- $this_width = sum @{ $calc_column_widths }[$j..$last_idx];
-
- } else {
- $this_width = $calc_column_widths->[$j];
- }
+ # Scalars that hold sum of the maximum and minimum widths of all columns
+ my ( $max_col_w , $min_col_w ) = ( 0,0 );
+ my ( $row, $col_name, $col_fnt_size, $space_w );
+
+ my $word_widths = {};
+ my $rows_height = [];
+ my $first_row = 1;
+
+ for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ )
+ {
+ my $column_widths = []; #holds the width of each column
+ # Init the height for this row
+ $rows_height->[$row_idx] = 0;
+
+ for( my $column_idx = 0; $column_idx < scalar(@{$data->[$row_idx]}) ; $column_idx++ )
+ {
+ # look for font information for this column
+ my ($cell_font, $cell_font_size);
+
+ if( !$row_idx and ref $header_props )
+ {
+ $cell_font = $header_props->{'font'};
+ $cell_font_size = $header_props->{'font_size'};
+ }
+
+ # Get the most specific value if none was already set from header_props
+ $cell_font ||= $cell_props->[$row_idx][$column_idx]->{'font'}
+ || $col_props->[$column_idx]->{'font'}
+ || $fnt_name;
+
+ $cell_font_size ||= $cell_props->[$row_idx][$column_idx]->{'font_size'}
+ || $col_props->[$column_idx]->{'font_size'}
+ || $fnt_size;
+
+ # Set Font
+ $txt->font( $cell_font, $cell_font_size );
+
+ # Set row height to biggest font size from row's cells
+ if( $cell_font_size > $rows_height->[$row_idx] )
+ {
+ $rows_height->[$row_idx] = $cell_font_size;
+ }
+
+ # This should fix a bug with very long words like serial numbers etc.
+ if( $max_word_len > 0 )
+ {
+ $data->[$row_idx][$column_idx] =~ s#(\S{$max_word_len})(?=\S)#$1 #g;
+ }
+
+ # Init cell size limits
+ $space_w = $txt->advancewidth( "\x20" );
+ $column_widths->[$column_idx] = 0;
+ $max_col_w = 0;
+ $min_col_w = 0;
+
+ my @words = split( /\s+/, $data->[$row_idx][$column_idx] );
+
+ foreach( @words )
+ {
+ unless( exists $word_widths->{$_} )
+ { # Calculate the width of every word and add the space width to it
+ $word_widths->{$_} = $txt->advancewidth( $_ ) + $space_w;
+ }
+
+ $column_widths->[$column_idx] += $word_widths->{$_};
+ $min_col_w = $word_widths->{$_} if( $word_widths->{$_} > $min_col_w );
+ $max_col_w += $word_widths->{$_};
+ }
+
+ $min_col_w += $pad_left + $pad_right;
+ $max_col_w += $pad_left + $pad_right;
+ $column_widths->[$column_idx] += $pad_left + $pad_right;
+
+ # Keep a running total of the overall min and max widths
+ $col_props->[$column_idx]->{'min_w'} ||= 0;
+ $col_props->[$column_idx]->{'max_w'} ||= 0;
+
+ if( $min_col_w > $col_props->[$column_idx]->{'min_w'} )
+ { # Calculated Minimum Column Width is more than user-defined
+ $col_props->[$column_idx]->{'min_w'} = $min_col_w ;
+ }
+
+ if( $max_col_w > $col_props->[$column_idx]->{'max_w'} )
+ { # Calculated Maximum Column Width is more than user-defined
+ $col_props->[$column_idx]->{'max_w'} = $max_col_w ;
+ }
+ }#End of for(my $column_idx....
+
+ $row_col_widths->[$row_idx] = $column_widths;
+
+ # Copy the calculated row properties of header row.
+ @$header_row_props = @$column_widths if(!$row_idx and ref $header_props);
+ }
+
+ # Calc real column widths and expand table width if needed.
+ my $calc_column_widths;
+ ($calc_column_widths, $width) = CalcColumnWidths( $col_props, $width );
+ my $num_cols = scalar @{ $calc_column_widths };
+
+ # Lets draw what we have!
+ my $row_index = 0;
+ # Store header row height for later use if headers have to be repeated
+ my $header_row_height = $rows_height->[0];
+
+ my ( $gfx, $gfx_bg, $background_color, $font_color, $bot_marg, $table_top_y, $text_start);
+
+ # Each iteration adds a new page as neccessary
+ while(scalar(@{$data}))
+ {
+ my ($page_header, $columns_number);
+
+ if($pg_cnt == 1)
+ {
+ $table_top_y = $ybase;
+ $bot_marg = $table_top_y - $height;
+ }
+ else
+ {
+ if(ref $arg{'new_page_func'})
+ {
+ $page = &{$arg{'new_page_func'}};
+ }
+ else
+ {
+ $page = $pdf->page;
+ }
+
+ $table_top_y = $next_y;
+ $bot_marg = $table_top_y - $next_h;
+
+ if( ref $header_props and $header_props->{'repeat'})
+ {
+ # Copy Header Data
+ @$page_header = @$header_row;
+ my $hrp ;
+ @$hrp = @$header_row_props ;
+ # Then prepend it to master data array
+ unshift @$data, @$page_header;
+ unshift @$row_col_widths, $hrp;
+ unshift @$rows_height, $header_row_height;
+
+ $first_row = 1; # Means YES
+ $row_index--; # Rollback the row_index because a new header row has been added
+ }
+ }
+
+ # Check for safety reasons
+ if( $bot_marg < 0 )
+ { # This warning should remain i think
+# carp "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
+ $bot_marg = 0;
+ }
+
+ $gfx_bg = $page->gfx;
+ $txt = $page->text;
+ $txt->font($fnt_name, $fnt_size);
+
+ $cur_y = $table_top_y;
+
+ if ($line_w)
+ {
+ $gfx = $page->gfx;
+ $gfx->strokecolor($border_color);
+ $gfx->linewidth($line_w);
+
+ # Draw the top line
+ if ($horiz_borders)
+ {
+ $gfx->move( $xbase , $cur_y );
+ $gfx->hline($xbase + $width );
+ }
+ }
+ else
+ {
+ $gfx = undef;
+ }
+
+ # Each iteration adds a row to the current page until the page is full
+ # or there are no more rows to add
+ # Row_Loop
+ while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
+ {
+ # Remove the next item from $data
+ my $record = shift @{$data};
+
+ # Get columns number to know later how many vertical lines to draw
+ # TODO: get the max number of columns per page as currently last row's columns overrides
+ $columns_number = scalar(@$record);
+
+ # Get the next set of row related settings
+ # Row Height
+ my $pre_calculated_row_height = shift @$rows_height;
+
+ # Row cell widths
+ my $record_widths = shift @$row_col_widths;
+
+ # Row coloumn props - TODO in another commit
+
+ # Row cell props - TODO in another commit
+
+ # Added to resolve infite loop bug with returned undef values
+ for(my $d = 0; $d < scalar(@{$record}) ; $d++)
+ {
+ $record->[$d] = '-' unless( defined $record->[$d]);
+ }
+
+ # Choose colors for this row
+ $background_color = $row_index % 2 ? $background_color_even : $background_color_odd;
+ $font_color = $row_index % 2 ? $font_color_even : $font_color_odd;
+
+ #Determine current row height
+ my $current_row_height = $pad_top + $pre_calculated_row_height + $pad_bot;
+
+ # $row_h is the calculated global user requested row height.
+ # It will be honored, only if it has bigger value than the calculated one.
+ # TODO: It's questionable if padding should be inclided in this calculation or not
+ if($current_row_height < $row_h){
+ $current_row_height = $row_h;
+ }