Diff for /loncom/xml/lontable.pm between versions 1.12 and 1.16

version 1.12, 2010/08/27 09:42:49 version 1.16, 2011/04/05 10:02:58
Line 58  use strict; Line 58  use strict;
 use Apache::lonlatextable;  use Apache::lonlatextable;
 use Apache::lonnet; # for trace logging.  use Apache::lonnet; # for trace logging.
   
 my $tracing = 1; # Set to 1 to enable log tracing. 2 for local sub tracing.  my $tracing = 0; # Set to 1 to enable log tracing. 2 for local sub tracing.
   
 =pod  =pod
   
Line 255  The contents of the cell. Line 255  The contents of the cell.
 sub new {  sub new {
     my ($class, $configuration) = @_;      my ($class, $configuration) = @_;
   
     if($tracing) {&Apache::lonnet::logthis("new table object");}  
   
     #  Initialize the object member data with the default values      #  Initialize the object member data with the default values
     #  then override with any stuff in $configuration.      #  then override with any stuff in $configuration.
Line 269  sub new { Line 268  sub new {
  column_count   => 0,   column_count   => 0,
  row_open       => 0,   row_open       => 0,
  rows           => [],   rows           => [],
    col_widths      => {}
     };      };
   
     foreach my $key (keys %$configuration) {      foreach my $key (keys %$configuration) {
Line 347  Set or get the presence of a request for Line 347  Set or get the presence of a request for
 drawn around them.  If a paramter is passed, it will be treated as  drawn around them.  If a paramter is passed, it will be treated as
 a new value for the cell border configuration.  Regardless,the final  a new value for the cell border configuration.  Regardless,the final
 value of that configuration parameter is returned.  value of that configuration parameter is returned.
   Valid values for the parameter are:
   
   =over 2
   
   =item 0 - no borders present.
   
   =item 1 - All borders (borders around all four sides of the cell.
   
   =item 2 - Border at top and bottom of the cell.
   
   =item 3 - Border at the left and right sides of the cell.
   
   
   =over -2 
   
 =head3 Examples:  =head3 Examples:
   
Line 548  The default vertical alignment for text Line 562  The default vertical alignment for text
   
 "top", "bottom" or "center"  "top", "bottom" or "center"
   
   
 =back   =back 
   
 =cut  =cut
Line 605  Number of rows the cell spans. Line 620  Number of rows the cell spans.
   
 Number of columns the cell spans.  Number of columns the cell spans.
   
   =item width
   
   LaTeX specification of the width of the cell.
   Note that if there is a colspan this width is going to be equally divided
   over the widths of the columnsn in the span.
   Note as well that if width specification conflict, the last one specified wins...silently.
   
 =back  =back
   
 =cut  =cut
Line 676  sub add_cell { Line 698  sub add_cell {
           
     if (defined($config)) {      if (defined($config)) {
  foreach my $key (keys(%$config)) {   foreach my $key (keys(%$config)) {
               if ($key eq 'colspan') {
                   next if ($config->{$key} == 0);
               }
     $cell->{$key} = $config->{$key};      $cell->{$key} = $config->{$key};
  }   }
     }      }
   
     $current_row->{'cell_width'} += $cell->{'colspan'};      $current_row->{'cell_width'} += $cell->{'colspan'};
   
   
       #
       # Process the width if it exists.  If supplied it must be of the form:
       #   float units
       # Where units can be in, cm or mm.
       # Regardless of the supplied units we will normalize to cm.
       # This allows computation on units at final table generation time.
       #
   
       if (exists($cell->{'width'})) {
    my $width;
    my $widthcm;
    $width   = $config->{'width'};
    $widthcm = $self->size_to_cm($width);
   
    # If there's a column span, the actual width is divided by the span
    # and applied to each of the columns in the span.
   
    $widthcm = $widthcm / $cell->{'colspan'};
    for (my $i = $last_coord; $i < $last_coord + $cell->{'colspan'}; $i++) {
       $self->{'col_widths'}->{$i} = $widthcm; 
    }
   
       }
   
     push(@$current_cells, $cell);      push(@$current_cells, $cell);
   
     if ($tracing) { &Apache::lonnet::logthis("add_cell done"); }      if ($tracing) { &Apache::lonnet::logthis("add_cell done"); }
Line 726  The caller can then ask the table object Line 777  The caller can then ask the table object
 sub generate {  sub generate {
     my ($this) = @_;      my ($this) = @_;
     my $useP   = 0;      my $useP   = 0;
     my $colwidth;  
     my $colunits;      my $colunits = 'cm'; # All widths get normalized to cm.
       my $tablewidth;
   
     if($tracing) {&Apache::lonnet::logthis("generate"); }      if($tracing) {&Apache::lonnet::logthis("generate"); }
     my $table = Apache::lonlatextable->new();      my $table = Apache::lonlatextable->new();
   
   
   
     # Add the caption if supplied.      # Add the caption if supplied.
   
     if ($this->{'caption'} ne "") {      if ($this->{'caption'} ne "") {
Line 742  sub generate { Line 793  sub generate {
           
     # Set the width if defined:      # Set the width if defined:
   
       my $default_width;
       my $colwidths        = $this->{'col_widths'};
     if (defined ($this->{'width'})) {      if (defined ($this->{'width'})) {
 # $table->set_width($this->{'width'});   $tablewidth = $this->{'width'};
 # $table->set_width_environment('tabularx');   $tablewidth = $this->size_to_cm($tablewidth);
   
  $useP = 1;   $useP = 1;
  ($colwidth, $colunits) = split(/ /, $this->{'width'});  
  $colwidth = $colwidth/$this->{'column_count'};  
   
    # Figure out the default width for a column with unspecified
    # We take the initially specified widths and sum them up.
    # This is subtracted from total width  above.
    # If the result is negative we're going to allow a minimum of 2.54cm for
    # each column and make the table spill appropriately.  
    # This (like a riot) is an ugly thing but I'm open to suggestions about
    # how to handle it better (e.g. scaling down requested widths?).
   
    my $specified_width = 0.0;
    my $specified_cols   = 0;
    foreach my $col (keys %$colwidths) {
       $specified_width = $specified_width + $colwidths->{$col};
       $specified_cols++;
    }
    my $unspecified_cols = $this->{'column_count'} - $specified_cols;
   
    #  If zero unspecified cols, we are pretty much done... just have to
    #  adjust the total width to be specified  width. Otherwise we
    #  must figure out the default width and total width:
    #
    my $total_width;
    if($unspecified_cols == 0) {
       $total_width = $specified_width;
    } else {
       $default_width = ($tablewidth - $specified_width)/$unspecified_cols; #  Could be negative....
       $total_width   = $default_width * $unspecified_cols + $specified_width;
    }
   
    # if the default_width is < 0.0 the user has oversubscribed the width of the table with the individual
    # column.  In this case, we're going to maintain the desired proportions of the user's columns, but 
    # ensure that the unspecified columns get a fair share of the width..where a fair share is defined as
    # the total width of the table / unspecified column count.
    # We figure out what this means in terms of reducing the specified widths by dividing by a constant proportionality.
    # Note that this cannot happen if the user hasn't specified anywidths as the computation above would then
    # just make all columns equal fractions of the total table width.
   
    if ($default_width < 0) {
       $default_width = ($tablewidth/$unspecified_cols);                     # 'fair' default width.
       my $width_remaining = $tablewidth - $default_width*$unspecified_cols; # What's left for the specified cols.
       my $reduction       = $tablewidth/$width_remaining;                    # Reduction fraction for specified cols
       foreach my $col (keys %$colwidths) {
    $colwidths->{$col} = $colwidths->{$col}/$reduction;
       }
       
           }
     }      }
   
   
   
   
     # Build up the data:      # Build up the data:
   
     my @data;      my @data;
Line 760  sub generate { Line 860  sub generate {
     my $outer_border = $this->{'outer_border'};      my $outer_border = $this->{'outer_border'};
     my $column_count = $this->{'column_count'};      my $column_count = $this->{'column_count'};
   
       my $cell_ul_border = (($inner_border == 1) || ($inner_border == 2)) ? 1 : 0;
       my $cell_lr_border = (($inner_border == 1) || ($inner_border == 3)) ? 1 : 0;
    
     # Add a top line if the outer or inner border is enabled:      # Add a top line if the outer or inner border is enabled:
   
     if ($outer_border || $inner_border) {      if ($outer_border || $cell_ul_border) {
  push(@data, ["\\cline{1-$column_count}"]);        push(@data, ["\\cline{1-$column_count}"]);     
   
     }      }
Line 799  sub generate { Line 902  sub generate {
   
     if ($halign eq 'right') {      if ($halign eq 'right') {
  $col_align = 'r';   $col_align = 'r';
  $embeddedAlignStart = '\begin{flushright} ';                  $embeddedAlignStart = '\raggedleft';
  $embeddedAlignEnd   = ' \end{flushright}';  
     }      }
     if ($halign eq 'center') {      if ($halign eq 'center') {
  $col_align = 'c';   $col_align = 'c';
Line 812  sub generate { Line 914  sub generate {
     # para mode; and wrap the contents in the start/stop stuff:      # para mode; and wrap the contents in the start/stop stuff:
   
     if ($useP) {      if ($useP) {
  my $cw = $colwidth * $cells->[$cell]->{'colspan'};   my $cw;
    if (defined($colwidths->{$cell})) {
       $cw = $colwidths->{$cell};
    } else {
       $cw = $default_width;
    }
    $cw = $cw * $cells->[$cell]->{'colspan'};
  $col_align = "p{$cw $colunits}";   $col_align = "p{$cw $colunits}";
  $contents = $embeddedAlignStart . $contents .  $embeddedAlignEnd;   $contents = $embeddedAlignStart . $contents .  $embeddedAlignEnd;
     }      }
   
     if ($inner_border || ($outer_border && ($cell == 0))) {      if ($cell_lr_border || ($outer_border && ($cell == 0))) {
  $col_align = '|'.$col_align;   $col_align = '|'.$col_align;
     }      }
     if ($inner_border || ($outer_border && ($cell == ($cell_count -1)))) {      if ($cell_lr_border || ($outer_border && ($cell == ($cell_count -1)))) {
  $col_align = $col_align.'|';   $col_align = $col_align.'|';
     }      }
   
Line 844  sub generate { Line 952  sub generate {
     $contents .= '  \\\\';      $contents .= '  \\\\';
  }   }
     }      }
     if ($inner_border && ($cells->[$cell]->{'rowspan'} == 1)) {      if ($cell_ul_border && ($cells->[$cell]->{'rowspan'} == 1)) {
  my $lastcol = $nextcol -1;   my $lastcol = $nextcol -1;
  push(@underlines, "\\cline{$startcol-$lastcol}");   push(@underlines, "\\cline{$startcol-$lastcol}");
     }      }
Line 855  sub generate { Line 963  sub generate {
   
  }   }
  push(@data, \@row);   push(@data, \@row);
  if ($inner_border) {   if ($cell_ul_border) {
     for (my $i =0; $i < scalar(@underlines); $i++) {      for (my $i =0; $i < scalar(@underlines); $i++) {
  push(@data, [$underlines[$i]]);   push(@data, [$underlines[$i]]);
     }      }
Line 866  sub generate { Line 974  sub generate {
     # Add bottom border if necessary: if the inner border was on, the loops above      # Add bottom border if necessary: if the inner border was on, the loops above
     # will have done a bottom line under the last cell.      # will have done a bottom line under the last cell.
     #      #
     if ($outer_border && !$inner_border) {      if ($outer_border && !$cell_ul_border) {
  push(@data, ["\\cline{1-$column_count}"]);        push(@data, ["\\cline{1-$column_count}"]);     
   
     }      }
     $table->set_data(\@data);      $table->set_data(\@data);
           
     my $coldef = "";      my $coldef = "";
     if ($outer_border || $inner_border) {      if ($outer_border || $cell_lr_border) {
  $coldef .= '|';   $coldef .= '|';
     }      }
     for (my $i =0; $i < $column_count; $i++) {      for (my $i =0; $i < $column_count; $i++) {
  if ($useP) {   if ($useP) {
     $coldef .= "p{$colwidth $colunits}";      $coldef .= "p{$default_width $colunits}";
  } else {   } else {
     $coldef .= 'l';      $coldef .= 'l';
  }   }
  if ($inner_border ||    if ($cell_lr_border || 
     ($outer_border && ($i == $column_count-1))) {      ($outer_border && ($i == $column_count-1))) {
     $coldef .= '|';      $coldef .= '|';
  }   }
Line 897  sub generate { Line 1005  sub generate {
     return $table;      return $table;
   
 }  }
   #---------------------------------------------------------------------------
   #
   #  Private methods:
   #
   
   # 
   # Convert size with units -> size in cm.
   # The resulting size is floating point with no  units so that it can be used in
   # computation.  Note that an illegal or missing unit is treated silently as
   #  cm for now.
   #
   sub size_to_cm {
       my ($this, $size_spec) = @_;
       my ($size, $units) = split(/ /, $size_spec);
       if (lc($units) eq 'mm') {
    return $size / 10.0;
       }
       if (lc($units) eq 'in') {
    return $size * 2.54;
       }
       
       return $size; # Default is cm.
   }
 #----------------------------------------------------------------------------  #----------------------------------------------------------------------------
 # The following methods allow for testability.  # The following methods allow for testability.
   
Line 914  sub get_row { Line 1045  sub get_row {
     my $rows = $self->{'rows'};  # ref to an array....      my $rows = $self->{'rows'};  # ref to an array....
     return $rows->[$row];         # ref to the row hash for the selected row.      return $rows->[$row];         # ref to the row hash for the selected row.
 }  }
   
 #   Mandatory initialization.  #   Mandatory initialization.
 BEGIN{  BEGIN{
 }  }
   
 1;  1;
 __END__  __END__
    

Removed from v.1.12  
changed lines
  Added in v.1.16


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>