[LON-CAPA-cvs] cvs: loncom /xml londefdef.pm lontable.pm

foxr foxr@source.lon-capa.org
Tue, 20 Jan 2009 12:01:01 -0000


This is a MIME encoded message

--foxr1232452861
Content-Type: text/plain

foxr		Tue Jan 20 12:01:01 2009 EDT

  Modified files:              
    /loncom/xml	londefdef.pm lontable.pm 
  Log:
  Switch to new table code.  It seems to work for all my table problems.
  
  
--foxr1232452861
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20090120120101.txt"

Index: loncom/xml/londefdef.pm
diff -u loncom/xml/londefdef.pm:1.397 loncom/xml/londefdef.pm:1.398
--- loncom/xml/londefdef.pm:1.397	Mon Nov 24 18:55:01 2008
+++ loncom/xml/londefdef.pm	Tue Jan 20 12:01:00 2009
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Tags Default Definition Module 
 #
-# $Id: londefdef.pm,v 1.397 2008/11/24 18:55:01 jms Exp $
+# $Id: londefdef.pm,v 1.398 2009/01/20 12:01:00 foxr Exp $
 # 
 #
 # Copyright Michigan State University Board of Trustees
@@ -42,6 +42,7 @@
 use Apache::lonnet;
 use strict;
 use Apache::lonxml;
+use Apache::lontable;
 use Apache::File();
 use Image::Magick;
 use Apache::lonmenu();
@@ -58,20 +59,7 @@
 
 }
 
-#
-#   Dumps all elements of the table structure.
-#   Need this 'cause evidently when given an array, Data::Dumper only seems
-#   to dump element 0.
-#
-#sub debug_dump_table {
-#    my $lastrow = $#Apache::londefdef::table;
-#    &Apache::lonnet::logthis("Dumping table:  Last row index: $lastrow");
-#    my $row;
-#    for ($row =0; $row <= $lastrow; $row++ ) {
-#	my $text = Dumper($Apache::londefdef::table[$row]);
-#	&Apache::lonnet::logthis("table [ $row ]".$text);
-#    }
-#}
+
 sub initialize_londefdef {
     $Apache::londefdef::TD_redirection=0;
     @Apache::londefdef::table = ();
@@ -208,6 +196,12 @@
 			  '\usepackage{pifont}' ."\n".
 			  '\usepackage{latexsym}'."\n".
                           '\usepackage{epsfig}'.
+			  "\\usepackage{xtab}\n".
+			  "\\usepackage{tabularx}\n".
+			  "\\usepackage{booktabs}\n".
+			  "\\usepackage{array}\n".
+			  "\\usepackage{colortbl}\n".
+			  "\\usepackage{xcolor}\n".
                           '\usepackage{calc}'.
                           '\usepackage{amsmath}'.
                           '\usepackage{amssymb}'.
@@ -2018,7 +2012,8 @@
 #               only way I could think of to allow <p> in 
 #               <tr> <th> bodies
 #
-#list of supported attributes: border,width,TeXwidth
+#list of supported attributes: border,width,TeXwidth,TeXtheme
+#                              align
 sub start_table {
     my ($target,$token,$tagstack,$parstack,$parser,$safeeval) = @_;
     my $textwidth = '';
@@ -2027,6 +2022,59 @@
 	$currentstring .= $token->[4];     
     } elsif ($target eq 'tex') {
 	&disable_para();	# Can't have paras in a table.
+
+
+	#  New table code:
+
+	#  Get the parameters that we can do something about:
+
+	my $border = &Apache::lonxml::get_param('border', $parstack, $safeeval, undef, 0);
+	my $width  = &Apache::lonxml::get_param('TeXwidth', $parstack, $safeeval, undef, 0);
+	my $theme  = &Apache::lonxml::get_param('TeXtheme', $parstack, $safeeval, undef, 0);
+	my $align  = &Apache::lonxml::get_param('align', $parstack, $safeeval, undef, 0);
+
+	# The only thing that needs any figuring out is the width.. and then only if it is
+	# a percent. If not it's assumed to be some valid TeX measurement unit e.g. 3.0cm
+	#
+
+	my $table = new Apache::lontable();
+	if ($border ne '') {
+	    $table->table_border(1);
+	    $table->cell_border(1);
+	}
+	if ($theme ne '') {
+	    $table->theme($theme);
+	}
+	if ($align ne '') {
+	    $table->alignment($align);
+	}
+
+	# Missing width is most of page width
+
+	if ($width eq "") {
+	    $width = '70%';
+	}
+	
+	# If a percentage, need to calculate what this means in terms of
+	# page width:
+	
+	if ($width =~ /%$/) {
+	    my $textwidth = &recalc($env{'form.textwidth'});  # Page width in mm.
+	    $width =~ s/%//;
+	    $width = $width * $textwidth / 100.0;
+	    $width .= " mm";
+	    $table->width($width);
+	}
+
+	push(@Apache::londefdef::table, $table);
+        $currentstring.=' \keephidden{NEW TABLE ENTRY}';
+
+	#--------------------------------------------------------
+	#  Old table code here.
+	#--------------------------------------------------------
+
+
+	if (0) {
 	push(@Apache::londefdef::table, {}); 
 	$Apache::londefdef::table[-1]{'row_number'} = -1;
         #maximum table's width (default coincides with text line length)
@@ -2101,7 +2149,7 @@
         $Apache::londefdef::table[-1]{'content'}=[];
         $Apache::londefdef::table[-1]{'align'}=[];
         $currentstring.=' \keephidden{NEW TABLE ENTRY}';
-
+    }
 
     }
     return $currentstring;
@@ -2113,6 +2161,20 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[2];     
     } elsif ($target eq 'tex') {
+
+
+	#  New table code:
+
+	my $table = pop(@Apache::londefdef::table);
+	my $t     = $table->generate();
+	$currentstring = $t->generate_string();
+	&enable_para();
+	#--------------------------------------------------------------
+	#  Old table code:
+	#--------------------------------------------------------------
+
+	if (0) {
+
 	my $border =  &Apache::lonxml::get_param('border',$parstack,$safeeval);
 	my $inmemory = '';
 	my $output = '';
@@ -2528,6 +2590,7 @@
 	}
 	&enable_para();
     }
+    }
     return $currentstring;
 }
 
@@ -2538,6 +2601,19 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[4];     
     } elsif ($target eq 'tex') {
+
+	my $align = &Apache::lonxml::get_param('align', $parstack, $safeeval, undef, 1);
+	$Apache::londefdef::table[-1]->start_row();
+	
+	if ($align ne '') {
+	    $Apache::londefdef::table[-1]->configure_row({default_halign => $align});
+	}
+
+	#---------------------------------------------------------------
+	# Old table code.
+	#---------------------------------------------------------------
+
+	if (0) {
 	$Apache::londefdef::table[-1]{'row_number'}++;
 	my $alignchar=&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1);
 	if ($alignchar ne '') {
@@ -2556,6 +2632,7 @@
 	push @ {$Apache::londefdef::table[-1]{'minlen'}}, [];
 	push @ {$Apache::londefdef::table[-1]{'maxlen'}}, [];
 	push @ {$Apache::londefdef::table[-1]{'content'}}, [];
+    }
     } 
     return $currentstring;
 }
@@ -2566,6 +2643,19 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring .= $token->[2];     
     } elsif ($target eq 'tex') {
+
+	# In case the user is missing a </td> or </th> tag:
+
+	if ($Apache::londefdef::TD_redirection) {
+	    &end_td_tex($parstack,$parser,$safeeval);    
+	}
+	$Apache::londefdef::table[-1]->end_row();
+
+	#-----------------------------------------------
+	# Old table code
+	#-----------------------------------------------
+
+	if (0) {
 	if ($Apache::londefdef::TD_redirection) {
 	    &end_td_tex($parstack,$parser,$safeeval);    
 	}
@@ -2574,7 +2664,7 @@
 	if ($Apache::londefdef::table[-1]{'prior_columns'} > $Apache::londefdef::table[-1]{'counter_columns'}) {
 	    $Apache::londefdef::table[-1]{'counter_columns'} = $Apache::londefdef::table[-1]{'prior_columns'};
 	}
-
+    }
 
 	
     }
@@ -2610,9 +2700,50 @@
     }
     return '';
 }
+
+#
+#  Factor out cell configuration hash generation:
+#
+
+sub cell_config_hash {
+    my ($align, $rowspan, $colspan) = @_;
+    my %config;
+    if ($align ne '') {
+	$config{'halign'} = $align;
+    }
+    if ($colspan ne "") {
+	$config{'colspan'} = $colspan;
+    }
+    if ($rowspan ne '') {
+	$config{'rowspan'} = $rowspan;
+    }
+    return \%config;
+}
  
 sub start_td_tex {
     my ($parstack,$parser,$safeeval) = @_;
+
+    # At this stage, an empty cell is created with the
+    # appropriate rowspan/colspan and alignment
+    # attributes, but empty of text.  end_td_tex will
+    # fetch the contents from the recursive parse and
+    # fill the cell with them:
+    my $align   = &Apache::lonxml::get_param('align', $parstack, $safeeval, undef, 1);
+    my $rowspan = &Apache::lonxml::get_param('rowspan', $parstack, $safeeval, undef, 1);
+    my $colspan = &Apache::lonxml::get_param('colspan', $parstack, $safeeval, undef, 1);
+
+    my $config = &cell_config_hash($align, $rowspan, $colspan);
+
+    my $table = $Apache::londefdef::table[-1];
+    $table->add_cell('', $config);
+    
+
+    #------------------------------------------------
+    #  Old table code.
+    #------------------------------------------------
+
+    if (0) {
+
     my $alignchar = substr(&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1),0,1);
     if ($alignchar eq '') {
 	$alignchar = $Apache::londefdef::table[-1]{'rows'}[-1];
@@ -2625,11 +2756,22 @@
 	$current_length=~/(\d+\.?\d*)/;
 	push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$1;
     }
+    }
     &Apache::lonxml::startredirection();
     return '';
 }
 
 sub end_td_tex {
+
+    my $text = &Apache::lonxml::endredirection();
+    my $table = $Apache::londefdef::table[-1];
+    $table->append_cell_text($text);
+
+    #-------------------------------------------------
+    # Old table code
+    #-------------------------------------------------
+
+    if (0) {
     my ($parstack,$parser,$safeeval) = @_;
     my $current_row    = $Apache::londefdef::table[-1]{'row_number'};
     my $current_column = $Apache::londefdef::table[-1]{'counter_columns'}; 
@@ -2794,7 +2936,7 @@
 	
     }
 
-
+    }
 
     return '';
 }
@@ -2843,6 +2985,24 @@
  
 sub start_th_tex {
     my ($parstack,$parser,$safeeval) = @_;
+
+    my $alignment = &Apache::lonxml::get_param('align', $parstack, $safeeval, undef,1);
+    my $rowspan  =  &Apache::lonxml::get_param('rowspan', $parstack, $safeeval, undef, 1);
+    my $colspan  =  &Apache::lonxml::get_param('colspan', $parstack, $safeeval, undef, 1);
+
+    my $config   = cell_config_hash($alignment, $rowspan, $colspan);
+    my $table    = $Apache::londefdef::table[-1];
+    $table->add_cell('\textbf{', $config);
+
+    #-------------------------------------------------------------------------------------
+    #
+    #  Old table code.
+    #
+    #--------------------------------------------------------------------------------------
+
+    if (0) {
+
+
     my $alignchar = substr(&Apache::lonxml::get_param('align',$parstack,$safeeval,undef,1),0,1);
     if ($alignchar eq '') {
 	$alignchar = $Apache::londefdef::table[-1]{'rows'}[-1];
@@ -2855,12 +3015,26 @@
 	$current_length=~/(\d+\.?\d*)/;
 	push @ {$Apache::londefdef::table[-1]{'TeXlen'}[$Apache::londefdef::table[-1]{'row_number'}] },$1;
     }
+    }
+
+    # Accept xml until the </th> tag.
+
     &Apache::lonxml::startredirection();
     return '';
 }
 
 sub end_th_tex {
     my ($parstack,$parser,$safeeval) = @_;
+
+    my $table = $Apache::londefdef::table[-1];
+    my $text  = &Apache::lonxml::endredirection();
+    $table->append_cell_text($text.'}');
+
+    #-----------------------------------------------------------------------------
+    #  Old table code:
+    #-----------------------------------------------------------------------------
+
+    if (0) {
     my $current_row = $Apache::londefdef::table[-1]{'row_number'};
     my $data=&Apache::lonxml::endredirection();
     my $TeXwidth=&Apache::lonxml::get_param('TeXwidth',$parstack,$safeeval,undef,0);
@@ -2925,6 +3099,7 @@
     #make data bold
     $data='\textbf{'.$data.'}';
     push @ {$Apache::londefdef::table[-1]{'content'}[-1] },$data;
+    }
     return'';
 }
 
Index: loncom/xml/lontable.pm
diff -u loncom/xml/lontable.pm:1.7 loncom/xml/lontable.pm:1.8
--- loncom/xml/lontable.pm:1.7	Mon Dec 29 11:57:37 2008
+++ loncom/xml/lontable.pm	Tue Jan 20 12:01:01 2009
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 #  Generating TeX tables.
 #
-# $Id: lontable.pm,v 1.7 2008/12/29 11:57:37 foxr Exp $
+# $Id: lontable.pm,v 1.8 2009/01/20 12:01:01 foxr Exp $
 # 
 #
 # Copyright Michigan State University Board of Trustees
@@ -56,7 +56,9 @@
 package Apache::lontable;
 use strict;
 use LaTeX::Table;
+use Apache::lonnet;		# for trace logging.
 
+my $tracing = 0;		# Set to 1 to enable log tracing. 2 for local sub tracing.
 
 =pod
 
@@ -135,9 +137,10 @@
 
 =item width
 
-The width of the table.  This can be expressed as fractions of full width, or in any
-TeX unit measure e.g. 0.75 for 75% of the width, or 10.8cm  This forces the table to the
-tabularx environment.
+The width of the table.   in any
+TeX unit measure e.g.  10.8cm  This forces the table to the
+tabularx environment.  It also forces the declarations for
+cells to be paragraph mode which supports more internal formatting.
 
 =back
 
@@ -252,6 +255,8 @@
 sub new {
     my ($class, $configuration) = @_;
 
+    if($tracing) {&Apache::lonnet::logthis("new table object");}
+
     #  Initialize the object member data with the default values
     #  then override with any stuff in $configuration.
 
@@ -298,6 +303,8 @@
 sub alignment {
     my ($self, $new_value) = @_;
 
+    if ($tracing) {&Apache::lonnet::logthis("alignment = $new_value");}
+
     if (defined($new_value)) {
 	$self->{'alignment'} = $new_value;
     }
@@ -323,6 +330,8 @@
 sub table_border {
     my ($self, $new_value) = @_;
 
+    if ($tracing) {&Apache::lonnet::logthis("table_border $new_value");}
+
     if (defined($new_value)) {
 	$self->{'outer_border'} = $new_value;
     }
@@ -348,7 +357,7 @@
 
 sub cell_border {
     my ($self, $new_value) = @_;
-
+    if($tracing) {&Apache::lonnet::logthis("cell_border: $new_value"); }
     if (defined($new_value)) {
 	$self->{'inner_border'} = $new_value;
     }
@@ -373,6 +382,7 @@
 sub caption {
     my ($self, $new_value) = @_;
 
+    if($tracing) {&Apache::lonnet::logthis("caption: $new_value"); }
     if (defined($new_value)) {
 	$self->{'caption'} = $new_value;
     }
@@ -397,7 +407,7 @@
 
 sub theme {
     my ($self, $new_value) = @_;
-
+    if($tracing) {&Apache::lonnet::logthis("theme $new_value"); }
     if (defined($new_value)) {
 	$self->{'theme'} = $new_value;
     }
@@ -412,12 +422,13 @@
 
 =head 3 Examples:
 
- $table->width("0.8");    # 80% of the column width.
  my $newwidth = $table->width("10cm");   # 10cm width returns "10cm".
 
 =cut
 sub width {
     my ($self, $new_value) = @_;
+    if($tracing) {&Apache::lonnet::logthis("width = $new_value"); }
+
     if (defined($new_value)) {
 	$self->{'width'} = $new_value;
     }
@@ -454,7 +465,7 @@
 
 sub start_row {
     my ($self, $config) = @_;
-
+    if($tracing) {&Apache::lonnet::logthis("start_row"); }
     if ($self->{'row_open'}) { 
 	$self->end_row();
     }
@@ -495,7 +506,7 @@
 
 sub end_row {
     my ($self) = @_;
-
+    if($tracing) {&Apache::lonnet::logthis("end_row"); }
     if ($self->{'row_open'}) {
 	
 	# Mostly we need to determine if this row has the maximum
@@ -543,7 +554,7 @@
 
 sub configure_row {
     my ($self, $config) = @_;
-
+    if($tracing) {&Apache::lonnet::logthis("configure_row");}
     if (!$self->{'row_open'}) {
 	$self->start_row();
     }
@@ -601,6 +612,8 @@
 sub add_cell {
     my ($self, $text, $config) = @_;
 
+    if($tracing) {&Apache::lonnet::logthis("add_cell : $text"); }
+
     # If a row is not open, we must open it:
 
     if (!$self->{'row_open'}) {
@@ -627,6 +640,9 @@
 		# end point of the pulled down cell.
 
 		my $prior_cell = $last_row->{'cells'}->[$prior_cell_index];
+		if (!defined($prior_cell)) {
+		    last;
+		}
 		if (($prior_cell->{'start_col'} == $last_coord) &&
 		    ($prior_cell->{'rowspan'}  > 1)) {
 		    
@@ -666,8 +682,36 @@
     $current_row->{'cell_width'} += $cell->{'colspan'};
 
     push(@$current_cells, $cell);
+
+    if ($tracing) { &Apache::lonnet::logthis("add_cell done"); }
 }
 
+
+=pod
+
+=head2  append_cell_text
+
+Sometimes it's necessary to create/configure the cell and then later add text to it.
+This sub allows text to be appended to the most recently created cell.
+
+=head3 Parameters
+
+The text to add to the cell.
+
+=cut
+sub append_cell_text {
+    my ($this, $text) = @_;
+
+    if($tracing) {&Apache::lonnet::logthis("append_cell_text: $text"); }
+    my $rows         = $this->{'rows'};
+    my $current_row  = $rows->[-1];
+    my $cells        = $current_row->{'cells'};
+    my $current_cell = $cells->[-1];
+    $current_cell->{'contents'} .= $text;
+    
+}
+
+
 =pod
 
 =head2 generate
@@ -681,21 +725,31 @@
 =cut
 sub generate {
     my ($this) = @_;
+    my $useP   = 0;
+    my $colwidth;
+    my $colunits;
 
+    if($tracing) {&Apache::lonnet::logthis("generate"); }
     my $table = LaTeX::Table->new();
+    $table->set_center(0);	# loncapa tables don't float.
+    $table->set_environment(0);
+
 
     # Add the caption if supplied.
 
     if ($this->{'caption'} ne "") {
 	$table->set_caption($this->caption);
     }
-
     
     # Set the width if defined:
 
     if (defined ($this->{'width'})) {
-	$table->set_width($this->{'width'});
-	$table->set_width_environment('tabularx');
+#	$table->set_width($this->{'width'});
+#	$table->set_width_environment('tabularx');
+	$useP = 1;
+	($colwidth, $colunits) = split(/ /, $this->{'width'});
+	$colwidth = $colwidth/$this->{'column_count'};
+
     }
 
     # Build up the data:
@@ -715,6 +769,7 @@
 	my $startcol   = 1;
 	my @underlines;		# Array of \cline cells if cellborder on.
 
+
 	for (my $cell  = 0; $cell < $cell_count; $cell++) {
 	    my $contents = $cells->[$cell]->{'contents'};
 
@@ -732,12 +787,29 @@
 	    # Create the horizontal alignment character:
 
 	    my $col_align = 'l';
+	    my $embeddedAlignStart = "";
+	    my $embeddedAlignEnd   = "";
+
 	    if ($halign eq 'right') {
 		$col_align = 'r';
+		$embeddedAlignStart = '\begin{flushright} ';
+		$embeddedAlignEnd   = ' \end{flushright}';
 	    }
 	    if ($halign eq 'center') {
 		$col_align = 'c';
+		$embeddedAlignStart = '\begin{center}';
+		$embeddedAlignEnd   = '\end{center}';
 	    }
+
+	    # If the width has been specified, turn these into
+	    # para mode; and wrap the contents in the start/stop stuff:
+
+	    if ($useP) {
+		my $cw = $colwidth * $cells->[$cell]->{'colspan'};
+		$col_align = "p{$cw $colunits}";
+		$contents = $embeddedAlignStart . $contents .  $embeddedAlignEnd;
+	    }
+
 	    if ($inner_border || ($outer_border && ($cell == 0))) {
 		$col_align = '|'.$col_align;
 	    }
@@ -749,7 +821,22 @@
 
 	    my $cspan    = $cells->[$cell]->{'colspan'};
 	    my $nextcol  = $startcol + $cspan;
-	    $contents = '\multicolumn{'.$cspan.'}{'.$col_align.'}{'.$contents.'}';
+
+	    # If we can avoid the \multicolumn directive that's best as
+	    # that makes some things like \parpic invalid in LaTeX which
+            # screws everything up.
+
+	    if (($cspan > 1) || !($col_align =~ /l/)) {
+
+		$contents = '\multicolumn{'.$cspan.'}{'.$col_align.'}{'.$contents.'}';
+
+		# A nasty edge case.  If there's only one cell, the software will assume
+		# we're in complete control of the row so we need to end the row ourselves.
+		
+		if ($cell_count == 1) {
+		    $contents .= '  \\\\';
+		}
+	    }
 	    if ($inner_border && ($cells->[$cell]->{'rowspan'} == 1)) {
 		my $lastcol = $nextcol -1;
 		push(@underlines, "\\cline{$startcol-$lastcol}");
@@ -757,7 +844,6 @@
 	    $startcol = $nextcol;
 	    # Rowspans should take care of themselves.
 	    
-
 	    push(@row, $contents);
 
 	}
@@ -776,7 +862,11 @@
 	$coldef .= '|';
     }
     for (my $i =0; $i < $column_count; $i++) {
-	$coldef .= 'l';
+	if ($useP) {
+	    $coldef .= "p{$colwidth $colunits}";
+	} else {
+	    $coldef .= 'l';
+	}
 	if ($inner_border || 
 	    ($outer_border && ($i == $column_count-1))) {
 	    $coldef .= '|';
@@ -786,6 +876,8 @@
 
     # Return the table:
 
+    if ($tracing) { &Apache::lonnet::logthis("Leaving generate"); }
+
     return $table;
 
 }
@@ -795,11 +887,14 @@
 
 sub get_object_attribute {
     my ($self, $attribute) = @_;
+    if ($tracing > 1) { &Apache::lonnet::logthis("get_object_attribute: $attribute"); }
     return $self->{$attribute};
 }
 
 sub get_row {
     my ($self, $row) = @_;
+    if ($tracing > 1) { &Apache::lonnet::logthis("get_row"); }
+
     my $rows = $self->{'rows'};	  # ref to an array....
     return $rows->[$row];         # ref to the row hash for the selected row.
 }

--foxr1232452861--