Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision ca2ec834

Von Sven Schöling vor fast 9 Jahren hinzugefügt

  • ID ca2ec834a15bc9b47397f8b608e35e095e3ead8a
  • Vorgänger 387cb8fa
  • Nachfolger 35cd4452

PDF::Table update auf aktuelle Version aus git

cpan speist sich aus https://github.com/kamenov/PDF-Table

Diese hier ist aktuell aus Commit 5a9f499

Unterschiede anzeigen:

modules/override/PDF/Table.pm
3 3
use 5.006;
4 4
use strict;
5 5
use warnings;
6
our $VERSION = '0.9.3';
6
use Carp;
7
our $VERSION = '0.9.10';
7 8

  
8
use List::Util qw(sum);
9
print __PACKAGE__.' is version: '.$VERSION.$/ if($ENV{'PDF_TABLE_DEBUG'});
9 10

  
10 11
############################################################
11 12
#
......
17 18
#
18 19
############################################################
19 20

  
20
sub new {
21
  my ($type) = @_;
21
sub new
22
{
23
    my $type = shift(@_);
24
    my $class = ref($type) || $type;
25
    my $self  = {};
26
    bless ($self, $class);
22 27

  
23
  my $class = ref($type) || $type;
24
  my $self  = {};
25
  bless ($self, $class);
26
  return $self;
28
    # Pass all the rest to init for validation and initialisation
29
    $self->_init(@_);
30

  
31
    return $self;
32
}
33

  
34
sub _init
35
{
36
    my ($self, $pdf, $page, $data, %options ) = @_;
37

  
38
    # Check and set default values 
39
    $self->set_defaults();
40

  
41
    # Check and set mandatory params
42
    $self->set_pdf($pdf);
43
    $self->set_page($page);
44
    $self->set_data($data);
45
    $self->set_options(\%options);
46

  
47
    return;
48
}
49

  
50
sub set_defaults{
51
	my $self = shift;
52
	
53
	$self->{'font_size'} = 12;
54
}
55

  
56
sub set_pdf{
57
    my ($self, $pdf) = @_;
58
    $self->{'pdf'} = $pdf;
59
}
60

  
61
sub set_page{
62
    my ($self, $page) = @_;
63
    if ( defined($page) && ref($page) ne 'PDF::API2::Page' ){
64

  
65
        if( ref($self->{'pdf'}) eq 'PDF::API2' ){
66
            $self->{'page'} = $self->{'pdf'}->page();
67
        } else {
68
            carp 'Warning: Page must be a PDF::API2::Page object but it seems to be: '.ref($page).$/;
69
            carp 'Error: Cannot set page from passed PDF object either as it is invalid!'.$/;
70
        }
71
        return;
72
    }
73
    $self->{'page'} = $page;
74

  
75
}
76

  
77
sub set_data{
78
    my ($self, $data) = @_;
79
    #TODO: implement
80
}
81

  
82
sub set_options{
83
    my ($self, $options) = @_;
84
    #TODO: implement
27 85
}
28 86

  
29 87
############################################################
......
32 90
#
33 91
############################################################
34 92

  
35
sub text_block {
36
  my $self        = shift;
37
  my $text_object = shift;
38
  my $text        = shift;          # The text to be displayed
39
  my %arg         = @_;             # Additional Arguments
40

  
41
  my  ($align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height)
42
    = (undef , undef, undef, undef , undef , undef      , undef     , undef , undef , undef  );
43
  my @line  = ();          # Temp data array with words on one line
44
  my %width = ();          # The width of every unique word in the givven text
45

  
46
  # Try to provide backward compatibility
47
  foreach my $key (keys %arg) {
48
    my $newkey = $key;
49
    if ($newkey =~ s#^-##) {
50
      $arg{$newkey} = $arg{$key};
51
      delete $arg{$key};
93
sub text_block
94
{
95
    my $self        = shift;
96
    my $text_object = shift;
97
    my $text        = shift;    # The text to be displayed
98
    my %arg         = @_;       # Additional Arguments
99

  
100
    my  ( $align, $xpos, $ypos, $xbase, $ybase, $line_width, $wordspace, $endw , $width, $height) = 
101
        ( undef , undef, undef, undef , undef , undef      , undef     , undef , undef , undef  );
102
    my @line        = ();       # Temp data array with words on one line 
103
    my %width       = ();       # The width of every unique word in the givven text
104

  
105
    # Try to provide backward compatibility
106
    foreach my $key (keys %arg)
107
    {
108
        my $newkey = $key;
109
        if($newkey =~ s#^-##)
110
        {
111
            $arg{$newkey} = $arg{$key};
112
            delete $arg{$key};
113
        }
52 114
    }
53
  }
54
  #####
55

  
56
  #---
57
  # Lets check mandatory parameters with no default values
58
  #---
59
  $xbase  = $arg{'x'} || -1;
60
  $ybase  = $arg{'y'} || -1;
61
  $width  = $arg{'w'} || -1;
62
  $height = $arg{'h'} || -1;
63
  unless ( $xbase  > 0 ) { print "Error: Left Edge of Block is NOT defined!\n"; return; }
64
  unless ( $ybase  > 0 ) { print "Error: Base Line of Block is NOT defined!\n"; return; }
65
  unless ( $width  > 0 ) { print "Error: Width of Block is NOT defined!\n";     return; }
66
  unless ( $height > 0 ) { print "Error: Height of Block is NOT defined!\n";    return; }
67
  # Check if any text to display
68
  unless ( defined( $text) and length($text) > 0 ) {
69
    print "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n";
70
    $text = '-';
71
  }
72

  
73
  # Strip any <CR> and Split the text into paragraphs
74
  $text          =~ s/\r//g;
75
  my @paragraphs =  split(/\n/, $text);
76

  
77
  # Width between lines in pixels
78
  my $line_space = defined $arg{'lead'} && $arg{'lead'} > 0 ? $arg{'lead'} : 12;
79

  
80
  # Calculate width of all words
81
  my $space_width = $text_object->advancewidth("\x20");
82
  my @words       = split(/\s+/, $text);
83
  foreach (@words) {
84
    next if exists $width{$_};
85
    $width{$_} = $text_object->advancewidth($_);
86
  }
87

  
88
  my @paragraph       = split(' ', shift(@paragraphs));
89
  my $first_line      = 1;
90
  my $first_paragraph = 1;
91

  
92
  # Little Init
93
  $xpos             = $xbase;
94
  $ypos             = $ybase;
95
  $ypos             = $ybase + $line_space;
96
  my $bottom_border = $ybase - $height;
97
  # While we can add another line
98
  while ( $ypos >= $bottom_border + $line_space ) {
99
    # Is there any text to render ?
100
    unless (@paragraph) {
101
      # Finish if nothing left
102
      last unless scalar @paragraphs;
103
      # Else take one line from the text
104
      @paragraph  = split(' ', shift( @paragraphs ) );
105

  
106
      $ypos      -= $arg{'parspace'} if $arg{'parspace'};
107
      last unless $ypos >= $bottom_border;
115
    #####
116

  
117
    #---
118
    # Lets check mandatory parameters with no default values
119
    #---
120
    $xbase  = $arg{'x'} || -1;
121
    $ybase  = $arg{'y'} || -1;
122
    $width  = $arg{'w'} || -1;
123
    $height = $arg{'h'} || -1;
124
    unless( $xbase  > 0 ){ carp "Error: Left Edge of Block is NOT defined!\n";  return; }
125
    unless( $ybase  > 0 ){ carp "Error: Base Line of Block is NOT defined!\n"; return; }
126
    unless( $width  > 0 ){ carp "Error: Width of Block is NOT defined!\n";  return; }
127
    unless( $height > 0 ){ carp "Error: Height of Block is NOT defined!\n"; return; }
128
    # Check if any text to display
129
    unless( defined( $text) and length($text) > 0 )
130
    {
131
        carp "Warning: No input text found. Trying to add dummy '-' and not to break everything.\n";
132
        $text = '-';
108 133
    }
109
    $ypos -= $line_space;
110
    $xpos  = $xbase;
111 134

  
112
    # While there's room on the line, add another word
113
    @line       = ();
114
    $line_width = 0;
115
    if ( $first_line && exists $arg{'hang'} ) {
116
      my $hang_width = $text_object->advancewidth($arg{'hang'});
135
    # Strip any <CR> and Split the text into paragraphs
136
    $text =~ s/\r//g;
137
    my @paragraphs  = split(/\n/, $text);
117 138

  
118
      $text_object->translate( $xpos, $ypos );
119
      $text_object->text( $arg{'hang'} );
139
    # Width between lines in pixels
140
    my $line_space = defined $arg{'lead'} && $arg{'lead'} > 0 ? $arg{'lead'} : 12;
120 141

  
121
      $xpos          += $hang_width;
122
      $line_width    += $hang_width;
123
      $arg{'indent'} += $hang_width if $first_paragraph;
142
    # Calculate width of all words
143
    my $space_width = $text_object->advancewidth("\x20");
144
    my @words = split(/\s+/, $text);
145
    foreach (@words) 
146
    {
147
        next if exists $width{$_};
148
        $width{$_} = $text_object->advancewidth($_);
149
    }
124 150

  
125
    } elsif ( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) {
126
      $xpos       += $arg{'flindent'};
127
      $line_width += $arg{'flindent'};
151
    my @paragraph = split(' ', shift(@paragraphs));
152
    my $first_line = 1;
153
    my $first_paragraph = 1;
154

  
155
    # Little Init
156
    $xpos = $xbase;
157
    $ypos = $ybase;
158
    $ypos = $ybase + $line_space;
159
    my $bottom_border = $ypos - $height; 
160
    # While we can add another line
161
    while ( $ypos >= $bottom_border + $line_space ) 
162
    {
163
        # Is there any text to render ?
164
        unless (@paragraph) 
165
        {
166
            # Finish if nothing left
167
            last unless scalar @paragraphs;
168
            # Else take one line from the text
169
            @paragraph = split(' ', shift( @paragraphs ) );
170

  
171
            $ypos -= $arg{'parspace'} if $arg{'parspace'};
172
            last unless $ypos >= $bottom_border;
173
        }
174
        $ypos -= $line_space;
175
        $xpos = $xbase;
176

  
177
        # While there's room on the line, add another word
178
        @line = ();
179
        $line_width = 0;
180
        if( $first_line && exists $arg{'hang'} ) 
181
        {
182
            my $hang_width = $text_object->advancewidth($arg{'hang'});
183
    
184
            $text_object->translate( $xpos, $ypos );
185
            $text_object->text( $arg{'hang'} );
186
    
187
            $xpos         += $hang_width;
188
            $line_width   += $hang_width;
189
            $arg{'indent'} += $hang_width if $first_paragraph;
190
        }
191
        elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) 
192
        {
193
            $xpos += $arg{'flindent'};
194
            $line_width += $arg{'flindent'};
195
        }
196
        elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) 
197
        {
198
            $xpos += $arg{'fpindent'};
199
            $line_width += $arg{'fpindent'};
200
        }
201
        elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) 
202
        {
203
            $xpos += $arg{'indent'};
204
            $line_width += $arg{'indent'};
205
        }
206
    
207
        # Lets take from paragraph as many words as we can put into $width - $indent; 
208
        while ( @paragraph and $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + 
209
                                $line_width < $width ) 
210
        {
211
            push(@line, shift(@paragraph));
212
        }
213
        $line_width += $text_object->advancewidth(join('', @line));
214
            
215
        # calculate the space width
216
        if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) 
217
        {
218
            @line = split(//,$line[0]) if (scalar(@line) == 1) ;
219
            $wordspace = ($width - $line_width) / (scalar(@line) - 1);
220
            $align='justify';
221
        } 
222
        else 
223
        {
224
            $align=($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
225
            $wordspace = $space_width;
226
        }
227
        $line_width += $wordspace * (scalar(@line) - 1);
228
    
229
        if( $align eq 'justify') 
230
        {
231
            foreach my $word (@line) 
232
            {
233
                $text_object->translate( $xpos, $ypos );
234
                $text_object->text( $word );
235
                $xpos += ($width{$word} + $wordspace) if (@line);
236
            }
237
            $endw = $width;
238
        } 
239
        else 
240
        {
241
            # calculate the left hand position of the line
242
            if( $align eq 'right' ) 
243
            {
244
                $xpos += $width - $line_width;
245
            } 
246
            elsif( $align eq 'center' ) 
247
            {
248
                $xpos += ( $width / 2 ) - ( $line_width / 2 );
249
            }
250
    
251
            # render the line
252
            $text_object->translate( $xpos, $ypos );
253
            $endw = $text_object->text( join("\x20", @line));
254
        }
255
        $first_line = 0;
256
    }#End of while(
257
    unshift(@paragraphs, join(' ',@paragraph)) if scalar(@paragraph);
258
    return ($endw, $ypos, join("\n", @paragraphs))
259
}
128 260

  
129
    } elsif ( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) {
130
      $xpos       += $arg{'fpindent'};
131
      $line_width += $arg{'fpindent'};
132 261

  
133
    } elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) {
134
      $xpos       += $arg{'indent'};
135
      $line_width += $arg{'indent'};
262
################################################################
263
# table - utility method to build multi-row, multicolumn tables
264
################################################################
265
sub table
266
{
267
    my $self    = shift;
268
    my $pdf     = shift;
269
    my $page    = shift;
270
    my $data    = shift;
271
    my %arg     = @_;
272

  
273
    #=====================================
274
    # Mandatory Arguments Section
275
    #=====================================
276
    unless($pdf and $page and $data)
277
    {
278
        carp "Error: Mandatory parameter is missing pdf/page/data object!\n";
279
        return;
136 280
    }
137 281

  
138
    # Lets take from paragraph as many words as we can put into $width - $indent;. Always take at least one word; otherwise we'd end up in an infinite loop.
139
    while (!scalar(@line) || (@paragraph && ($text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + $line_width < $width))) {
140
      push(@line, shift(@paragraph));
282
    # Validate mandatory argument data type
283
    croak "Error: Invalid pdf object received."  unless (ref($pdf) eq 'PDF::API2');
284
    croak "Error: Invalid page object received." unless (ref($page) eq 'PDF::API2::Page');
285
    croak "Error: Invalid data received."        unless ((ref($data) eq 'ARRAY') && scalar(@$data));
286
    croak "Error: Missing required settings."    unless (scalar(keys %arg));
287

  
288
    # Validate settings key
289
    my %valid_settings_key = (
290
	x                     => 1,
291
        w                     => 1,
292
        start_y               => 1,
293
        start_h               => 1,
294
        next_y                => 1,
295
        next_h                => 1,
296
        lead                  => 1,
297
        padding               => 1,
298
        padding_right         => 1,
299
        padding_left          => 1,
300
        padding_top           => 1,
301
        padding_bottom        => 1,
302
        background_color      => 1,
303
        background_color_odd  => 1,
304
        background_color_even => 1,
305
        border                => 1,
306
        border_color          => 1,
307
        horizontal_borders    => 1,
308
        vertical_borders      => 1,
309
        font                  => 1,
310
        font_size             => 1,
311
        font_color            => 1,
312
        font_color_even       => 1,
313
        background_color_odd  => 1,
314
        background_color_even => 1,
315
        row_height            => 1,
316
        new_page_func         => 1,
317
        header_props          => 1,
318
        column_props          => 1,
319
        cell_props            => 1,
320
        max_word_length       => 1,
321
    );
322
    foreach my $key (keys %arg) {
323
	croak "Error: Invalid setting key '$key' received." 
324
            unless (exists $valid_settings_key{$key});
141 325
    }
142
    $line_width += $text_object->advancewidth(join('', @line));
143 326

  
144
    # calculate the space width
145
    if ( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) {
146
      @line      = split(//,$line[0]) if (scalar(@line) == 1) ;
147
      $wordspace = ($width - $line_width) / (scalar(@line) - 1);
148
      $align     ='justify';
149

  
150
    } else {
151
      $align     = ($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
152
      $wordspace = $space_width;
327
    # Try to provide backward compatibility
328
    foreach my $key (keys %arg)
329
    {
330
        my $newkey = $key;
331
        if($newkey =~ s#^-##)
332
        {
333
            $arg{$newkey} = $arg{$key};
334
            delete $arg{$key};
335
        }
153 336
    }
154
    $line_width += $wordspace * (scalar(@line) - 1);
155

  
156
    if ( $align eq 'justify') {
157
      foreach my $word (@line) {
158
        $text_object->translate( $xpos, $ypos );
159
        $text_object->text( $word );
160
        $xpos += ($width{$word} + $wordspace) if (@line);
161
      }
162
      $endw = $width;
163

  
164
    } else {
165
      # calculate the left hand position of the line
166
      if ( $align eq 'right' ) {
167
        $xpos += $width - $line_width;
168

  
169
      } elsif ( $align eq 'center' ) {
170
        $xpos += ( $width / 2 ) - ( $line_width / 2 );
171
      }
172

  
173
      # render the line
174
      $text_object->translate( $xpos, $ypos );
175
      $endw = $text_object->text( join("\x20", @line));
337
    
338
    ######
339
    #TODO: Add code for header props compatibility and col_props comp....
340
    ######
341
    my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
342
    # Could be 'int' or 'real' values
343
    $xbase  = $arg{'x'      } || -1;    
344
    $ybase  = $arg{'start_y'} || -1;
345
    $width  = $arg{'w'      } || -1;
346
    $height = $arg{'start_h'} || -1;
347

  
348
    # Global geometry parameters are also mandatory. 
349
    unless( $xbase  > 0 ){ carp "Error: Left Edge of Table is NOT defined!\n";  return; }
350
    unless( $ybase  > 0 ){ carp "Error: Base Line of Table is NOT defined!\n"; return; }
351
    unless( $width  > 0 ){ carp "Error: Width of Table is NOT defined!\n";  return; }
352
    unless( $height > 0 ){ carp "Error: Height of Table is NOT defined!\n"; return; }
353

  
354
    # Ensure default values for -next_y and -next_h
355
    my $next_y  = $arg{'next_y'} || $arg{'start_y'} || 0;
356
    my $next_h  = $arg{'next_h'} || $arg{'start_h'} || 0;
357

  
358
    # Create Text Object
359
    my $txt     = $page->text;
360

  
361
    # Set Default Properties
362
    my $fnt_name    = $arg{'font'            } || $pdf->corefont('Times',-encode => 'utf8');
363
    my $fnt_size    = $arg{'font_size'       } || 12;
364
    my $max_word_len= $arg{'max_word_length' } || 20;
365

  
366
    #=====================================
367
    # Table Header Section
368
    #=====================================
369
    # Disable header row into the table
370
    my $header_props = undef;
371

  
372
    # Check if the user enabled it ?
373
    if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH')
374
    {
375
        # Transfer the reference to local variable
376
        $header_props = $arg{'header_props'};
377

  
378
        # Check other params and put defaults if needed
379
        $header_props->{'repeat'        } = $header_props->{'repeat'        } || 0;
380
        $header_props->{'font'          } = $header_props->{'font'          } || $fnt_name;
381
        $header_props->{'font_color'    } = $header_props->{'font_color'    } || '#000066';
382
        $header_props->{'font_size'     } = $header_props->{'font_size'     } || $fnt_size + 2;
383
        $header_props->{'bg_color'      } = $header_props->{'bg_color'      } || '#FFFFAA';
384
        $header_props->{'justify'       } = $header_props->{'justify'       };
176 385
    }
177
    $first_line = 0;
178
  }#End of while(
179

  
180
  unshift(@paragraphs, join(' ',@paragraph)) if scalar(@paragraph);
181

  
182
  return ($endw, $ypos, join("\n", @paragraphs))
183
}
184

  
185 386

  
186
############################################################
187
# table - utility method to build multi-row, multicolumn tables
188
############################################################
189
sub table {
190
  my $self  = shift;
191
  my $pdf   = shift;
192
  my $page  = shift;
193
  my $data  = shift;
194
  my %arg   = @_;
195

  
196
  #=====================================
197
  # Mandatory Arguments Section
198
  #=====================================
199
  unless ($pdf and $page and $data) {
200
    print "Error: Mandatory parameter is missing pdf/page/data object!\n";
201
    return;
202
  }
203
  # Try to provide backward compatibility
204
  foreach my $key (keys %arg) {
205
    my $newkey = $key;
206
    if ($newkey =~ s#^-##) {
207
      $arg{$newkey} = $arg{$key};
208
      delete $arg{$key};
387
    my $header_row  = undef;
388
    #=====================================
389
    # Other Parameters check
390
    #=====================================
391
    my $lead          = $arg{'lead'          } || $fnt_size;
392
    my $pad_left      = $arg{'padding_left'  } || $arg{'padding'} || 0;
393
    my $pad_right     = $arg{'padding_right' } || $arg{'padding'} || 0;
394
    my $pad_top       = $arg{'padding_top'   } || $arg{'padding'} || 0;
395
    my $pad_bot       = $arg{'padding_bottom'} || $arg{'padding'} || 0;
396
    my $line_w        = defined $arg{'border'} ? $arg{'border'} : 1 ;
397
    my $horiz_borders = defined $arg{'horizontal_borders'}
398
        ? $arg{'horizontal_borders'}
399
        : $line_w;
400
    my $vert_borders  = defined $arg{'vertical_borders'}
401
        ? $arg{'vertical_borders'}
402
        : $line_w;
403
    
404
    my $background_color_even   = $arg{'background_color_even'  } || $arg{'background_color'} || undef;
405
    my $background_color_odd    = $arg{'background_color_odd'   } || $arg{'background_color'} || undef;
406
    my $font_color_even         = $arg{'font_color_even'        } || $arg{'font_color'      } || 'black';
407
    my $font_color_odd          = $arg{'font_color_odd'         } || $arg{'font_color'      } || 'black';
408
    my $border_color            = $arg{'border_color'           } || 'black';
409

  
410
    my $min_row_h   = $fnt_size + $pad_top + $pad_bot;
411
    my $row_h       = defined ($arg{'row_height'}) 
412
                                && 
413
                    ($arg{'row_height'} > $min_row_h) 
414
                                ? 
415
                     $arg{'row_height'} : $min_row_h;
416

  
417
    my $pg_cnt      = 1;
418
    my $cur_y       = $ybase;
419
    my $cell_props  = $arg{cell_props} || [];   # per cell properties
420

  
421
    #If there is no valid data array reference warn and return!
422
    if(ref $data ne 'ARRAY')
423
    {
424
        carp "Passed table data is not an ARRAY reference. It's actually a ref to ".ref($data);
425
        return ($page,0,$cur_y);
209 426
    }
210
  }
211
  #TODO: Add code for header props compatibility and col_props comp....
212
  #####
213
  my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
214
  # Could be 'int' or 'real' values
215
  $xbase  = $arg{'x'    } || -1;
216
  $ybase  = $arg{'start_y'} || -1;
217
  $width  = $arg{'w'    } || -1;
218
  $height = $arg{'start_h'} || -1;
219

  
220
  # Global geometry parameters are also mandatory.
221
  unless ( $xbase  > 0 ) { print "Error: Left Edge of Table is NOT defined!\n"; return; }
222
  unless ( $ybase  > 0 ) { print "Error: Base Line of Table is NOT defined!\n"; return; }
223
  unless ( $width  > 0 ) { print "Error: Width of Table is NOT defined!\n";     return; }
224
  unless ( $height > 0 ) { print "Error: Height of Table is NOT defined!\n";    return; }
225

  
226
  # Ensure default values for -next_y and -next_h
227
  my $next_y       = $arg{'next_y'} || $arg{'start_y'} || 0;
228
  my $next_h       = $arg{'next_h'} || $arg{'start_h'} || 0;
229

  
230
  # Create Text Object
231
  my $txt          = $page->text;
232
  # Set Default Properties
233
  my $fnt_name     = $arg{'font'}            || $pdf->corefont('Times', -encode => 'utf8');
234
  my $fnt_size     = $arg{'font_size'}       || 12;
235
  my $max_word_len = $arg{'max_word_length'} || 20;
236

  
237
  #=====================================
238
  # Table Header Section
239
  #=====================================
240
  # Disable header row into the table
241
  my $header_props;
242
  my $num_header_rows = 0;
243
  my (@header_rows, @header_row_cell_props);
244
  # Check if the user enabled it ?
245
  if (defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH') {
246
    # Transfer the reference to local variable
247
    $header_props = $arg{'header_props'};
248
    # Check other params and put defaults if needed
249
    $header_props->{'repeat'}     = $header_props->{'repeat'}     || 0;
250
    $header_props->{'font'}       = $header_props->{'font'}       || $fnt_name;
251
    $header_props->{'font_color'} = $header_props->{'font_color'} || '#000066';
252
    $header_props->{'font_size'}  = $header_props->{'font_size'}  || $fnt_size + 2;
253
    $header_props->{'bg_color'}   = $header_props->{'bg_color'}   || '#FFFFAA';
254

  
255
    $num_header_rows              = $arg{'num_header_rows'}       || 1;
256
  }
257
  #=====================================
258
  # Other Parameters check
259
  #=====================================
260

  
261
  my $lead      = $arg{'lead'}           || $fnt_size;
262
  my $pad_left  = $arg{'padding_left'}   || $arg{'padding'} || 0;
263
  my $pad_right = $arg{'padding_right'}  || $arg{'padding'} || 0;
264
  my $pad_top   = $arg{'padding_top'}    || $arg{'padding'} || 0;
265
  my $pad_bot   = $arg{'padding_bottom'} || $arg{'padding'} || 0;
266
  my $pad_w     = $pad_left + $pad_right;
267
  my $pad_h     = $pad_top  + $pad_bot  ;
268
  my $line_w    = defined $arg{'border'} ? $arg{'border'} : 1 ;
269

  
270
  my $background_color_even = $arg{'background_color_even'} || $arg{'background_color'} || undef;
271
  my $background_color_odd  = $arg{'background_color_odd'}  || $arg{'background_color'} || undef;
272
  my $font_color_even       = $arg{'font_color_even'}       || $arg{'font_color'}       || 'black';
273
  my $font_color_odd        = $arg{'font_color_odd'}        || $arg{'font_color'}       || 'black';
274
  my $border_color          = $arg{'border_color'}          || 'black';
275

  
276
  my $min_row_h  = $fnt_size + $pad_top + $pad_bot;
277
  my $row_h      = defined ($arg{'row_height'}) && ($arg{'row_height'} > $min_row_h) ? $arg{'row_height'} : $min_row_h;
278

  
279
  my $pg_cnt     = 1;
280
  my $cur_y      = $ybase;
281
  my $cell_props = $arg{cell_props} || [];   # per cell properties
282
  my $row_cnt    = $num_header_rows;
283

  
284
  #If there is valid data array reference use it!
285
  if (ref $data eq 'ARRAY') {
427

  
286 428
    # Copy the header row if header is enabled
287
    if (defined $header_props) {
288
      map { push @header_rows,           $$data[$_] }       (0..$num_header_rows - 1);
289
      map { push @header_row_cell_props, $$cell_props[$_] } (0..$num_header_rows - 1);
290
    }
429
    @$header_row = $$data[0] if defined $header_props;
291 430
    # Determine column widths based on content
292 431

  
293
    #  an arrayref whose values are a hashref holding
432
    #  an arrayref whose values are a hashref holding 
294 433
    #  the minimum and maximum width of that column
295 434
    my $col_props =  $arg{'column_props'} || [];
296 435

  
297
    # An array ref of arrayrefs whose values are
436
    # An array ref of arrayrefs whose values are 
298 437
    #  the actual widths of the column/row intersection
299
    my $row_props = [];
300
    # An array ref with the widths of the header row
301
    my @header_row_widths;
302

  
303
    # Scalars that hold sum of the maximum and minimum widths of all columns
304
    my ( $max_col_w, $min_col_w ) = ( 0,0 );
438
    my $row_col_widths = [];
439
    # An array ref with the widths of the header row 
440
    my $header_row_props = [];
441
 
442
    # Scalars that hold sum of the maximum and minimum widths of all columns 
443
    my ( $max_col_w  , $min_col_w   ) = ( 0,0 );
305 444
    my ( $row, $col_name, $col_fnt_size, $space_w );
306 445

  
307
    # Hash that will hold the width of every word from input text
308
    my $word_w       = {};
309
    my $rows_counter = 0;
310

  
311
    foreach $row ( @{$data} ) {
312
      push(@header_row_widths, []) if ($rows_counter < $num_header_rows);
446
    my $word_widths  = {};
447
    my $rows_height  = [];
448
    my $first_row    = 1;
313 449

  
314
      my $column_widths = []; #holds the width of each column
315
      for( my $j = 0; $j < scalar(@$row) ; $j++ ) {
316
        # look for font information for this column
317
        $col_fnt_size   =  $col_props->[$j]->{'font_size'} || $fnt_size;
318
        if ( !$rows_counter and ref $header_props) {
319
          $txt->font(  $header_props->{'font'}, $header_props->{'font_size'} );
320

  
321
        } elsif ( $col_props->[$j]->{'font'} ) {
322
          $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size );
323

  
324
        } else {
325
          $txt->font( $fnt_name, $col_fnt_size );
326
        }
327

  
328
        # This should fix a bug with very long word like serial numbers etc.
329
        # $myone is used because $1 gets out of scope in while condition
330
        my $myone;
331
        do {
332
          $myone = 0;
333
          # This RegEx will split any word that is longer than {25} symbols
334
          $row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#;
335
          $myone = 1 if ( defined $2 );
336
        } while( $myone );
337
        $row->[$j] =~ s/^\s+//;
338

  
339
        $space_w             = $txt->advancewidth( "\x20" );
340
        $column_widths->[$j] = 0;
341
        $max_col_w           = 0;
342
        $min_col_w           = 0;
343

  
344
        my @words = split( /\s+/, $row->[$j] );
345

  
346
        foreach( @words ) {
347
          unless ( exists $word_w->{$_} ) { # Calculate the width of every word and add the space width to it
348
            $word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
349
          }
350
          $column_widths->[$j] += $word_w->{$_};
351
          $min_col_w            = $word_w->{$_} if $word_w->{$_} > $min_col_w;
352
          $max_col_w           += $word_w->{$_};
353
        }
354
        $min_col_w             += $pad_w;
355
        $max_col_w             += $pad_w;
356
        $column_widths->[$j]   += $pad_w;
450
    for( my $row_idx = 0; $row_idx < scalar(@$data) ; $row_idx++ )
451
    {
452
        my $column_widths = []; #holds the width of each column
453
        # Init the height for this row
454
        $rows_height->[$row_idx] = 0;
455
        
456
        for( my $column_idx = 0; $column_idx < scalar(@{$data->[$row_idx]}) ; $column_idx++ )
457
        {
458
            # look for font information for this column
459
            my ($cell_font, $cell_font_size);
460
            
461
            if( !$row_idx and ref $header_props )
462
            {   
463
                $cell_font      = $header_props->{'font'};
464
                $cell_font_size = $header_props->{'font_size'};
465
            }
466
            
467
            # Get the most specific value if none was already set from header_props
468
            $cell_font      ||= $cell_props->[$row_idx][$column_idx]->{'font'} 
469
                            ||  $col_props->[$column_idx]->{'font'}
470
                            ||  $fnt_name;
471
                              
472
            $cell_font_size ||= $cell_props->[$row_idx][$column_idx]->{'font_size'}
473
                            ||  $col_props->[$column_idx]->{'font_size'}
474
                            ||  $fnt_size;
475
                              
476
            # Set Font
477
            $txt->font( $cell_font, $cell_font_size ); 
478
            
479
            # Set row height to biggest font size from row's cells
480
            if( $cell_font_size  > $rows_height->[$row_idx] )
481
            {   
482
                $rows_height->[$row_idx] = $cell_font_size;
483
            }
357 484

  
358
        # Keep a running total of the overall min and max widths
359
        $col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0;
360
        $col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0;
485
            # This should fix a bug with very long words like serial numbers etc.
486
            if( $max_word_len > 0 )
487
            {
488
                $data->[$row_idx][$column_idx] =~ s#(\S{$max_word_len})(?=\S)#$1 #g;
489
            }
361 490

  
362
        if ( $min_col_w > $col_props->[$j]->{min_w} ) { # Calculated Minimum Column Width is more than user-defined
363
          $col_props->[$j]->{min_w}    = $min_col_w ;
364
        }
365
        if ( $max_col_w > $col_props->[$j]->{max_w} ) { # Calculated Maximum Column Width is more than user-defined
366
          $col_props->[$j]->{max_w}    = $max_col_w ;
367
        }
368
      }#End of for(my $j....
369
      $row_props->[$rows_counter] = $column_widths;
370
      # Copy the calculated row properties of header row.
371
      if (($rows_counter < $num_header_rows) && $header_props) {
372
        push(@header_row_widths, [ @{ $column_widths } ]);
373
      }
374
      $rows_counter++;
491
            # Init cell size limits
492
            $space_w                      = $txt->advancewidth( "\x20" );
493
            $column_widths->[$column_idx] = 0;
494
            $max_col_w                    = 0;
495
            $min_col_w                    = 0;
496

  
497
            my @words = split( /\s+/, $data->[$row_idx][$column_idx] );
498

  
499
            foreach( @words ) 
500
            {
501
                unless( exists $word_widths->{$_} )
502
                {   # Calculate the width of every word and add the space width to it
503
                    $word_widths->{$_} = $txt->advancewidth( $_ ) + $space_w;
504
                }
505
                
506
                $column_widths->[$column_idx] += $word_widths->{$_};
507
                $min_col_w                     = $word_widths->{$_} if( $word_widths->{$_} > $min_col_w );
508
                $max_col_w                    += $word_widths->{$_};
509
            }
510
            
511
            $min_col_w                    += $pad_left + $pad_right;
512
            $max_col_w                    += $pad_left + $pad_right;
513
            $column_widths->[$column_idx] += $pad_left + $pad_right;
514

  
515
            # Keep a running total of the overall min and max widths
516
            $col_props->[$column_idx]->{'min_w'} ||= 0;
517
            $col_props->[$column_idx]->{'max_w'} ||= 0;
518

  
519
            if( $min_col_w > $col_props->[$column_idx]->{'min_w'} )
520
            {   # Calculated Minimum Column Width is more than user-defined
521
                $col_props->[$column_idx]->{'min_w'} = $min_col_w ;
522
            }
523
            
524
            if( $max_col_w > $col_props->[$column_idx]->{'max_w'} )
525
            {   # Calculated Maximum Column Width is more than user-defined
526
                $col_props->[$column_idx]->{'max_w'} = $max_col_w ;
527
            }
528
        }#End of for(my $column_idx....
529
        
530
        $row_col_widths->[$row_idx] = $column_widths;
531
        
532
        # Copy the calculated row properties of header row. 
533
        @$header_row_props = @$column_widths if(!$row_idx and ref $header_props);
375 534
    }
535

  
376 536
    # Calc real column widths and expand table width if needed.
377
    my $calc_column_widths;
378
    ($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width );
379
    my $num_cols  = scalar @{ $calc_column_widths };
380
    my $comp_cnt  = 1;
381
    $rows_counter = 0;
537
    my $calc_column_widths; 
538
    ($calc_column_widths, $width) = CalcColumnWidths( $col_props, $width );
382 539

  
383
    my ( $gfx   , $gfx_bg   , $background_color , $font_color,        );
384
    my ( $bot_marg, $table_top_y, $text_start   , $record,  $record_widths  );
540
    # Lets draw what we have!
541
    my $row_index    = 0;
542
    # Store header row height for later use if headers have to be repeated
543
    my $header_row_height = $rows_height->[0];
385 544

  
386
    my $remaining_header_rows = $header_props ? $num_header_rows : 0;
545
    my ( $gfx, $gfx_bg, $background_color, $font_color, $bot_marg, $table_top_y, $text_start);
387 546

  
388 547
    # Each iteration adds a new page as neccessary
389
    while(scalar(@{$data})) {
390
      my $page_header;
391
      if ($pg_cnt == 1) {
392
        $table_top_y = $ybase;
393
        $bot_marg = $table_top_y - $height;
394

  
395
      } else {
396
        if (ref $arg{'new_page_func'}) {
397
          $page = &{$arg{'new_page_func'}};
398

  
399
        } else {
400
          $page = $pdf->page;
401
        }
402

  
403
        $table_top_y = $next_y;
404
        $bot_marg = $table_top_y - $next_h;
548
    while(scalar(@{$data}))
549
    {
550
        my ($page_header, $columns_number);
405 551

  
406
        if ( ref $header_props and $header_props->{'repeat'}) {
407
          foreach my $idx (0 .. $num_header_rows - 1) {
408
            unshift @$data,      [ @{ $header_rows[$idx]      } ];
409
            unshift @$row_props, [ @{ $header_row_widths[$idx] } ];
410
          }
411
          $remaining_header_rows = $num_header_rows;
552
        if($pg_cnt == 1)
553
        {
554
            $table_top_y = $ybase;
555
            $bot_marg = $table_top_y - $height;
412 556
        }
413
      }
414

  
415
      # Check for safety reasons
416
      if ( $bot_marg < 0 ) { # This warning should remain i think
417
#         print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
418
        $bot_marg = 0;
419
      }
420

  
421
      $gfx_bg = $page->gfx;
422
      $txt = $page->text;
423
      $txt->font($fnt_name, $fnt_size);
424
      $gfx = $page->gfx;
425
      $gfx->strokecolor($border_color);
426
      $gfx->linewidth($line_w);
427

  
428
      # Draw the top line
429
      $cur_y = $table_top_y;
430
      $gfx->move( $xbase , $cur_y );
431
      $gfx->hline($xbase + $width );
432

  
433
      # Each iteration adds a row to the current page until the page is full
434
      #  or there are no more rows to add
435
      while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg) {
436
        # Remove the next item from $data
437
        $record = shift @{$data};
438
        # Added to resolve infite loop bug with returned undef values
439
        for(my $d = 0; $d < scalar(@{$record}) ; $d++) {
440
          $record->[$d] = '-' unless ( defined $record->[$d]);
557
        else
558
        {
559
            if(ref $arg{'new_page_func'})
560
            {   
561
                $page = &{$arg{'new_page_func'}};   
562
            }
563
            else
564
            {   
565
                $page = $pdf->page; 
566
            }
567
    
568
            $table_top_y = $next_y;
569
            $bot_marg = $table_top_y - $next_h;
570

  
571
            if( ref $header_props and $header_props->{'repeat'})
572
            {
573
                # Copy Header Data
574
                @$page_header = @$header_row;
575
                my $hrp ;
576
                @$hrp = @$header_row_props ;
577
                # Then prepend it to master data array
578
                unshift @$data, @$page_header;
579
                unshift @$row_col_widths, $hrp;
580
                unshift @$rows_height, $header_row_height;
581

  
582
                $first_row = 1; # Means YES
583
                $row_index--; # Rollback the row_index because a new header row has been added
584
            }
441 585
        }
442 586

  
443
        $record_widths = shift @$row_props;
444
        next unless $record;
445

  
446
        # Choose colors for this row
447
        $background_color = $rows_counter % 2 ? $background_color_even  : $background_color_odd;
448
        $font_color     = $rows_counter % 2 ? $font_color_even    : $font_color_odd;
449

  
450
        if ($remaining_header_rows and ref $header_props) {
451
          $background_color = $header_props->{'bg_color'}
587
        # Check for safety reasons
588
        if( $bot_marg < 0 )
589
        {   # This warning should remain i think
590
            carp "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
591
            $bot_marg = 0;
452 592
        }
453
        $text_start    = $cur_y - $fnt_size - $pad_top;
454
        my $cur_x    = $xbase;
455
        my $leftovers    = undef; # Reference to text that is returned from textblock()
456
        my $do_leftovers = 0;
457

  
458
        my ($colspan, @vertical_lines);
459 593

  
460
        # Process every column from current row
461
        for( my $j = 0; $j < scalar( @$record); $j++ ) {
462
          next unless $col_props->[$j]->{max_w};
463
          next unless $col_props->[$j]->{min_w};
464
          $leftovers->[$j] = undef;
594
        $gfx_bg = $page->gfx;
595
        $txt = $page->text;
596
        $txt->font($fnt_name, $fnt_size); 
465 597

  
466
          # Choose font color
467
          if ( $remaining_header_rows and ref $header_props ) {
468
            $txt->fillcolor( $header_props->{'font_color'} );
598
        $cur_y = $table_top_y;
469 599

  
470
          } elsif ( $cell_props->[$row_cnt][$j]{font_color} ) {
471
            $txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} );
600
        if ($line_w)
601
        {
602
            $gfx = $page->gfx;
603
            $gfx->strokecolor($border_color);
604
            $gfx->linewidth($line_w);
472 605

  
473
          } elsif ( $col_props->[$j]->{'font_color'} ) {
474
            $txt->fillcolor( $col_props->[$j]->{'font_color'} );
606
            # Draw the top line
607
            if ($horiz_borders) 
608
            {
609
                $gfx->move( $xbase , $cur_y );
610
                $gfx->hline($xbase + $width );
611
            }
612
        }
613
        else
614
        {
615
            $gfx = undef;
616
        }
475 617

  
476
          } else {
477
            $txt->fillcolor($font_color);
478
          }
618
        # Each iteration adds a row to the current page until the page is full 
619
        #  or there are no more rows to add
620
        # Row_Loop
621
        while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
622
        {
623
            # Remove the next item from $data
624
            my $record = shift @{$data};
625
            
626
            # Get columns number to know later how many vertical lines to draw
627
            # TODO: get the max number of columns per page as currently last row's columns overrides
628
            $columns_number = scalar(@$record);
629

  
630
            # Get the next set of row related settings
631
            # Row Height
632
            my $pre_calculated_row_height = shift @$rows_height;
633

  
634
            # Row cell widths
635
            my $record_widths = shift @$row_col_widths;
636

  
637
            # Row coloumn props - TODO in another commit
638

  
639
            # Row cell props - TODO in another commit
640

  
641
            # Added to resolve infite loop bug with returned undef values
642
            for(my $d = 0; $d < scalar(@{$record}) ; $d++)
643
            { 
644
                $record->[$d] = '-' unless( defined $record->[$d]); 
645
            }
479 646

  
480
          # Choose font size
481
          if ( $remaining_header_rows and ref $header_props ) {
482
            $col_fnt_size = $header_props->{'font_size'};
647
            # Choose colors for this row
648
            $background_color = $row_index % 2 ? $background_color_even  : $background_color_odd;
649
            $font_color       = $row_index % 2 ? $font_color_even        : $font_color_odd;
483 650

  
484
          } elsif ( $col_props->[$j]->{'font_size'} ) {
485
            $col_fnt_size = $col_props->[$j]->{'font_size'};
651
            #Determine current row height
652
            my $current_row_height = $pad_top + $pre_calculated_row_height + $pad_bot;
486 653

  
487
          } else {
488
            $col_fnt_size = $fnt_size;
489
          }
654
            # $row_h is the calculated global user requested row height.
655
            # It will be honored, only if it has bigger value than the calculated one.
656
            # TODO: It's questionable if padding should be inclided in this calculation or not
657
            if($current_row_height < $row_h){
658
                $current_row_height = $row_h;
659
            }
490 660

  
491
          # Choose font family
492
          if ( $remaining_header_rows and ref $header_props ) {
493
            $txt->font( $header_props->{'font'}, $header_props->{'font_size'});
661
            # Define the font y base position for this line.
662
            $text_start      = $cur_y - ($current_row_height - $pad_bot);
663

  
664
            my $cur_x        = $xbase;
665
            my $leftovers    = undef;   # Reference to text that is returned from textblock()
666
            my $do_leftovers = 0;
667

  
668
            # Process every cell(column) from current row
669
            for( my $column_idx = 0; $column_idx < scalar( @$record); $column_idx++ ) 
670
            {
671
                next unless $col_props->[$column_idx]->{'max_w'};
672
                next unless $col_props->[$column_idx]->{'min_w'};  
673
                $leftovers->[$column_idx] = undef;
674

  
675
                # look for font information for this cell
676
                my ($cell_font, $cell_font_size, $cell_font_color, $justify);
677
                                    
678
                if( $first_row and ref $header_props)
679
                {   
680
                    $cell_font       = $header_props->{'font'};
681
                    $cell_font_size  = $header_props->{'font_size'};
682
                    $cell_font_color = $header_props->{'font_color'};
683
                    $justify         = $header_props->{'justify'};
684
                }
685
                
686
                # Get the most specific value if none was already set from header_props
687
                $cell_font       ||= $cell_props->[$row_index][$column_idx]->{'font'} 
688
                                 ||  $col_props->[$column_idx]->{'font'}
689
                                 ||  $fnt_name;
690
                                  
691
                $cell_font_size  ||= $cell_props->[$row_index][$column_idx]->{'font_size'}
692
                                 ||  $col_props->[$column_idx]->{'font_size'}
693
                                 ||  $fnt_size;
694
                                  
695
                $cell_font_color ||= $cell_props->[$row_index][$column_idx]->{'font_color'}
696
                                 ||  $col_props->[$column_idx]->{'font_color'}
697
                                 ||  $font_color;
698
                                
699
                $justify         ||= $cell_props->[$row_index][$column_idx]->{'justify'}
700
                                 ||  $col_props->[$column_idx]->{'justify'}
701
                                 ||  $arg{'justify'}
702
                                 ||  'left';                                    
703
                
704
                # Init cell font object
705
                $txt->font( $cell_font, $cell_font_size );
706
                $txt->fillcolor($cell_font_color);
707
 
708
                # If the content is wider than the specified width, we need to add the text as a text block
709
                if( $record->[$column_idx] !~ m/(.\n.)/ and
710
                    $record_widths->[$column_idx] and 
711
                    $record_widths->[$column_idx] <= $calc_column_widths->[$column_idx]
712
                ){
713
                    my $space = $pad_left;
714
                    if ($justify eq 'right')
715
                    {
716
                        $space = $calc_column_widths->[$column_idx] -($txt->advancewidth($record->[$column_idx]) + $pad_right);
717
                    }
718
                    elsif ($justify eq 'center')
719
                    {
720
                        $space = ($calc_column_widths->[$column_idx] - $txt->advancewidth($record->[$column_idx])) / 2;
721
                    }
722
                    $txt->translate( $cur_x + $space, $text_start );
723
                    $txt->text( $record->[$column_idx] );
724
                }
725
                # Otherwise just use the $page->text() method
726
                else
727
                {
728
                    my ($width_of_last_line, $ypos_of_last_line, $left_over_text) = $self->text_block(
729
                        $txt,
730
                        $record->[$column_idx],
731
                        x        => $cur_x + $pad_left,
732
                        y        => $text_start,
733
                        w        => $calc_column_widths->[$column_idx] - $pad_left - $pad_right,
734
                        h        => $cur_y - $bot_marg - $pad_top - $pad_bot,
735
                        align    => $justify,
736
                        lead     => $lead
737
                    );
738
                    # Desi - Removed $lead because of fixed incorrect ypos bug in text_block
739
                    my  $current_cell_height = $cur_y - $ypos_of_last_line + $pad_bot;
740
                    if( $current_cell_height > $current_row_height )
741
                    {
742
                        $current_row_height = $current_cell_height;
743
                    }
744
                    
745
                    if( $left_over_text )
746
                    {
747
                        $leftovers->[$column_idx] = $left_over_text;
748
                        $do_leftovers = 1;
749
                    }
750
                }
751
                $cur_x += $calc_column_widths->[$column_idx];
752
            }
753
            if( $do_leftovers )
754
            {
755
                unshift @$data, $leftovers;
756
                unshift @$row_col_widths, $record_widths;
757
                unshift @$rows_height, $pre_calculated_row_height;
758
            }
759
            
760
            # Draw cell bgcolor
761
            # This has to be separately from the text loop 
762
            #  because we do not know the final height of the cell until all text has been drawn
763
            $cur_x = $xbase;
764
            for(my $column_idx = 0 ; $column_idx < scalar(@$record) ; $column_idx++)
765
            {
766
                my $cell_bg_color;
767
                                    
768
                if( $first_row and ref $header_props)
769
                {                                  #Compatibility                 Consistency with other props    
770
                    $cell_bg_color = $header_props->{'bg_color'} || $header_props->{'background_color'};
771
                }
772
                
773
                # Get the most specific value if none was already set from header_props
774
                $cell_bg_color ||= $cell_props->[$row_index][$column_idx]->{'background_color'} 
775
                               ||  $col_props->[$column_idx]->{'background_color'}
776
                               ||  $background_color;
777

  
778
                if ($cell_bg_color)
779
                {
780
                    $gfx_bg->rect( $cur_x, $cur_y-$current_row_height, $calc_column_widths->[$column_idx], $current_row_height);
781
                    $gfx_bg->fillcolor($cell_bg_color);
782
                    $gfx_bg->fill();
783
                }
784
                $cur_x += $calc_column_widths->[$column_idx];
785
            }#End of for(my $column_idx....
786

  
787
            $cur_y -= $current_row_height;
788
            if ($gfx && $horiz_borders)
789
            {
790
                $gfx->move(  $xbase , $cur_y );
791
                $gfx->hline( $xbase + $width );
792
            }
494 793

  
495
          } elsif ( $col_props->[$j]->{'font'} ) {
496
            $txt->font( $col_props->[$j]->{'font'}, $col_fnt_size);
794
            $row_index++ unless ( $do_leftovers );
795
            $first_row = 0;
796
        }# End of Row_Loop
797

  
798
        if ($gfx)
799
        {
800
            # Draw vertical lines
801
            if ($vert_borders) 
802
            {
803
                $gfx->move(  $xbase, $table_top_y);
804
                $gfx->vline( $cur_y );
805
                my $cur_x = $xbase;
806
                for( my $j = 0; $j < $columns_number; $j++ )
807
                {
808
                    $cur_x += $calc_column_widths->[$j];
809
                    $gfx->move(  $cur_x, $table_top_y );
810
                    $gfx->vline( $cur_y );
811
                }
812
            }
497 813

  
498
          } else {
499
            $txt->font( $fnt_name, $col_fnt_size);
500
          }
501
          #TODO: Implement Center text align
502
          $col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left';
814
            # ACTUALLY draw all the lines
815
            $gfx->fillcolor( $border_color);
816
            $gfx->stroke;
817
        }
818
        $pg_cnt++;
819
    }# End of while(scalar(@{$data}))
503 820

  
504
          my $this_width;
505
          if (!$remaining_header_rows && $cell_props->[$row_cnt]->[$j]->{colspan}) {
506
            $colspan = $cell_props->[$row_cnt]->[$j]->{colspan};
821
    return ($page,--$pg_cnt,$cur_y);
822
}
507 823

  
508
          } elsif ($remaining_header_rows && $header_row_cell_props[$num_header_rows - $remaining_header_rows]->[$j]->{colspan}) {
509
            $colspan = $header_row_cell_props[$num_header_rows - $remaining_header_rows]->[$j]->{colspan};
510 824

  
511
          }
825
# calculate the column widths
826
sub CalcColumnWidths
827
{
828
    my $col_props   = shift;
829
    my $avail_width = shift;
830
    my $min_width   = 0;
512 831

  
513
          if ($colspan) {
514
            $colspan     = $num_cols - $j if (-1 == $colspan);
515
            my $last_idx = $j + $colspan - 1;
516
            $this_width  = sum @{ $calc_column_widths }[$j..$last_idx];
832
    my $calc_widths ;
517 833

  
518
          } else {
519
            $this_width = $calc_column_widths->[$j];
520
          }
834
    for(my $j = 0; $j < scalar( @$col_props); $j++)
835
    {
836
        $min_width += $col_props->[$j]->{min_w} || 0;
837
    }
521 838

  
522
          # If the content is wider than the specified width, we need to add the text as a text block
523
          if ($record->[$j] !~ m#(.\n.)# and  $record_widths->[$j] and ($record_widths->[$j] < $this_width)) {
524
            my $space = $pad_left;
525
            if ($col_props->[$j]->{justify} eq 'right') {
526
              $space = $this_width -($txt->advancewidth($record->[$j]) + $pad_right);
527
            }
528
            $txt->translate( $cur_x + $space, $text_start );
529
            $txt->text( $record->[$j] );
530
          } else { # Otherwise just use the $page->text() method
531
            my($width_of_last_line, $ypos_of_last_line, $left_over_text) =
532
              $self->text_block($txt,
533
                                $record->[$j],
534
                                'x'     => $cur_x + $pad_left,
535
                                'y'     => $text_start,
536
                                'w'     => $this_width - $pad_w,
537
                                'h'     => $cur_y - $bot_marg - $pad_top - $pad_bot,
538
                                'align' => $col_props->[$j]->{justify},
539
                                'lead'  => $lead
540
              );
541
            # Desi - Removed $lead because of fixed incorrect ypos bug in text_block
542
            my $this_row_h = $cur_y - ( $ypos_of_last_line - $pad_bot );
543
            $row_h = $this_row_h if $this_row_h > $row_h;
544
            if ( $left_over_text ) {
545
              $leftovers->[$j] = $left_over_text;
546
              $do_leftovers    = 1;
547
            }
548
          }
549
          $cur_x += $calc_column_widths->[$j];
839
    # I think this is the optimal variant when good view can be guaranateed
840
    if($avail_width < $min_width)
841
    {
842
        carp "!!! Warning !!!\n Calculated Mininal width($min_width) > Table width($avail_width).\n",
843
            ' Expanding table width to:',int($min_width)+1,' but this could lead to unexpected results.',"\n",
844
            ' Possible solutions:',"\n",
845
            '  0)Increase table width.',"\n",
846
            '  1)Decrease font size.',"\n",
847
            '  2)Choose a more narrow font.',"\n",
848
            '  3)Decrease "max_word_length" parameter.',"\n",
849
            '  4)Rotate page to landscape(if it is portrait).',"\n",
850
            '  5)Use larger paper size.',"\n",
851
            '!!! --------- !!!',"\n";
852
        $avail_width = int( $min_width) + 1;
550 853

  
551
          push @vertical_lines, (!$colspan || (1 >= $colspan)) ? 1 : 0;
552
          $colspan-- if ($colspan);
553
        }
854
    }
554 855

  
555
        if ( $do_leftovers ) {
556
          unshift @$data, $leftovers;
557
          unshift @$row_props, $record_widths;
558
          $rows_counter--;
559
        }
856
    # Calculate how much can be added to every column to fit the available width.
857
    for(my $j = 0; $j < scalar(@$col_props); $j++ )
858
    {
859
        $calc_widths->[$j] = $col_props->[$j]->{min_w} || 0;;
860
    }
560 861

  
561
        # Draw cell bgcolor
562
        # This has to be separately from the text loop
563
        #  because we do not know the final height of the cell until all text has been drawn
564
        $cur_x = $xbase;
565
        for(my $j =0;$j < scalar(@$record);$j++) {
566
          if (  $cell_props->[$row_cnt][$j]->{'background_color'} ||
567
                $col_props->[$j]->{'background_color'} ||
568
                $background_color ) {
569
            $gfx_bg->rect( $cur_x, $cur_y-$row_h, $calc_column_widths->[$j], $row_h);
570
            if ( $cell_props->[$row_cnt][$j]->{'background_color'} && !$remaining_header_rows ) {
571
              $gfx_bg->fillcolor($cell_props->[$row_cnt][$j]->{'background_color'});
572

  
573
            } elsif ( $col_props->[$j]->{'background_color'} && !$remaining_header_rows  ) {
574
              $gfx_bg->fillcolor($col_props->[$j]->{'background_color'});
575

  
576
            } else {
577
              $gfx_bg->fillcolor($background_color);
862
    # Allow columns to expand to max_w before applying extra space equally.
863
    my $is_last_iter;
864
    for (;;)
865
    {
866
        my $span = ($avail_width - $min_width) / scalar( @$col_props);
867
        last if $span <= 0;
868

  
869
        $min_width = 0;
870
        my $next_will_be_last_iter = 1;
871
        for(my $j = 0; $j < scalar(@$col_props); $j++ )
872
        {
873
            my $new_w = $calc_widths->[$j] + $span;
874

  
875
            if (!$is_last_iter && $new_w > $col_props->[$j]->{max_w})
876
            {
877
                $new_w = $col_props->[$j]->{max_w}
578 878
            }
579
            $gfx_bg->fill();
580
          }
581

  
582
          $cur_x += $calc_column_widths->[$j];
583

  
584
          if ($line_w && $vertical_lines[$j] && ($j != (scalar(@{ $record }) - 1))) {
585
            $gfx->move($cur_x, $cur_y);
586
            $gfx->vline($cur_y - $row_h);
587
            $gfx->fillcolor($border_color);
588
          }
589
        }#End of for(my $j....
590

  
591
        $cur_y -= $row_h;
592
        $row_h  = $min_row_h;
593
        $gfx->move(  $xbase , $cur_y );
594
        $gfx->hline( $xbase + $width );
595
        $rows_counter++;
596
        if ($remaining_header_rows) {
597
          $remaining_header_rows--;
598
        } else {
599
          $row_cnt++ unless $do_leftovers;
879
            if ($calc_widths->[$j] != $new_w )
880
            {
881
                $calc_widths->[$j] = $new_w;
882
                $next_will_be_last_iter = 0;
883
            }
884
            $min_width += $new_w;
600 885
        }
601
      }# End of while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
602

  
603
      # Draw vertical lines
604
      if ($line_w) {
605
        $gfx->move($xbase, $table_top_y);
606
        $gfx->vline($cur_y);
607
        $gfx->move($xbase + sum(@{ $calc_column_widths }[0..$num_cols - 1]), $table_top_y);
608
        $gfx->vline($cur_y);
609
        $gfx->fillcolor($border_color);
610
        $gfx->stroke();
611
      }
612
      $pg_cnt++;
613
    }# End of while(scalar(@{$data}))
614
  }# End of if (ref $data eq 'ARRAY')
615

  
616
  return ($page,--$pg_cnt,$cur_y);
617
}
618

  
886
        last if $is_last_iter;
887
        $is_last_iter = $next_will_be_last_iter;
888
    }
619 889

  
620
# calculate the column widths
621
sub CalcColumnWidths {
622
  my $self    = shift;
623
  my $col_props   = shift;
624
  my $avail_width = shift;
625
  my $min_width   = 0;
626

  
627
  my $calc_widths ;
628
  for(my $j = 0; $j < scalar( @$col_props); $j++) {
629
    $min_width += $col_props->[$j]->{min_w};
630
  }
631

  
632
  # I think this is the optimal variant when good view can be guaranateed
633
  if ($avail_width < $min_width) {
634
#     print "!!! Warning !!!\n Calculated Mininal width($min_width) > Table width($avail_width).\n",
635
#       ' Expanding table width to:',int($min_width)+1,' but this could lead to unexpected results.',"\n",
636
#       ' Possible solutions:',"\n",
637
#       '  0)Increase table width.',"\n",
638
#       '  1)Decrease font size.',"\n",
639
#       '  2)Choose a more narrow font.',"\n",
640
#       '  3)Decrease "max_word_length" parameter.',"\n",
641
#       '  4)Rotate page to landscape(if it is portrait).',"\n",
642
#       '  5)Use larger paper size.',"\n",
643
#       '!!! --------- !!!',"\n";
644
    $avail_width = int( $min_width) + 1;
645

  
646
  }
647

  
648
  my $span = 0;
649
  # Calculate how much can be added to every column to fit the available width
650
  $span = ($avail_width - $min_width) / scalar( @$col_props);
651
  for (my $j = 0; $j < scalar(@$col_props); $j++ ) {
652
    $calc_widths->[$j] = $col_props->[$j]->{min_w} + $span;
653
  }
654

  
655
  return ($calc_widths,$avail_width);
890
    return ($calc_widths,$avail_width);
656 891
}
657 892
1;
658 893

  
......
693 928
     $some_data,
694 929
     x => $left_edge_of_table,
695 930
     w => 495,
696
     start_y => 750,
697
     next_y  => 700,
931
     start_y => 500,
698 932
     start_h => 300,
699
     next_h  => 500,
700 933
     # some optional params
934
     next_y  => 750,
935
     next_h  => 500,
701 936
     padding => 5,
702 937
     padding_right => 10,
703 938
     background_color_odd  => "gray",
......
715 950

  
716 951
=head1 DESCRIPTION
717 952

  
718
This class is a utility for use with the PDF::API2 module from CPAN.
719
It can be used to display text data in a table layout within the PDF.
720
The text data must be in a 2d array (such as returned by a DBI statement handle fetchall_arrayref() call).
721
The PDF::Table will automatically add as many new pages as necessary to display all of the data.
722
Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows.
723
Also a (non)repeated header row with different layout properties can be specified.
953
This class is a utility for use with the PDF::API2 module from CPAN. 
954
It can be used to display text data in a table layout within a PDF. 
955
The text data must be in a 2D array (such as returned by a DBI statement handle fetchall_arrayref() call). 
956
The PDF::Table will automatically add as many new pages as necessary to display all of the data. 
957
Various layout properties, such as font, font size, and cell padding and background color can be specified for each column and/or for even/odd rows. 
958
Also a (non)repeated header row with different layout properties can be specified. 
724 959

  
725
See the METHODS section for complete documentation of every parameter.
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff