X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=modules%2Foverride%2FPDF%2FTable.pm;h=602c88728d499a7653d32f6fec44a0a37b025c48;hb=a206eca6ec7beb6a4344a56df5c8ddb17b50c877;hp=d89274e21f7abdb1f1e4a64a225af5ab468b7760;hpb=a5a81f46c232cbbc19ee1024194ff339708d22e1;p=kivitendo-erp.git diff --git a/modules/override/PDF/Table.pm b/modules/override/PDF/Table.pm old mode 100644 new mode 100755 index d89274e21..602c88728 --- a/modules/override/PDF/Table.pm +++ b/modules/override/PDF/Table.pm @@ -8,6 +8,8 @@ use warnings; package PDF::Table; use Carp; +use List::Util qw(sum); + our $VERSION = '0.10.1'; print __PACKAGE__.' is version: '.$VERSION.$/ if($ENV{'PDF_TABLE_DEBUG'}); @@ -132,8 +134,8 @@ sub text_block # Check if any text to display unless( defined( $text) and length($text) > 0 ) { - carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n"; - $text = '-'; +# carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n"; + $text = ' '; } # Strip any and Split the text into paragraphs @@ -209,8 +211,12 @@ sub text_block } # Lets take from paragraph as many words as we can put into $width - $indent; - while ( @paragraph and $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + - $line_width < $width ) + # Always take at least one word; otherwise we'd end up in an infinite loop. + while ( !scalar(@line) || ( + @paragraph && ( + $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + $line_width < $width + ) + )) { push(@line, shift(@paragraph)); } @@ -326,6 +332,7 @@ sub table max_word_length => 1, cell_render_hook => 1, default_text => 1, + num_header_rows => 1, ); foreach my $key (keys %arg) { @@ -371,7 +378,7 @@ sub table #===================================== # Disable header row into the table my $header_props = undef; - + my (@header_rows, @header_row_cell_props); # Check if the user enabled it ? if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH') { @@ -386,9 +393,8 @@ sub table $header_props->{'font_underline'} = $header_props->{'font_underline'} || $fnt_underline; $header_props->{'bg_color' } = $header_props->{'bg_color' } || '#FFFFAA'; $header_props->{'justify' } = $header_props->{'justify' }; + $header_props->{num_header_rows } = $arg{num_header_rows } || 1; } - - my $header_row = undef; #===================================== # Other Parameters check #===================================== @@ -431,7 +437,10 @@ sub table } # Copy the header row if header is enabled - @$header_row = $$data[0] if defined $header_props; + if (defined $header_props) { + map { push @header_rows, $$data[$_] } (0..$header_props->{num_header_rows} - 1); + map { push @header_row_cell_props, $$cell_props[$_] } (0..$header_props->{num_header_rows} - 1); + } # Determine column widths based on content # an arrayref whose values are a hashref holding @@ -442,7 +451,7 @@ sub table # the actual widths of the column/row intersection my $row_col_widths = []; # An array ref with the widths of the header row - my $header_row_props = []; + my @header_row_widths; # Scalars that hold sum of the maximum and minimum widths of all columns my ( $max_col_w , $min_col_w ) = ( 0,0 ); @@ -454,6 +463,8 @@ sub table for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ ) { + #push @header_row_widths, [] if $row_idx < $header_props->{num_header_rows}; + my $column_widths = []; #holds the width of each column # Init the height for this row $rows_height->[$row_idx] = 0; @@ -494,8 +505,12 @@ sub table $rows_height->[$row_idx] = $cell_font_size; } + if (!defined $data->[$row_idx][$column_idx]) { + $data->[$row_idx][$column_idx] = ' '; + } + # This should fix a bug with very long words like serial numbers etc. - if( $max_word_len > 0 ) + if( $max_word_len > 0 && $data->[$row_idx][$column_idx]) { $data->[$row_idx][$column_idx] =~ s#(\S{$max_word_len})(?=\S)#$1 #g; } @@ -542,20 +557,25 @@ sub table $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); + if (ref $header_props && $row_idx < $header_props->{num_header_rows}) { + push @header_row_widths, [ @{ $column_widths } ]; + } } # 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 @header_row_heights = @$rows_height[0 .. $header_props->{num_header_rows}-1]; my ( $gfx, $gfx_bg, $background_color, $font_color, $bot_marg, $table_top_y, $text_start); + my $remaining_header_rows = $header_props ? $header_props->{num_header_rows} : 0; + # Each iteration adds a new page as neccessary while(scalar(@{$data})) { @@ -570,7 +590,7 @@ sub table # Check for safety reasons if( $bot_marg < 0 ) { # This warning should remain i think - carp "!!! Warning: !!! Incorrect Table Geometry! start_h (${height}) is above start_y (${table_top_y}). Setting bottom margin to end of sheet!\n"; + #carp "!!! Warning: !!! Incorrect Table Geometry! start_h (${height}) is above start_y (${table_top_y}). Setting bottom margin to end of sheet!\n"; $bot_marg = 0; } @@ -592,23 +612,17 @@ sub table # Check for safety reasons if( $bot_marg < 0 ) { # This warning should remain i think - carp "!!! Warning: !!! Incorrect Table Geometry! next_y or start_y (${next_y}) is above next_h or start_h (${next_h}). Setting bottom margin to end of sheet!\n"; + #carp "!!! Warning: !!! Incorrect Table Geometry! next_y or start_y (${next_y}) is above next_h or start_h (${next_h}). Setting bottom margin to end of sheet!\n"; $bot_marg = 0; } 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 + unshift @$data, @header_rows; + unshift @$row_col_widths, @header_row_widths; + unshift @$rows_height, @header_row_heights; + $remaining_header_rows = $header_props->{num_header_rows}; + $first_row = 1; } } @@ -659,10 +673,15 @@ sub table # 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; + $background_color = ($row_index - $header_props->{num_header_rows}) % 2 ? $background_color_even : $background_color_odd; + $font_color = ($row_index - $header_props->{num_header_rows}) % 2 ? $font_color_even : $font_color_odd; #Determine current row height my $current_row_height = $pad_top + $pre_calculated_row_height + $pad_bot; @@ -680,6 +699,7 @@ sub table 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 cell(column) from current row for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ ) @@ -691,7 +711,7 @@ sub table # look for font information for this cell my ($cell_font, $cell_font_size, $cell_font_color, $cell_font_underline, $justify); - if( $first_row and ref $header_props) + if( $remaining_header_rows and ref $header_props) { $cell_font = $header_props->{'font'}; $cell_font_size = $header_props->{'font_size'}; @@ -732,19 +752,34 @@ sub table // $col_props->[$column_idx]->{'default_text'} // $default_text; + my $this_width; + if (!$remaining_header_rows && $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan}) { + $colspan = $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{colspan}; + } elsif ($remaining_header_rows && ($header_row_cell_props[$header_props->{num_header_rows} - $remaining_header_rows][$column_idx]->{colspan})) { + $colspan = $header_row_cell_props[$header_props->{num_header_rows} - $remaining_header_rows][$column_idx]->{colspan}; + } + + if ($colspan) { + $colspan = $num_cols - $column_idx if (-1 == $colspan); + my $last_idx = $column_idx + $colspan - 1; + $this_width = sum @{ $calc_column_widths }[$column_idx..$last_idx]; + } else { + $this_width = $calc_column_widths->[$column_idx]; + } + # If the content is wider than the specified width, we need to add the text as a text block if( $record->[$column_idx] !~ m/(.\n.)/ and $record_widths->[$column_idx] and - $record_widths->[$column_idx] <= $calc_column_widths->[$column_idx] + $record_widths->[$column_idx] <= $this_width ){ my $space = $pad_left; if ($justify eq 'right') { - $space = $calc_column_widths->[$column_idx] -($txt->advancewidth($record->[$column_idx]) + $pad_right); + $space = $this_width -($txt->advancewidth($record->[$column_idx]) + $pad_right); } elsif ($justify eq 'center') { - $space = ($calc_column_widths->[$column_idx] - $txt->advancewidth($record->[$column_idx])) / 2; + $space = ($this_width - $txt->advancewidth($record->[$column_idx])) / 2; } $txt->translate( $cur_x + $space, $text_start ); my %text_options; @@ -759,7 +794,7 @@ sub table $record->[$column_idx], x => $cur_x + $pad_left, y => $text_start, - w => $calc_column_widths->[$column_idx] - $pad_left - $pad_right, + w => $this_width - $pad_left - $pad_right, h => $cur_y - $bot_marg - $pad_top - $pad_bot, align => $justify, lead => $lead @@ -793,6 +828,9 @@ sub table } $cur_x += $calc_column_widths->[$column_idx]; + + push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0; + $colspan-- if $colspan; } if( $do_leftovers ) { @@ -809,13 +847,13 @@ sub table { my $cell_bg_color; - if( $first_row and ref $header_props) + if( $remaining_header_rows and ref $header_props) { #Compatibility Consistency with other props $cell_bg_color = $header_props->{'bg_color'} || $header_props->{'background_color'}; } # Get the most specific value if none was already set from header_props - $cell_bg_color ||= $cell_props->[$row_index][$column_idx]->{'background_color'} + $cell_bg_color ||= $cell_props->[$row_index + $header_props->{num_header_rows}][$column_idx]->{'background_color'} || $col_props->[$column_idx]->{'background_color'} || $background_color; @@ -826,6 +864,12 @@ sub table $gfx_bg->fill(); } $cur_x += $calc_column_widths->[$column_idx]; + + if ($line_w && $vertical_lines[$column_idx] && ($column_idx != (scalar(@{ $record }) - 1))) { + $gfx->move($cur_x, $cur_y); + $gfx->vline($cur_y - $current_row_height); + $gfx->fillcolor($border_color); + } }#End of for(my $column_idx.... $cur_y -= $current_row_height; @@ -835,8 +879,12 @@ sub table $gfx->hline( $xbase + $width ); } - $row_index++ unless ( $do_leftovers ); $first_row = 0; + if ($remaining_header_rows) { + $remaining_header_rows--; + } else { + $row_index++ unless $do_leftovers; + } }# End of Row_Loop if ($gfx) @@ -846,13 +894,8 @@ sub table { $gfx->move( $xbase, $table_top_y); $gfx->vline( $cur_y ); - my $cur_x = $xbase; - for( my $j = 0; $j < $columns_number; $j++ ) - { - $cur_x += $calc_column_widths->[$j]; - $gfx->move( $cur_x, $table_top_y ); - $gfx->vline( $cur_y ); - } + $gfx->move($xbase + sum(@{ $calc_column_widths }[0..$num_cols - 1]), $table_top_y); + $gfx->vline( $cur_y ); } # ACTUALLY draw all the lines @@ -903,32 +946,11 @@ sub CalcColumnWidths $calc_widths->[$j] = $col_props->[$j]->{min_w} || 0;; } - # Allow columns to expand to max_w before applying extra space equally. - my $is_last_iter; - for (;;) - { - my $span = ($avail_width - $min_width) / scalar( @$col_props); - last if $span <= 0; - - $min_width = 0; - my $next_will_be_last_iter = 1; - for(my $j = 0; $j < scalar(@$col_props); $j++ ) - { - my $new_w = $calc_widths->[$j] + $span; - - if (!$is_last_iter && $new_w > $col_props->[$j]->{max_w}) - { - $new_w = $col_props->[$j]->{max_w} - } - if ($calc_widths->[$j] != $new_w ) - { - $calc_widths->[$j] = $new_w; - $next_will_be_last_iter = 0; - } - $min_width += $new_w; - } - last if $is_last_iter; - $is_last_iter = $next_will_be_last_iter; + my $span = 0; + # Calculate how much can be added to every column to fit the available width + $span = ($avail_width - $min_width) / scalar( @$col_props); + for (my $j = 0; $j < scalar(@$col_props); $j++ ) { + $calc_widths->[$j] = $col_props->[$j]->{min_w} + $span; } return ($calc_widths,$avail_width);