Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 42b702a6

Von Moritz Bunkus vor fast 17 Jahren hinzugefügt

  • ID 42b702a6bbfdef8a094b1fafbdf205c986efd7be
  • Vorgänger de41ce6f
  • Nachfolger 93262a51

Umstellung der PDF-Erzeugungsroutine des ReportGenerator auf die Verwendung des Perl-Moduls PDF::API2, sofern es installiert ist, mit Fallback zur alten Routine mit html2ps.

Unterschiede anzeigen:

SL/InstallationCheck.pm
3 3
use English '-no_match_vars';
4 4
use IO::File;
5 5

  
6
use vars qw(@required_modules);
6
use vars qw(@required_modules @optional_modules);
7 7

  
8 8
@required_modules = (
9 9
  { "name" => "Class::Accessor", "url" => "http://search.cpan.org/~kasei/" },
......
22 22
  { "name" => "Digest::MD5", "url" => "http://search.cpan.org/~gaas/" },
23 23
  );
24 24

  
25
@optional_modules = (
26
  { "name" => "PDF::API2", "url" => "http://search.cpan.org/~areibens/" },
27
  );
28

  
25 29
sub module_available {
26 30
  my ($module) = @_;
27 31

  
SL/ReportGenerator.pm
28 28
    'html_template'         => 'report_generator/html_report',
29 29
    'pdf_template'          => 'report_generator/pdf_report',
30 30
    'pdf_export'            => {
31
      'paper_size'          => 'A4',
31
      'paper_size'          => 'a4',
32 32
      'orientation'         => 'landscape',
33
      'font_size'           => '10',
33
      'font_name'           => 'Verdana',
34
      'font_size'           => '7',
34 35
      'margin_top'          => 1.5,
35 36
      'margin_left'         => 1.5,
36 37
      'margin_bottom'       => 1.5,
......
187 188
  my $self    = shift;
188 189
  my %options = @_;
189 190

  
190
  map { $self->{options}->{$_} = $options{$_} } keys %options;
191
  while (my ($key, $value) = each %options) {
192
    if ($key eq 'pdf_export') {
193
      map { $self->{options}->{pdf_export}->{$_} = $value->{$_} } keys %{ $value };
194
    } else {
195
      $self->{options}->{$key} = $value;
196
    }
197
  }
191 198
}
192 199

  
193 200
sub set_options_from_form {
......
372 379

  
373 380
  my $allow_pdf_export = $opts->{allow_pdf_export} && (-x $main::html2ps_bin) && (-x $main::ghostscript_bin);
374 381

  
382
  eval { require PDF::API2; require PDF::Table; };
383
  $allow_pdf_export |= 1 if (! $@);
384

  
375 385
  my $variables = {
376 386
    'TITLE'                => $opts->{title},
377 387
    'TOP_INFO_TEXT'        => $self->html_format($opts->{top_info_text}),
......
400 410
  return $self->{form}->parse_html_template($self->{options}->{html_template}, $variables);
401 411
}
402 412

  
413
sub _cm2bp {
414
  # 1 bp = 1/72 in
415
  # 1 in = 2.54 cm
416
  return $_[0] * 72 / 2.54;
417
}
418

  
419
sub render_pdf_with_pdf_api2 {
420
  my $self       = shift;
421
  my $variables  = $self->prepare_html_content();
422
  my $form       = $self->{form};
423
  my $myconfig   = $self->{myconfig};
424

  
425
  my $opts       = $self->{options};
426
  my $params     = $opts->{pdf_export};
427

  
428
  my (@data, @column_props, @cell_props);
429

  
430
  my $data_row        = [];
431
  my $cell_props_row  = [];
432
  my @visible_columns = $self->get_visible_columns('HTML');
433

  
434
  foreach $name (@visible_columns) {
435
    $column = $self->{columns}->{$name};
436

  
437
    push @{ $data_row },       $column->{text};
438
    push @{ $cell_props_row }, {};
439
    push @column_props,        { 'justify' => $column->{align} eq 'right' ? 'right' : 'left' };
440
  }
441

  
442
  push @data,       $data_row;
443
  push @cell_props, $cell_props_row;
444

  
445
  my $num_columns = scalar @column_props;
446

  
447
  foreach my $row_set (@{ $self->{data} }) {
448
    if ('HASH' eq ref $row_set) {
449
      if ($row_set->{type} eq 'colspan_data') {
450
        push @data, [ $row_set->{data} ];
451

  
452
        $cell_props_row = [];
453
        push @cell_props, $cell_props_row;
454

  
455
        foreach (0 .. $num_columns - 1) {
456
          push @{ $cell_props_row }, { 'background_color' => '#000000',
457
                                       'font_color'       => '#ffffff', };
458
        }
459
      }
460
      next;
461
    }
462

  
463
    foreach my $row (@{ $row_set }) {
464
      $data_row = [];
465
      push @data, $data_row;
466

  
467
      my $col_idx = 0;
468
      foreach my $col_name (@visible_columns) {
469
        my $col = $row->{$col_name};
470
        push @{ $data_row }, join("\n", @{ $col->{data} });
471

  
472
        $column_props[$col_idx]->{justify} = 'right' if ($col->{align} eq 'right');
473

  
474
        $col_idx++;
475
      }
476

  
477
      $cell_props_row = [];
478
      push @cell_props, $cell_props_row;
479

  
480
      foreach (0 .. $num_columns - 1) {
481
        push @{ $cell_props_row }, { };
482
      }
483
    }
484
  }
485

  
486
  foreach my $i (0 .. scalar(@data) - 1) {
487
    my $aref             = $data[$i];
488
    my $num_columns_here = scalar @{ $aref };
489

  
490
    if ($num_columns_here < $num_columns) {
491
      push @{ $aref }, ('') x ($num_columns - $num_columns_here);
492
    } elsif ($num_columns_here > $num_columns) {
493
      splice @{ $aref }, $num_columns;
494
    }
495
  }
496

  
497
  my $papersizes = {
498
    'a3'         => [ 842, 1190 ],
499
    'a4'         => [ 595,  842 ],
500
    'a5'         => [ 420,  595 ],
501
    'letter'     => [ 612,  792 ],
502
    'legal'      => [ 612, 1008 ],
503
  };
504

  
505
  my %supported_fonts = map { $_ => 1 } qw(courier georgia helvetica times verdana);
506

  
507
  my $paper_size  = defined $params->{paper_size} && defined $papersizes->{lc $params->{paper_size}} ? lc $params->{paper_size} : 'a4';
508
  my ($paper_width, $paper_height);
509

  
510
  if (lc $params->{orientation} eq 'landscape') {
511
    ($paper_width, $paper_height) = @{$papersizes->{$paper_size}}[1, 0];
512
  } else {
513
    ($paper_width, $paper_height) = @{$papersizes->{$paper_size}}[0, 1];
514
  }
515

  
516
  my $margin_top        = _cm2bp($params->{margin_top}    || 1.5);
517
  my $margin_bottom     = _cm2bp($params->{margin_bottom} || 1.5);
518
  my $margin_left       = _cm2bp($params->{margin_left}   || 1.5);
519
  my $margin_right      = _cm2bp($params->{margin_right}  || 1.5);
520

  
521
  my $table             = PDF::Table->new();
522
  my $pdf               = PDF::API2->new();
523
  my $page              = $pdf->page();
524

  
525
  $pdf->mediabox($paper_width, $paper_height);
526

  
527
  my $font              = $pdf->corefont(defined $params->{font_name} && $supported_fonts{lc $params->{font_name}} ? ucfirst $params->{font_name} : 'Verdana',
528
                                         '-encoding' => $main::dbcharset || 'ISO-8859-15');
529
  my $font_size         = $params->{font_size} || 7;
530
  my $title_font_size   = $font_size + 1;
531
  my $padding           = 1;
532
  my $font_height       = $font_size + 2 * $padding;
533
  my $title_font_height = $font_size + 2 * $padding;
534

  
535
  my $header_height     = 2 * $title_font_height if ($opts->{title});
536
  my $footer_height     = 2 * $font_height       if ($params->{number});
537

  
538
  my $top_text_height   = 0;
539

  
540
  if ($self->{options}->{top_info_text}) {
541
    my $top_text     =  $self->{options}->{top_info_text};
542
    $top_text        =~ s/\r//g;
543
    $top_text        =~ s/\n+$//;
544

  
545
    my @lines        =  split m/\n/, $top_text;
546
    $top_text_height =  $font_height * scalar @lines;
547

  
548
    foreach my $line_no (0 .. scalar(@lines) - 1) {
549
      my $y_pos    = $paper_height - $margin_top - $header_height - $line_no * $font_height;
550
      my $text_obj = $page->text();
551

  
552
      $text_obj->font($font, $font_size);
553
      $text_obj->translate($margin_left, $y_pos);
554
      $text_obj->text($lines[$line_no]);
555
    }
556
  }
557

  
558
  $table->table($pdf,
559
                $page,
560
                \@data,
561
                'x'                     => $margin_left,
562
                'w'                     => $paper_width - $margin_left - $margin_right,
563
                'start_y'               => $paper_height - $margin_top                  - $header_height                  - $top_text_height,
564
                'next_y'                => $paper_height - $margin_top                  - $header_height,
565
                'start_h'               => $paper_height - $margin_top - $margin_bottom - $header_height - $footer_height - $top_text_height,
566
                'next_h'                => $paper_height - $margin_top - $margin_bottom - $header_height - $footer_height,
567
                'padding'               => 1,
568
                'background_color_odd'  => '#ffffff',
569
                'background_color_even' => '#eeeeee',
570
                'font'                  => $font,
571
                'font_size'             => $font_size,
572
                'font_color'            => '#000000',
573
                'header_props'          => {
574
                  'bg_color'            => '#ffffff',
575
                  'repeat'              => 1,
576
                  'font_color'          => '#000000',
577
                },
578
                'column_props'          => \@column_props,
579
                'cell_props'            => \@cell_props,
580
    );
581

  
582
  foreach my $page_num (1..$pdf->pages()) {
583
    my $curpage  = $pdf->openpage($page_num);
584

  
585
    if ($params->{number}) {
586
      my $label    = $main::locale->text("Page #1/#2", $page_num, $pdf->pages());
587
      my $text_obj = $curpage->text();
588

  
589
      $text_obj->font($font, $font_size);
590
      $text_obj->translate(($paper_width - $margin_left - $margin_right) / 2 + $margin_left - $text_obj->advancewidth($label) / 2, $margin_bottom);
591
      $text_obj->text($label);
592
    }
593

  
594
    if ($opts->{title}) {
595
      my $text_obj = $curpage->text();
596

  
597
      $text_obj->font($font, $title_font_size);
598
      $text_obj->translate(($paper_width - $margin_left - $margin_right) / 2 + $margin_left - $text_obj->advancewidth($opts->{title}) / 2,
599
                           $paper_height - $margin_top);
600
      $text_obj->text($opts->{title}, '-underline' => 1);
601
    }
602
  }
603

  
604
  my $filename = $self->get_attachment_basename();
605

  
606
  print qq|content-type: application/pdf\n|;
607
  print qq|content-disposition: attachment; filename=${filename}.pdf\n\n|;
608

  
609
  print $pdf->stringify();
610
}
611

  
403 612
sub verify_paper_size {
404 613
  my $self                 = shift;
405 614
  my $requested_paper_size = lc shift;
......
410 619
  return $allowed_paper_sizes{$requested_paper_size} ? $requested_paper_size : $default_paper_size;
411 620
}
412 621

  
413
sub generate_pdf_content {
622
sub render_pdf_with_html2ps {
414 623
  my $self      = shift;
415 624
  my $variables = $self->prepare_html_content();
416 625
  my $form      = $self->{form};
......
521 730
  }
522 731
}
523 732

  
733
sub generate_pdf_content {
734
  my $self = shift;
735

  
736
  eval { require PDF::API2; require PDF::Table; };
737

  
738
  if ($@) {
739
    return $self->render_pdf_with_html2ps(@_);
740
  } else {
741
    return $self->render_pdf_with_pdf_api2(@_);
742
  }
743
}
744

  
524 745
sub unescape_string {
525 746
  my $self = shift;
526 747
  my $text = shift;
bin/mozilla/reportgenerator.pl
41 41

  
42 42
  $form->{copies} = max $myconfig{copies} * 1, 1;
43 43

  
44
  my $allow_font_selection = 1;
45
  eval { require PDF::API2; };
46
  $allow_font_selection = 0 if ($@);
47

  
44 48
  $form->{title} = $locale->text('PDF export -- options');
45 49
  $form->header();
46
  print $form->parse_html_template('report_generator/pdf_export_options', { 'HIDDEN' => \@form_values });
50
  print $form->parse_html_template('report_generator/pdf_export_options', { 'HIDDEN'               => \@form_values,
51
                                                                            'ALLOW_FONT_SELECTION' => $allow_font_selection, });
47 52

  
48 53
  $lxdebug->leave_sub();
49 54
}
doc/modules/LICENSE.PDF-Table
1

  
2

  
3

  
4

  
5
			 The "Artistic License"
6

  
7
				Preamble
8

  
9
The intent of this document is to state the conditions under which a
10
Package may be copied, such that the Copyright Holder maintains some
11
semblance of artistic control over the development of the package,
12
while giving the users of the package the right to use and distribute
13
the Package in a more-or-less customary fashion, plus the right to make
14
reasonable modifications.
15

  
16
Definitions:
17

  
18
	"Package" refers to the collection of files distributed by the
19
	Copyright Holder, and derivatives of that collection of files
20
	created through textual modification.
21

  
22
	"Standard Version" refers to such a Package if it has not been
23
	modified, or has been modified in accordance with the wishes
24
	of the Copyright Holder as specified below.
25

  
26
	"Copyright Holder" is whoever is named in the copyright or
27
	copyrights for the package.
28

  
29
	"You" is you, if you're thinking about copying or distributing
30
	this Package.
31

  
32
	"Reasonable copying fee" is whatever you can justify on the
33
	basis of media cost, duplication charges, time of people involved,
34
	and so on.  (You will not be required to justify it to the
35
	Copyright Holder, but only to the computing community at large
36
	as a market that must bear the fee.)
37

  
38
	"Freely Available" means that no fee is charged for the item
39
	itself, though there may be fees involved in handling the item.
40
	It also means that recipients of the item may redistribute it
41
	under the same conditions they received it.
42

  
43
1. You may make and give away verbatim copies of the source form of the
44
Standard Version of this Package without restriction, provided that you
45
duplicate all of the original copyright notices and associated disclaimers.
46

  
47
2. You may apply bug fixes, portability fixes and other modifications
48
derived from the Public Domain or from the Copyright Holder.  A Package
49
modified in such a way shall still be considered the Standard Version.
50

  
51
3. You may otherwise modify your copy of this Package in any way, provided
52
that you insert a prominent notice in each changed file stating how and
53
when you changed that file, and provided that you do at least ONE of the
54
following:
55

  
56
    a) place your modifications in the Public Domain or otherwise make them
57
    Freely Available, such as by posting said modifications to Usenet or
58
    an equivalent medium, or placing the modifications on a major archive
59
    site such as uunet.uu.net, or by allowing the Copyright Holder to include
60
    your modifications in the Standard Version of the Package.
61

  
62
    b) use the modified Package only within your corporation or organization.
63

  
64
    c) rename any non-standard executables so the names do not conflict
65
    with standard executables, which must also be provided, and provide
66
    a separate manual page for each non-standard executable that clearly
67
    documents how it differs from the Standard Version.
68

  
69
    d) make other distribution arrangements with the Copyright Holder.
70

  
71
4. You may distribute the programs of this Package in object code or
72
executable form, provided that you do at least ONE of the following:
73

  
74
    a) distribute a Standard Version of the executables and library files,
75
    together with instructions (in the manual page or equivalent) on where
76
    to get the Standard Version.
77

  
78
    b) accompany the distribution with the machine-readable source of
79
    the Package with your modifications.
80

  
81
    c) give non-standard executables non-standard names, and clearly
82
    document the differences in manual pages (or equivalent), together
83
    with instructions on where to get the Standard Version.
84

  
85
    d) make other distribution arrangements with the Copyright Holder.
86

  
87
5. You may charge a reasonable copying fee for any distribution of this
88
Package.  You may charge any fee you choose for support of this
89
Package.  You may not charge a fee for this Package itself.  However,
90
you may distribute this Package in aggregate with other (possibly
91
commercial) programs as part of a larger (possibly commercial) software
92
distribution provided that you do not advertise this Package as a
93
product of your own.  You may embed this Package's interpreter within
94
an executable of yours (by linking); this shall be construed as a mere
95
form of aggregation, provided that the complete Standard Version of the
96
interpreter is so embedded.
97

  
98
6. The scripts and library files supplied as input to or produced as
99
output from the programs of this Package do not automatically fall
100
under the copyright of this Package, but belong to whoever generated
101
them, and may be sold commercially, and may be aggregated with this
102
Package.  If such scripts or library files are aggregated with this
103
Package via the so-called "undump" or "unexec" methods of producing a
104
binary executable image, then distribution of such an image shall
105
neither be construed as a distribution of this Package nor shall it
106
fall under the restrictions of Paragraphs 3 and 4, provided that you do
107
not represent such an executable image as a Standard Version of this
108
Package.
109

  
110
7. C subroutines (or comparably compiled subroutines in other
111
languages) supplied by you and linked into this Package in order to
112
emulate subroutines and variables of the language defined by this
113
Package shall not be considered part of this Package, but are the
114
equivalent of input as in Paragraph 6, provided these subroutines do
115
not change the language in any way that would cause it to fail the
116
regression tests for the language.
117

  
118
8. Aggregation of this Package with a commercial distribution is always
119
permitted provided that the use of this Package is embedded; that is,
120
when no overt attempt is made to make this Package's interfaces visible
121
to the end user of the commercial distribution.  Such use shall not be
122
construed as a distribution of this Package.
123

  
124
9. The name of the Copyright Holder may not be used to endorse or promote
125
products derived from this software without specific prior written permission.
126

  
127
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
128
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
129
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
130

  
131
				The End
doc/modules/README.PDF-Table
1
PDF-Table version 0.9.3
2
=====================
3
SOME NOTES
4

  
5
This module is intended for table generation using PDF::API2
6
The current version is RC1 and I will apreciate any feedback.
7
Developed and tested on i586 Linux SuSE 10.0 and perl, v5.8.7 built for i586-linux-thread-multi
8

  
9
CHANGES
10

  
11
Since version 0.02 there are many changes. 
12
See the ChangeLog file or make a diff from the tools menu in CPAN
13

  
14
CONTACTS 
15

  
16
See http://search.cpan.org/~omega/
17

  
18
INSTALLATION
19

  
20
To install this module type the following:
21

  
22
   perl Makefile.PL
23
   make
24
   make test
25
   make install
26

  
27
DEPENDENCIES
28

  
29
This module requires these other modules and libraries:
30

  
31
  PDF::API2
32

  
33
COPYRIGHT AND LICENCE
34

  
35
Put the correct copyright and licence information here.
36

  
37
Copyright (C) 2006 by Daemmon Hughes
38

  
39
Extended by Desislav Kamenov since version 0.02
40

  
41
This library is free software; you can redistribute it and/or modify
42
it under the same terms as Perl itself, either Perl version 5.8.7 or,
43
at your option, any later version of Perl 5 you may have available.
44

  
45

  
locale/de/all
641 641
  'Follow-Up saved.'            => 'Wiedervorlage gespeichert.',
642 642
  'Follow-Ups'                  => 'Wiedervorlagen',
643 643
  'Follow-up for'               => 'Wiedervorlage f?r',
644
  'Font'                        => 'Schriftart',
644 645
  'Font size'                   => 'Schriftgr&ouml;&szlig;e',
645 646
  'For each unit there\'s either no or exactly one base unit. If you chose a base unit then you also have to chose a factor. That way the new unit will be defined as a multiple of the base unit. The base unit must be the &quot;smaller&quot; one. A factor may not be less than 1. Therefore you may define &quot;kg&quot; with the base unit &quot;g&quot; and a factor of &quot;1&quot;, but not the other way round.' => 'Einheiten haben entweder keine oder genau eine Basiseinheit, von der sie ein Vielfaches sind. Wenn Sie eine Basiseinheit ausw&auml;hlen, dann m&uuml;ssen Sie auch einen Faktor eingeben. Sie m&uuml;ssen Einheiten als ein Vielfaches einer kleineren Einheit eingeben. So ist die Definition von &quot;kg&quot; mit der Basiseinheit &quot;g&quot; und dem Faktor 1000 zul&auml;ssig, die Definition von &quot;g&quot; mit der Basiseinheit &quot;kg&quot; und dem Faktor &quot;0,001&quot; hingegen nicht.',
646 647
  'Foreign Exchange Gain'       => 'Wechselkursertr?ge',
......
997 998
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
998 999
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
999 1000
  'Packing Lists'               => 'Lieferschein',
1001
  'Page #1/#2'                  => 'Seite #1/#2',
1000 1002
  'Paid'                        => 'bezahlt',
1001 1003
  'Part'                        => 'Ware',
1002 1004
  'Part Description'            => 'Artikelbeschreibung',
locale/de/ap
157 157
  'POSTED AS NEW'               => 'Als neu gebucht',
158 158
  'PRINTED'                     => 'Gedruckt',
159 159
  'Packing List'                => 'Lieferschein',
160
  'Page #1/#2'                  => 'Seite #1/#2',
160 161
  'Paid'                        => 'bezahlt',
161 162
  'Part Number'                 => 'Artikelnummer',
162 163
  'Part description'            => 'Artikelbeschreibung',
locale/de/ar
163 163
  'POSTED AS NEW'               => 'Als neu gebucht',
164 164
  'PRINTED'                     => 'Gedruckt',
165 165
  'Packing List'                => 'Lieferschein',
166
  'Page #1/#2'                  => 'Seite #1/#2',
166 167
  'Paid'                        => 'bezahlt',
167 168
  'Part Number'                 => 'Artikelnummer',
168 169
  'Part description'            => 'Artikelbeschreibung',
locale/de/ca
93 93
  'POSTED AS NEW'               => 'Als neu gebucht',
94 94
  'PRINTED'                     => 'Gedruckt',
95 95
  'Packing List'                => 'Lieferschein',
96
  'Page #1/#2'                  => 'Seite #1/#2',
96 97
  'Pick List'                   => 'Sammelliste',
97 98
  'Proforma Invoice'            => 'Proformarechnung',
98 99
  'Project Number'              => 'Projektnummer',
locale/de/ct
100 100
  'POSTED AS NEW'               => 'Als neu gebucht',
101 101
  'PRINTED'                     => 'Gedruckt',
102 102
  'Packing List'                => 'Lieferschein',
103
  'Page #1/#2'                  => 'Seite #1/#2',
103 104
  'Part Number'                 => 'Artikelnummer',
104 105
  'Part description'            => 'Artikelbeschreibung',
105 106
  'Phone'                       => 'Telefon',
locale/de/dn
164 164
  'Packing List'                => 'Lieferschein',
165 165
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
166 166
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
167
  'Page #1/#2'                  => 'Seite #1/#2',
167 168
  'Part Description'            => 'Artikelbeschreibung',
168 169
  'Part Number'                 => 'Artikelnummer',
169 170
  'Part description'            => 'Artikelbeschreibung',
locale/de/do
174 174
  'Packing List'                => 'Lieferschein',
175 175
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
176 176
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
177
  'Page #1/#2'                  => 'Seite #1/#2',
177 178
  'Part Description'            => 'Artikelbeschreibung',
178 179
  'Part Number'                 => 'Artikelnummer',
179 180
  'Part description'            => 'Artikelbeschreibung',
locale/de/fu
86 86
  'POSTED AS NEW'               => 'Als neu gebucht',
87 87
  'PRINTED'                     => 'Gedruckt',
88 88
  'Packing List'                => 'Lieferschein',
89
  'Page #1/#2'                  => 'Seite #1/#2',
89 90
  'Pick List'                   => 'Sammelliste',
90 91
  'Proforma Invoice'            => 'Proformarechnung',
91 92
  'Purchase Order'              => 'Lieferantenauftrag',
locale/de/gl
154 154
  'POSTED AS NEW'               => 'Als neu gebucht',
155 155
  'PRINTED'                     => 'Gedruckt',
156 156
  'Packing List'                => 'Lieferschein',
157
  'Page #1/#2'                  => 'Seite #1/#2',
157 158
  'Part Number'                 => 'Artikelnummer',
158 159
  'Part description'            => 'Artikelbeschreibung',
159 160
  'Pick List'                   => 'Sammelliste',
locale/de/ic
187 187
  'Packing List'                => 'Lieferschein',
188 188
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
189 189
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
190
  'Page #1/#2'                  => 'Seite #1/#2',
190 191
  'Part Description'            => 'Artikelbeschreibung',
191 192
  'Part Description missing!'   => 'Artikelbezeichnung fehlt!',
192 193
  'Part Number'                 => 'Artikelnummer',
locale/de/login
226 226
  'Packing List'                => 'Lieferschein',
227 227
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
228 228
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
229
  'Page #1/#2'                  => 'Seite #1/#2',
229 230
  'Part Description'            => 'Artikelbeschreibung',
230 231
  'Part Number'                 => 'Artikelnummer',
231 232
  'Part description'            => 'Artikelbeschreibung',
locale/de/oe
204 204
  'Packing List'                => 'Lieferschein',
205 205
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
206 206
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
207
  'Page #1/#2'                  => 'Seite #1/#2',
207 208
  'Part Description'            => 'Artikelbeschreibung',
208 209
  'Part Number'                 => 'Artikelnummer',
209 210
  'Part description'            => 'Artikelbeschreibung',
locale/de/projects
86 86
  'POSTED AS NEW'               => 'Als neu gebucht',
87 87
  'PRINTED'                     => 'Gedruckt',
88 88
  'Packing List'                => 'Lieferschein',
89
  'Page #1/#2'                  => 'Seite #1/#2',
89 90
  'Part Number'                 => 'Artikelnummer',
90 91
  'Part description'            => 'Artikelbeschreibung',
91 92
  'Pick List'                   => 'Sammelliste',
locale/de/reportgenerator
61 61
  'POSTED AS NEW'               => 'Als neu gebucht',
62 62
  'PRINTED'                     => 'Gedruckt',
63 63
  'Packing List'                => 'Lieferschein',
64
  'Page #1/#2'                  => 'Seite #1/#2',
64 65
  'Pick List'                   => 'Sammelliste',
65 66
  'Proforma Invoice'            => 'Proformarechnung',
66 67
  'Purchase Order'              => 'Lieferantenauftrag',
locale/de/rp
149 149
  'POSTED AS NEW'               => 'Als neu gebucht',
150 150
  'PRINTED'                     => 'Gedruckt',
151 151
  'Packing List'                => 'Lieferschein',
152
  'Page #1/#2'                  => 'Seite #1/#2',
152 153
  'Part Number'                 => 'Artikelnummer',
153 154
  'Part description'            => 'Artikelbeschreibung',
154 155
  'Payments'                    => 'Zahlungsausg?nge',
locale/de/todo
223 223
  'Packing List'                => 'Lieferschein',
224 224
  'Packing List Date missing!'  => 'Datum f?r Verpackungsliste fehlt!',
225 225
  'Packing List Number missing!' => 'Verpackungslistennummer fehlt!',
226
  'Page #1/#2'                  => 'Seite #1/#2',
226 227
  'Part Description'            => 'Artikelbeschreibung',
227 228
  'Part Number'                 => 'Artikelnummer',
228 229
  'Part description'            => 'Artikelbeschreibung',
locale/de/wh
94 94
  'POSTED AS NEW'               => 'Als neu gebucht',
95 95
  'PRINTED'                     => 'Gedruckt',
96 96
  'Packing List'                => 'Lieferschein',
97
  'Page #1/#2'                  => 'Seite #1/#2',
97 98
  'Part Number'                 => 'Artikelnummer',
98 99
  'Part description'            => 'Artikelbeschreibung',
99 100
  'Pick List'                   => 'Sammelliste',
modules/override/PDF/Table.pm
1
package PDF::Table;
2

  
3
use 5.006;
4
use strict;
5
use warnings;
6
our $VERSION = '0.9.3';
7

  
8

  
9
############################################################
10
#
11
# new - Constructor
12
#
13
# Parameters are meta information about the PDF
14
#
15
# $pdf = PDF::Table->new();
16
#
17
############################################################
18

  
19
sub new
20
{
21
	my ($type) = @_;
22

  
23
	my $class = ref($type) || $type;
24
	my $self  = {};
25
	bless ($self, $class);
26
	return $self;
27
}
28

  
29
############################################################
30
#
31
# text_block - utility method to build multi-paragraph blocks of text
32
#
33
############################################################
34

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

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

  
47
	# Try to provide backward compatibility
48
	foreach my $key (keys %arg)
49
	{
50
		my $newkey = $key;
51
		if($newkey =~ s#^-##)
52
		{
53
			$arg{$newkey} = $arg{$key};
54
			delete $arg{$key};
55
		}
56
	}
57
	#####
58

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

  
77
    # Strip any <CR> and Split the text into paragraphs
78
	$text =~ s/\r//g;
79
    my @paragraphs 	= split(/\n/, $text);
80

  
81
	# Width between lines in pixels
82
	my $line_space = defined $arg{'lead'} && $arg{'lead'} > 0 ? $arg{'lead'} : 12;
83

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

  
93
    my @paragraph = split(' ', shift(@paragraphs));
94
    my $first_line = 1;
95
    my $first_paragraph = 1;
96

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

  
113
	    	$ypos -= $arg{'parspace'} if $arg{'parspace'};
114
	    	last unless $ypos >= $bottom_border;
115
		}
116
		$ypos -= $line_space;
117
		$xpos = $xbase;
118

  
119
		# While there's room on the line, add another word
120
		@line = ();
121
		$line_width = 0;
122
		if( $first_line && exists $arg{'hang'} ) 
123
		{
124
		    my $hang_width = $text_object->advancewidth($arg{'hang'});
125
	
126
		    $text_object->translate( $xpos, $ypos );
127
		    $text_object->text( $arg{'hang'} );
128
	
129
		    $xpos         += $hang_width;
130
		    $line_width   += $hang_width;
131
		    $arg{'indent'} += $hang_width if $first_paragraph;
132
		}
133
		elsif( $first_line && exists $arg{'flindent'} && $arg{'flindent'} > 0 ) 
134
		{
135
		    $xpos += $arg{'flindent'};
136
		    $line_width += $arg{'flindent'};
137
		}
138
		elsif( $first_paragraph && exists $arg{'fpindent'} && $arg{'fpindent'} > 0 ) 
139
		{
140
		    $xpos += $arg{'fpindent'};
141
		    $line_width += $arg{'fpindent'};
142
		}
143
		elsif (exists $arg{'indent'} && $arg{'indent'} > 0 ) 
144
		{
145
		    $xpos += $arg{'indent'};
146
		    $line_width += $arg{'indent'};
147
		}
148
	
149
		# Lets take from paragraph as many words as we can put into $width - $indent; 
150
		while ( @paragraph and $text_object->advancewidth( join("\x20", @line)."\x20" . $paragraph[0]) + 
151
								$line_width < $width ) 
152
		{
153
		    push(@line, shift(@paragraph));
154
		}
155
		$line_width += $text_object->advancewidth(join('', @line));
156
			
157
		# calculate the space width
158
		if( $arg{'align'} eq 'fulljustify' or ($arg{'align'} eq 'justify' and @paragraph)) 
159
		{
160
		    @line = split(//,$line[0]) if (scalar(@line) == 1) ;
161
		    $wordspace = ($width - $line_width) / (scalar(@line) - 1);
162
		    $align='justify';
163
		} 
164
		else 
165
		{
166
		    $align=($arg{'align'} eq 'justify') ? 'left' : $arg{'align'};
167
		    $wordspace = $space_width;
168
		}
169
		$line_width += $wordspace * (scalar(@line) - 1);
170
	
171
		if( $align eq 'justify') 
172
		{
173
		    foreach my $word (@line) 
174
			{
175
				$text_object->translate( $xpos, $ypos );
176
				$text_object->text( $word );
177
				$xpos += ($width{$word} + $wordspace) if (@line);
178
		    }
179
		    $endw = $width;
180
		} 
181
		else 
182
		{
183
		    # calculate the left hand position of the line
184
		    if( $align eq 'right' ) 
185
			{
186
				$xpos += $width - $line_width;
187
		    } 
188
			elsif( $align eq 'center' ) 
189
			{
190
				$xpos += ( $width / 2 ) - ( $line_width / 2 );
191
		    }
192
	
193
		    # render the line
194
		    $text_object->translate( $xpos, $ypos );
195
		    $endw = $text_object->text( join("\x20", @line));
196
		}
197
		$first_line = 0;
198
    }#End of while(
199
    unshift(@paragraphs, join(' ',@paragraph)) if scalar(@paragraph);
200
    return ($endw, $ypos, join("\n", @paragraphs))
201
}
202

  
203

  
204
############################################################
205
# table - utility method to build multi-row, multicolumn tables
206
############################################################
207
sub table
208
	{
209
	my $self	= shift;
210
	my $pdf 	= shift;
211
	my $page 	= shift;
212
	my $data 	= shift;
213
	my %arg 	= @_;
214

  
215
	#=====================================
216
	# Mandatory Arguments Section
217
	#=====================================
218
	unless($pdf and $page and $data)
219
	{
220
		print "Error: Mandatory parameter is missing pdf/page/data object!\n";
221
		return;
222
	}
223
	# Try to provide backward compatibility
224
	foreach my $key (keys %arg)
225
	{
226
		my $newkey = $key;
227
		if($newkey =~ s#^-##)
228
		{
229
			$arg{$newkey} = $arg{$key};
230
			delete $arg{$key};
231
		}
232
	}
233
	#TODO: Add code for header props compatibility and col_props comp....
234
	#####
235
	my ( $xbase, $ybase, $width, $height ) = ( undef, undef, undef, undef );
236
	# Could be 'int' or 'real' values
237
	$xbase 	= $arg{'x'		} || -1;	
238
	$ybase 	= $arg{'start_y'} || -1;
239
	$width 	= $arg{'w'		} || -1;
240
	$height	= $arg{'start_h'} || -1;
241

  
242
	# Global geometry parameters are also mandatory. 
243
	unless( $xbase	> 0 ){ print "Error: Left Edge of Table is NOT defined!\n";	return; }
244
	unless( $ybase	> 0 ){ print "Error: Base Line of Table is NOT defined!\n"; return; }
245
	unless( $width	> 0 ){ print "Error: Width of Table is NOT defined!\n"; 	return; }
246
	unless( $height	> 0 ){ print "Error: Height of Table is NOT defined!\n";	return;	}
247

  
248
	# Ensure default values for -next_y and -next_h
249
	my $next_y	= $arg{'next_y'} || $arg{'start_y'} || 0;
250
	my $next_h	= $arg{'next_h'} || $arg{'start_h'} || 0;
251

  
252
	# Create Text Object
253
	my $txt 	= $page->text;
254
	# Set Default Properties
255
	my $fnt_name 	= $arg{'font'		 	 } || $pdf->corefont('Times',-encode => 'utf8');
256
	my $fnt_size 	= $arg{'font_size'	 	 } || 12;
257
	my $max_word_len= $arg{'max_word_length' } || 20;
258

  
259
	#=====================================
260
	# Table Header Section
261
	#=====================================
262
	# Disable header row into the table
263
	my $header_props = 0;
264
	# Check if the user enabled it ?
265
	if(defined $arg{'header_props'} and ref( $arg{'header_props'}) eq 'HASH')
266
	{
267
		# Transfer the reference to local variable
268
		$header_props = $arg{'header_props'};
269
		# Check other params and put defaults if needed
270
		$header_props->{'repeat'		} = $header_props->{'repeat' 		} || 0;
271
		$header_props->{'font'			} = $header_props->{'font' 			} || $fnt_name;
272
		$header_props->{'font_color'	} = $header_props->{'font_color' 	} || '#000066';
273
		$header_props->{'font_size'		} = $header_props->{'font_size' 	} || $fnt_size + 2;
274
		$header_props->{'bg_color'		} = $header_props->{'bg_color'		} || '#FFFFAA';
275
	}
276
	my $header_row	= undef;
277
	#=====================================
278
	# Other Parameters check
279
	#=====================================
280
	
281
	my $lead 		= $arg{'lead'			} || $fnt_size;
282
	my $pad_left 	= $arg{'padding_left'	} || $arg{'padding'} || 0;
283
	my $pad_right	= $arg{'padding_right'	} || $arg{'padding'} || 0;
284
	my $pad_top 	= $arg{'padding_top'	} || $arg{'padding'} || 0;
285
	my $pad_bot 	= $arg{'padding_bottom'	} || $arg{'padding'} || 0;
286
	my $pad_w 		= $pad_left + $pad_right;
287
	my $pad_h 		= $pad_top  + $pad_bot	;
288
	my $line_w 		= defined $arg{'border'} ? $arg{'border'} : 1 ;
289
	
290
	my $background_color_even 	= $arg{'background_color_even'	} || $arg{'background_color'} || undef;
291
	my $background_color_odd 	= $arg{'background_color_odd'	} || $arg{'background_color'} || undef;
292
	my $font_color_even 		= $arg{'font_color_even'		} || $arg{'font_color'		} || 'black';
293
	my $font_color_odd 			= $arg{'font_color_odd'			} || $arg{'font_color'		} || 'black';
294
	my $border_color 			= $arg{'border_color'			} || 'black';
295

  
296
	my $min_row_h 	= $fnt_size + $pad_top + $pad_bot;
297
	my $row_h 		= defined ($arg{'row_height'}) 
298
								&& 
299
					($arg{'row_height'} > $min_row_h) 
300
								? 
301
					 $arg{'row_height'} : $min_row_h;
302

  
303
	my $pg_cnt 		= 1;
304
	my $cur_y 		= $ybase;
305
	my $cell_props	= $arg{cell_props} || [];   # per cell properties
306
	my $row_cnt		= ( ref $header_props and $header_props->{'repeat'} ) ?  1 : 0; # current row in user data
307

  
308
	#If there is valid data array reference use it!
309
	if(ref $data eq 'ARRAY')
310
	{
311
		# Copy the header row if header is enabled
312
		@$header_row = $$data[0] if defined $header_props;
313
		# Determine column widths based on content
314

  
315
		#  an arrayref whose values are a hashref holding 
316
		#  the minimum and maximum width of that column
317
		my $col_props =  $arg{'column_props'} || [];
318

  
319
		# An array ref of arrayrefs whose values are 
320
		#  the actual widths of the column/row intersection
321
		my $row_props = [];
322
		# An array ref with the widths of the header row 
323
		my $header_row_props = [];
324
 
325
		# Scalars that hold sum of the maximum and minimum widths of all columns 
326
		my ( $max_col_w  , $min_col_w   ) = ( 0,0 );
327
		my ( $row, $col_name, $col_fnt_size, $space_w );
328

  
329
		# Hash that will hold the width of every word from input text
330
		my $word_w		 = {};
331
		my $rows_counter = 0;
332
		my $first_row	 = 1;
333

  
334
		foreach $row ( @{$data} )
335
		{
336
			my $column_widths = []; #holds the width of each column
337
			for( my $j = 0; $j < scalar(@$row) ; $j++ )
338
			{
339
				# look for font information for this column
340
				$col_fnt_size 	=  $col_props->[$j]->{'font_size'} || $fnt_size;
341
				if( !$rows_counter and ref $header_props)
342
				{	
343
					$txt->font(  $header_props->{'font'}, $header_props->{'font_size'} ); 
344
				}
345
				elsif( $col_props->[$j]->{'font'} ) 
346
				{	
347
					$txt->font( $col_props->[$j]->{'font'}, $col_fnt_size ); 
348
				}
349
				else
350
				{	
351
					$txt->font( $fnt_name, $col_fnt_size ); 
352
				}
353

  
354
				# This should fix a bug with very long word like serial numbers etc.
355
				# $myone is used because $1 gets out of scope in while condition
356
				my $myone;
357
				do{
358
			    	$myone = 0;
359
					# This RegEx will split any word that is longer than {25} symbols
360
					$row->[$j] =~ s#(\b\S{$max_word_len}?)(\S.*?\b)# $1 $2#;
361
					$myone = 1 if( defined $2 );
362
				}while( $myone );
363

  
364
				$space_w 				= $txt->advancewidth( "\x20" );
365
				$column_widths->[$j] 	= 0;
366
				$max_col_w 				= 0;
367
				$min_col_w 				= 0;
368

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

  
371
				foreach( @words ) 
372
				{
373
					unless( exists $word_w->{$_} )
374
					{	# Calculate the width of every word and add the space width to it
375
						$word_w->{$_} = $txt->advancewidth( $_ ) + $space_w;
376
					}
377
					$column_widths->[$j] 	+= $word_w->{$_};
378
					$min_col_w				 = $word_w->{$_} if $word_w->{$_} > $min_col_w;
379
					$max_col_w 				+= $word_w->{$_};
380
				}
381
				$min_col_w 					+= $pad_w;
382
				$max_col_w 					+= $pad_w;
383
				$column_widths->[$j] 		+= $pad_w;
384

  
385
				# Keep a running total of the overall min and max widths
386
				$col_props->[$j]->{min_w} = $col_props->[$j]->{min_w} || 0;
387
				$col_props->[$j]->{max_w} = $col_props->[$j]->{max_w} || 0;
388

  
389
				if( $min_col_w > $col_props->[$j]->{min_w} )
390
				{	# Calculated Minimum Column Width is more than user-defined
391
					$col_props->[$j]->{min_w} 	 = $min_col_w ;
392
				}
393
				if( $max_col_w > $col_props->[$j]->{max_w} )
394
				{	# Calculated Maximum Column Width is more than user-defined
395
					$col_props->[$j]->{max_w} 	 = $max_col_w ;
396
				}
397
			}#End of for(my $j....
398
			$row_props->[$rows_counter] = $column_widths;
399
			# Copy the calculated row properties of header row. 
400
			@$header_row_props = @$column_widths if(!$rows_counter and ref $header_props);
401
			$rows_counter++;
402
		}
403
		# Calc real column widths and expand table width if needed.
404
		my $calc_column_widths; 
405
		($calc_column_widths, $width) = $self->CalcColumnWidths( $col_props, $width );
406

  
407
		my $comp_cnt 	 = 1;
408
		$rows_counter	 = 0;
409

  
410
		my ( $gfx	  , $gfx_bg		, $background_color	, $font_color,				);
411
		my ( $bot_marg, $table_top_y, $text_start		, $record,	$record_widths	);
412

  
413
		# Each iteration adds a new page as neccessary
414
		while(scalar(@{$data}))
415
		{
416
			my $page_header;
417
			if($pg_cnt == 1)
418
			{
419
				$table_top_y = $ybase;
420
				$bot_marg = $table_top_y - $height;
421
			}
422
			else
423
			{
424
				if(ref $arg{'new_page_func'})
425
				{	
426
					$page = &{$arg{'new_page_func'}};	
427
				}
428
				else
429
				{	
430
					$page = $pdf->page;	
431
				}
432

  
433
				$table_top_y = $next_y;
434
				$bot_marg = $table_top_y - $next_h;
435

  
436
				if( ref $header_props and $header_props->{'repeat'})
437
				{
438
					# Copy Header Data
439
					@$page_header = @$header_row;
440
					my $hrp ;
441
					@$hrp = @$header_row_props ;
442
					# Then prepend it to master data array
443
					unshift @$data		,@$page_header	;
444
					unshift @$row_props	,$hrp			;
445
					$first_row = 1; # Means YES
446
				}
447
			}
448

  
449
			# Check for safety reasons
450
			if( $bot_marg < 0 )
451
			{	# This warning should remain i think
452
				print "!!! Warning: !!! Incorrect Table Geometry! Setting bottom margin to end of sheet!\n";
453
				$bot_marg = 0;
454
			}
455

  
456
			$gfx_bg = $page->gfx;
457
			$txt = $page->text;
458
			$txt->font($fnt_name, $fnt_size); 
459
			$gfx = $page->gfx;
460
			$gfx->strokecolor($border_color);
461
			$gfx->linewidth($line_w);
462

  
463
			# Draw the top line
464
			$cur_y = $table_top_y;
465
			$gfx->move( $xbase , $cur_y );
466
			$gfx->hline($xbase + $width );
467

  
468
			# Each iteration adds a row to the current page until the page is full 
469
			#  or there are no more rows to add
470
			while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
471
			{
472
				# Remove the next item from $data
473
				$record = shift @{$data};
474
				# Added to resolve infite loop bug with returned undef values
475
				for(my $d = 0; $d < scalar(@{$record}) ; $d++)
476
				{ 
477
					$record->[$d] = '-' unless( defined $record->[$d]);	
478
				}
479

  
480
				$record_widths = shift @$row_props;
481
				next unless $record;
482

  
483
				# Choose colors for this row
484
				$background_color = $rows_counter % 2 ? $background_color_even	: $background_color_odd;
485
				$font_color 	  = $rows_counter % 2 ? $font_color_even		: $font_color_odd;
486

  
487
				if($first_row and ref $header_props)
488
				{
489
					$background_color = $header_props->{'bg_color'}
490
				}
491
				$text_start		 = $cur_y - $fnt_size - $pad_top;
492
				my $cur_x		 = $xbase;
493
				my $leftovers 	 = undef;	# Reference to text that is returned from textblock()
494
				my $do_leftovers = 0;
495

  
496
				# Process every column from current row
497
				for( my $j = 0; $j < scalar( @$record); $j++ ) 
498
				{
499
					next unless $col_props->[$j]->{max_w};
500
					next unless $col_props->[$j]->{min_w};	
501
					$leftovers->[$j] = undef;
502

  
503
					# Choose font color
504
					if( $first_row and ref $header_props )
505
                    {   
506
						$txt->fillcolor( $header_props->{'font_color'} ); 
507
					}	
508
					elsif( $cell_props->[$row_cnt][$j]{font_color} )
509
					{
510
						$txt->fillcolor( $cell_props->[$row_cnt][$j]{font_color} );
511
					}
512
					elsif( $col_props->[$j]->{'font_color'} )
513
					{ 
514
						$txt->fillcolor( $col_props->[$j]->{'font_color'} ); 
515
					}
516
					else
517
					{ 
518
						$txt->fillcolor($font_color);	
519
					}
520

  
521
					# Choose font size
522
					if( $first_row and ref $header_props )
523
					{	
524
						$col_fnt_size = $header_props->{'font_size'}; 
525
					}
526
					elsif( $col_props->[$j]->{'font_size'} )
527
					{	
528
						$col_fnt_size = $col_props->[$j]->{'font_size'}; 
529
					}
530
					else
531
					{	
532
						$col_fnt_size = $fnt_size; 
533
					}
534

  
535
					# Choose font family
536
					if( $first_row and ref $header_props )
537
					{	
538
						$txt->font( $header_props->{'font'}, $header_props->{'font_size'}); 
539
					}
540
					elsif( $col_props->[$j]->{'font'} )
541
					{	
542
						$txt->font( $col_props->[$j]->{'font'}, $col_fnt_size);	
543
					}
544
					else
545
					{
546
						$txt->font( $fnt_name, $col_fnt_size); 
547
					}
548
					#TODO: Implement Center text align
549
					$col_props->[$j]->{justify} = $col_props->[$j]->{justify} || 'left';
550
					# If the content is wider than the specified width, we need to add the text as a text block
551
					if($record->[$j] !~ m#(.\n.)# and  $record_widths->[$j] and ($record_widths->[$j] < $calc_column_widths->[$j]))
552
					{
553
						my $space = $pad_left;
554
						if($col_props->[$j]->{justify} eq 'right')
555
						{
556
							$space = $calc_column_widths->[$j] -($txt->advancewidth($record->[$j]) + $pad_right);
557
						}
558
						$txt->translate( $cur_x + $space, $text_start );
559
						$txt->text( $record->[$j] );
560
					}
561
					# Otherwise just use the $page->text() method
562
					else
563
					{
564
						my($width_of_last_line, $ypos_of_last_line, $left_over_text) = $self->text_block(
565
						   	$txt,
566
						    $record->[$j],
567
						    x        => $cur_x + $pad_left,
568
						    y        => $text_start,
569
						    w        => $calc_column_widths->[$j] - $pad_w,
570
							h		 => $cur_y - $bot_marg - $pad_top - $pad_bot,
571
							align    => $col_props->[$j]->{justify},
572
							lead	 => $lead
573
						);
574
						# Desi - Removed $lead because of fixed incorrect ypos bug in text_block
575
						my $this_row_h = $cur_y - ( $ypos_of_last_line - $pad_bot );
576
						$row_h = $this_row_h if $this_row_h > $row_h;
577
						if( $left_over_text )
578
						{
579
							$leftovers->[$j] = $left_over_text;
580
							$do_leftovers 	 = 1;
581
						}
582
					}
583
					$cur_x += $calc_column_widths->[$j];
584
				}
585
				if( $do_leftovers )
586
				{
587
					unshift @$data, $leftovers;
588
					unshift @$row_props, $record_widths;
589
					$rows_counter--;
590
				}
591
				# Draw cell bgcolor
592
				# This has to be separately from the text loop 
593
				#  because we do not know the final height of the cell until all text has been drawn
594
				$cur_x = $xbase;
595
				for(my $j =0;$j < scalar(@$record);$j++)
596
				{
597
					if ( 	$cell_props->[$row_cnt][$j]->{'background_color'} || 
598
							$col_props->[$j]->{'background_color'} || 
599
							$background_color ) 
600
					{
601
						$gfx_bg->rect( $cur_x, $cur_y-$row_h, $calc_column_widths->[$j], $row_h);
602
						if ( $cell_props->[$row_cnt][$j]->{'background_color'} && !$first_row )
603
						{
604
						    $gfx_bg->fillcolor($cell_props->[$row_cnt][$j]->{'background_color'});
605
						}
606
						elsif( $col_props->[$j]->{'background_color'} && !$first_row  )
607
						{
608
						    $gfx_bg->fillcolor($col_props->[$j]->{'background_color'});
609
						}
610
						else
611
						{
612
						    $gfx_bg->fillcolor($background_color);
613
						}
614
						$gfx_bg->fill();
615
					}
616
					$cur_x += $calc_column_widths->[$j];
617
				}#End of for(my $j....
618

  
619
				$cur_y -= $row_h;
620
				$row_h  = $min_row_h;
621
				$gfx->move(  $xbase , $cur_y );
622
				$gfx->hline( $xbase + $width );
623
				$rows_counter++;
624
				$row_cnt++ unless ( $first_row );
625
				$first_row = 0;
626
			}# End of while(scalar(@{$data}) and $cur_y-$row_h > $bot_marg)
627

  
628
			# Draw vertical lines
629
			$gfx->move(  $xbase, $table_top_y);
630
			$gfx->vline( $cur_y );
631
			my $cur_x = $xbase;
632
			for( my $j = 0; $j < scalar(@$record); $j++ )
633
			{
634
				$cur_x += $calc_column_widths->[$j];
635
				$gfx->move(  $cur_x, $table_top_y );
636
				$gfx->vline( $cur_y );
637

  
638
			}
639
			# ACTUALLY draw all the lines
640
			$gfx->fillcolor( $border_color);
641
			$gfx->stroke if $line_w;
642
			$pg_cnt++;
643
		}# End of while(scalar(@{$data}))
644
	}# End of if(ref $data eq 'ARRAY')
645

  
646
	return ($page,--$pg_cnt,$cur_y);
647
}
648

  
649

  
650
# calculate the column widths
651
sub CalcColumnWidths
652
{
653
	my $self 		= shift;
654
	my $col_props 	= shift;
655
	my $avail_width = shift;
656
	my $min_width 	= 0;
657

  
658
	my $calc_widths	;
659

  
660
	for(my $j = 0; $j < scalar( @$col_props); $j++)
661
	{
662
		$min_width += $col_props->[$j]->{min_w};
663
	}
664

  
665
	# I think this is the optimal variant when good view can be guaranateed
666
	if($avail_width < $min_width)
667
	{
668
# 		print "!!! Warning !!!\n Calculated Mininal width($min_width) > Table width($avail_width).\n",
669
# 			' Expanding table width to:',int($min_width)+1,' but this could lead to unexpected results.',"\n",
670
# 			' Possible solutions:',"\n",
671
# 			'  0)Increase table width.',"\n",
672
# 			'  1)Decrease font size.',"\n",
673
# 			'  2)Choose a more narrow font.',"\n",
674
# 			'  3)Decrease "max_word_length" parameter.',"\n",
675
# 			'  4)Rotate page to landscape(if it is portrait).',"\n",
676
# 			'  5)Use larger paper size.',"\n",
677
# 			'!!! --------- !!!',"\n";
678
		$avail_width = int( $min_width) + 1;
679

  
680
	}
681

  
682
	my $span = 0;
683
	# Calculate how much can be added to every column to fit the available width
684
	$span = ($avail_width - $min_width) / scalar( @$col_props);
685
	for(my $j = 0; $j < scalar(@$col_props); $j++ )
686
	{
687
		$calc_widths->[$j] = $col_props->[$j]->{min_w} + $span;
688
	}
689

  
690
	return ($calc_widths,$avail_width);
691
}
692
1;
693

  
694
__END__
695

  
696
=pod
697

  
698
=head1 NAME
699

  
700
PDF::Table - A utility class for building table layouts in a PDF::API2 object.
701

  
702
=head1 SYNOPSIS
703

  
704
 use PDF::API2;
705
 use PDF::Table;
706

  
707
 my $pdftable = new PDF::Table;
708
 my $pdf = new PDF::API2(-file => "table_of_lorem.pdf");
709
 my $page = $pdf->page;
710

  
711
 # some data to layout
712
 my $some_data =[
713
    ["1 Lorem ipsum dolor",
714
    "Donec odio neque, faucibus vel",
715
    "consequat quis, tincidunt vel, felis."],
716
    ["Nulla euismod sem eget neque.",
717
    "Donec odio neque",
718
    "Sed eu velit."],
719
    #... and so on
720
 ];
721

  
722
 $left_edge_of_table = 50;
723
 # build the table layout
724
 $pdftable->table(
725
     # required params
726
     $pdf,
727
     $page,
728
     $some_data,
729
     x => $left_edge_of_table,
730
     w => 495,
731
     start_y => 750,
732
     next_y  => 700,
733
     start_h => 300,
734
     next_h  => 500,
735
     # some optional params
736
     padding => 5,
737
     padding_right => 10,
738
     background_color_odd  => "gray",
739
     background_color_even => "lightblue", #cell background color for even rows
740
  );
741

  
742
 # do other stuff with $pdf
743
 $pdf->saveas();
744
...
745

  
746
=head1 EXAMPLE
747

  
748
For a complete working example or initial script look into distribution`s 'examples' folder.
749

  
750

  
751
=head1 DESCRIPTION
752

  
753
This class is a utility for use with the PDF::API2 module from CPAN. 
754
It can be used to display text data in a table layout within the PDF. 
755
The text data must be in a 2d array (such as returned by a DBI statement handle fetchall_arrayref() call). 
756
The PDF::Table will automatically add as many new pages as necessary to display all of the data. 
757
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. 
758
Also a (non)repeated header row with different layout properties can be specified. 
759

  
760
See the METHODS section for complete documentation of every parameter.
761

  
762
=head1  METHODS
763

  
764
=head2 new
765

  
766
=over
767

  
768
Returns an instance of the class. There are no parameters.
769

  
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff