Die Funktionen in Template.pm zum Ersetzen von Schleifenvariablen so erweitert, dass...
[kivitendo-erp.git] / SL / Template.pm
index f6afe69..4cbde74 100644 (file)
@@ -39,14 +39,16 @@ sub _init {
 }
 
 sub set_tag_style {
-  my $self              = shift;
-  my $tag_start         = shift;
-  my $tag_end           = shift;
-
-  $self->{tag_start}    = $tag_start;
-  $self->{tag_end}      = $tag_end;
-  $self->{tag_start_qm} = quotemeta $tag_start;
-  $self->{tag_end_qm}   = quotemeta $tag_end;
+  my $self                    = shift;
+  my $tag_start               = shift;
+  my $tag_end                 = shift;
+
+  $self->{tag_start}          = $tag_start;
+  $self->{tag_end}            = $tag_end;
+  $self->{tag_start_qm}       = quotemeta $tag_start;
+  $self->{tag_end_qm}         = quotemeta $tag_end;
+
+  $self->{substitute_vars_re} = "$self->{tag_start_qm}(.+?)$self->{tag_end_qm}";
 }
 
 sub cleanup {
@@ -77,6 +79,47 @@ sub uses_temp_file {
   return 0;
 }
 
+sub _get_loop_variable {
+  my $self      = shift;
+  my $var       = shift;
+  my $get_array = shift;
+  my @indices   = @_;
+
+  my $form      = $self->{form};
+  my $value;
+
+  if (($get_array || @indices) && (ref $form->{TEMPLATE_ARRAYS} eq 'HASH') && (ref $form->{TEMPLATE_ARRAYS}->{$var} eq 'ARRAY')) {
+    $value = $form->{TEMPLATE_ARRAYS}->{$var};
+  } else {
+    $value = $form->{$var};
+  }
+
+  for (my $i = 0; $i < scalar(@indices); $i++) {
+    last unless (ref($value) eq "ARRAY");
+    $value = $value->[$indices[$i]];
+  }
+
+  return $value;
+}
+
+sub substitute_vars {
+  my ($self, $text, @indices) = @_;
+
+  my $form = $self->{"form"};
+
+  while ($text =~ /$self->{substitute_vars_re}/) {
+    my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
+    my ($var, @options)     = split(/\s+/, $1);
+
+    my $value               = $self->_get_loop_variable($var, 0, @indices);
+    $value                  = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
+
+    substr($text, $tag_pos, $tag_len, $value);
+  }
+
+  return $text;
+}
+
 1;
 
 ####
@@ -92,45 +135,16 @@ use vars qw(@ISA);
 sub new {
   my $type = shift;
 
-  return $type->SUPER::new(@_);
+  my $self = $type->SUPER::new(@_);
+
+  return $self;
 }
 
 sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => [quotemeta("\\"),
-                 '<pagebreak>',
-                 '&', quotemeta("\n"),
-                 '"', '\$', '%', '_', '#', quotemeta('^'),
-                 '{', '}',  '<', '>', '£', "\r", '±', '\xe1',
-                 '²', '³',
-
-                 ],
-     quotemeta("\\") => '\\textbackslash ',
-     '<pagebreak>'   => '',
-     '"'             => "''",
-     '&'             => '\&',
-     '\$'            => '\$',
-     '%'             => '\%',
-     '_'             => '\_',
-     '#'             => '\#',
-     '{'             => '\{',
-     '}'             => '\}',
-     '<'             => '$<$',
-     '>'             => '$>$',
-     '£'             => '\pounds ',
-     "\r"            => "",
-     '±'             => '$\pm$',
-     '\xe1'          => '$\bullet$',
-     quotemeta('^')  => '\^\\',
-     quotemeta("\n") => '\newline ',
-     '²'             => '$^2$',
-     '³'             => '$^3$',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/LaTeX', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -148,37 +162,12 @@ sub format_string {
   return $variable;
 }
 
-sub substitute_vars {
-  my ($self, $text, @indices) = @_;
-
-  my $form = $self->{"form"};
-
-  while ($text =~ /$self->{tag_start_qm}(.+?)$self->{tag_end_qm}/) {
-    my ($tag_pos, $tag_len) = ($-[0], $+[0] - $-[0]);
-    my ($var, @options) = split(/\s+/, $1);
-    my $value = $form->{$var};
-
-    for (my $i = 0; $i < scalar(@indices); $i++) {
-      last unless (ref($value) eq "ARRAY");
-      $value = $value->[$indices[$i]];
-    }
-    $value = $self->format_string($value) unless (grep(/^NOESCAPE$/, @options));
-    substr($text, $tag_pos, $tag_len) = $value;
-  }
-
-  return $text;
-}
-
 sub parse_foreach {
   my ($self, $var, $text, $start_tag, $end_tag, @indices) = @_;
 
   my ($form, $new_contents) = ($self->{"form"}, "");
 
-  my $ary = $form->{$var};
-  for (my $i = 0; $i < scalar(@indices); $i++) {
-    last unless (ref($ary) eq "ARRAY");
-    $ary = $ary->[$indices[$i]];
-  }
+  my $ary = $self->_get_loop_variable($var, 1, @indices);
 
   my $sum = 0;
   my $current_page = 1;
@@ -211,8 +200,7 @@ sub parse_foreach {
       }
 
       # Yes we need a manual page break -- or the user has forced one
-      if ((($current_line + $lines) > $lpp) ||
-          ($form->{"description"}->[$i] =~ /<pagebreak>/)) {
+      if ((($current_line + $lines) > $lpp) || ($form->{"description"}->[$i] =~ /<pagebreak>/) || ($form->{"longdescription"}->[$i] =~ /<pagebreak>/)) {
         my $pb = $self->{"pagebreak_block"};
 
         # replace the special variables <%sumcarriedforward%>
@@ -446,6 +434,31 @@ sub _parse_config_lines {
   }
 }
 
+sub _force_mandatory_packages {
+  my $self  = shift;
+  my $lines = shift;
+
+  my (%used_packages, $document_start_line);
+
+  foreach my $i (0 .. scalar @{ $lines } - 1) {
+    if ($lines->[$i] =~ m/\\usepackage[^{]*{(.*?)}/) {
+      $used_packages{$1} = 1;
+
+    } elsif ($lines->[$i] =~ m/\\begin{document}/) {
+      $document_start_line = $i;
+      last;
+
+    }
+  }
+
+  $document_start_line = scalar @{ $lines } - 1 if (!defined $document_start_line);
+
+  if (!$used_packages{textcomp}) {
+    splice @{ $lines }, $document_start_line, 0, "\\usepackage{textcomp}\n";
+    $document_start_line++;
+  }
+}
+
 sub parse {
   my $self = $_[0];
   local *OUT = $_[1];
@@ -459,6 +472,7 @@ sub parse {
   close(IN);
 
   $self->_parse_config_lines(\@lines);
+  $self->_force_mandatory_packages(\@lines) if (ref $self eq 'LaTeXTemplate');
 
   my $contents = join("", @lines);
 
@@ -503,7 +517,7 @@ sub convert_to_postscript {
     return 0;
   }
 
-  $form->{tmpfile} =~ s/$userspath\///g;
+  $form->{tmpfile} =~ s/\Q$userspath\E\///g;
 
   for (my $run = 1; $run <= 2; $run++) {
     system("latex --interaction=nonstopmode $form->{tmpfile} " .
@@ -542,7 +556,7 @@ sub convert_to_pdf {
     return 0;
   }
 
-  $form->{tmpfile} =~ s/$userspath\///g;
+  $form->{tmpfile} =~ s/\Q$userspath\E\///g;
 
   for (my $run = 1; $run <= 2; $run++) {
     system("pdflatex --interaction=nonstopmode $form->{tmpfile} " .
@@ -594,14 +608,7 @@ sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => ['<', '>', quotemeta("\n")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     quotemeta("\n") => '<br>',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/HTML', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -650,7 +657,7 @@ sub convert_to_postscript {
     return 0;
   }
 
-  $form->{"tmpfile"} =~ s/$userspath\///g;
+  $form->{"tmpfile"} =~ s/\Q$userspath\E\///g;
   my $psfile = $form->{"tmpfile"};
   $psfile =~ s/.html/.ps/;
   if ($psfile eq $form->{"tmpfile"}) {
@@ -683,7 +690,7 @@ sub convert_to_pdf {
     return 0;
   }
 
-  $form->{"tmpfile"} =~ s/$userspath\///g;
+  $form->{"tmpfile"} =~ s/\Q$userspath\E\///g;
   my $pdffile = $form->{"tmpfile"};
   $pdffile =~ s/.html/.pdf/;
   if ($pdffile eq $form->{"tmpfile"}) {
@@ -769,28 +776,12 @@ sub new {
     }
   }
 
-  $self->{"rnd"} = int(rand(1000000));
+  $self->{"rnd"}   = int(rand(1000000));
   $self->{"iconv"} = Text::Iconv->new($main::dbcharset, "UTF-8");
 
-  return $self;
-}
-
-sub substitute_vars {
-  my ($self, $text, @indices) = @_;
-
-  my $form = $self->{"form"};
-
-  while ($text =~ /\&lt;\%(.*?)\%\&gt;/) {
-    my $value = $form->{$1};
+  $self->set_tag_style('&lt;%', '%&gt;');
 
-    for (my $i = 0; $i < scalar(@indices); $i++) {
-      last unless (ref($value) eq "ARRAY");
-      $value = $value->[$indices[$i]];
-    }
-    substr($text, $-[0], $+[0] - $-[0]) = $self->format_string($value);
-  }
-
-  return $text;
+  return $self;
 }
 
 sub parse_foreach {
@@ -798,11 +789,7 @@ sub parse_foreach {
 
   my ($form, $new_contents) = ($self->{"form"}, "");
 
-  my $ary = $form->{$var};
-  for (my $i = 0; $i < scalar(@indices); $i++) {
-    last unless (ref($ary) eq "ARRAY");
-    $ary = $ary->[$indices[$i]];
-  }
+  my $ary = $self->_get_loop_variable($var, 1, @indices);
 
   for (my $i = 0; $i < scalar(@{$ary}); $i++) {
     $form->{"__first__"} = $i == 0;
@@ -1342,21 +1329,7 @@ sub format_string {
   my $form = $self->{"form"};
   my $iconv = $self->{"iconv"};
 
-  my %replace =
-    ('order' => ['&', '<', '>', '"', "'",
-                 '\x80',        # Euro
-                 quotemeta("\n"), quotemeta("\r")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     '"'             => '&quot;',
-     "'"             => '&apos;',
-     '&'             => '&amp;',
-     '\x80'          => chr(0xa4), # Euro
-     quotemeta("\n") => '<text:line-break/>',
-     quotemeta("\r") => '',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/OpenDocument', $variable);
 
   # Allow some HTML markup to be converted into the output format's
   # corresponding markup code, e.g. bold or italic.
@@ -1366,7 +1339,7 @@ sub format_string {
 
   foreach my $key (keys(%markup_replace)) {
     my $value = $markup_replace{$key};
-    $variable =~ s|\&lt;${key}\&gt;|<text:span text:style-name=\"TLXO${rnd}${value}\">|gi;
+    $variable =~ s|\&lt;${key}\&gt;|<text:span text:style-name=\"TLXO${rnd}${value}\">|gi; #"
     $variable =~ s|\&lt;/${key}\&gt;|</text:span>|gi;
   }
 
@@ -1409,14 +1382,7 @@ sub format_string {
   my ($self, $variable) = @_;
   my $form = $self->{"form"};
 
-  my %replace =
-    ('order' => ['<', '>', quotemeta("\n")],
-     '<'             => '&lt;',
-     '>'             => '&gt;',
-     quotemeta("\n") => '<br>',
-     );
-
-  map({ $variable =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} });
+  $variable = $main::locale->quote_special_chars('Template/XML', $variable);
 
   # Allow no markup to be converted into the output format
   my @markup_replace = ('b', 'i', 's', 'u', 'sub', 'sup');