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

foxr foxr@source.lon-capa.org
Wed, 13 Apr 2011 10:08:07 -0000


This is a MIME encoded message

--foxr1302689287
Content-Type: text/plain

foxr		Wed Apr 13 10:08:07 2011 EDT

  Modified files:              
    /loncom/xml	londefdef.pm lonlatextable.pm lontable.pm 
  Log:
  BZ 6317 - NOTE This commit contains over-extensive debugging output and should not be used in production.
  - This commit includes initial work to support the rule="groups" option in 
  <table> for printing.  Commit because some drastic re-factoring and some data
  structure re-engineering was requuired to capture some of the group information.
  Anticipate the next commit will support <thead><tbody><tfoot> properly
  both with respect to the order in which they appear in the output and
  with respect to rules="groups"...if this version does not already do that
  correctly...at that time the debug spew will be removed as well.
  
  
  
--foxr1302689287
Content-Type: text/plain
Content-Disposition: attachment; filename="foxr-20110413100807.txt"

Index: loncom/xml/londefdef.pm
diff -u loncom/xml/londefdef.pm:1.429 loncom/xml/londefdef.pm:1.430
--- loncom/xml/londefdef.pm:1.429	Tue Apr  5 10:33:15 2011
+++ loncom/xml/londefdef.pm	Wed Apr 13 10:08:06 2011
@@ -1,7 +1,8 @@
+
 # The LearningOnline Network with CAPA
 # Tags Default Definition Module 
 #
-# $Id: londefdef.pm,v 1.429 2011/04/05 10:33:15 foxr Exp $
+# $Id: londefdef.pm,v 1.430 2011/04/13 10:08:06 foxr Exp $
 # 
 #
 # Copyright Michigan State University Board of Trustees
@@ -2076,6 +2077,8 @@
 		$table->cell_border(2);
 	    } elsif ($cell_border eq 'cols') {
 		$table->cell_border(3);
+	    } elsif($cell_border eq 'groups') {
+		$table->cell_border(4);
 	    } else {
 		$table->cell_border(0);
 	    }
@@ -3384,13 +3387,34 @@
     return $currentstring;
 }
 
-#-- <colgroup> tag (end tag optional)
+#-- <colgroup tag (end tag optional)
 sub start_colgroup {
-    my ($target,$token) = @_;
+    my ($target,$token,$tagstack, $parstack, $parser, $safeeval, $style) = @_;
     my $currentstring = '';
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[4];     
     } 
+    if ($target eq 'tex') {
+	# TODO: Ensure this tag is in a table:
+
+	# Fetch the attributes and build the hash for the
+	# call to define_colgroup.
+
+	my $span    = &Apache::lonxml::get_param('span',   $parstack, $safeeval);
+	my $halign  = &Apache::lonxml::get_param('halign', $parstack, $safeeval);
+
+	my %colgroup_params;
+	if ($span ne '') {
+	    $colgroup_params{'span'} = $span;
+	}
+	if ($halign ne '') {
+	    $colgroup_params{'halign'} = $halign;
+	}
+	
+	my $table = $Apache::londefdef::table[-1];
+	$table->define_colgroup(\%colgroup_params);
+
+    }
     return $currentstring;
 }
 
@@ -3884,6 +3908,12 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[4];     
     } 
+    if ($target eq 'tex') {
+	# TODO: Ensure this tag is within a table:
+
+	my $table = $Apache::londefdef::table[-1];
+	$table->start_body();
+    }
     return $currentstring;
 }
 
@@ -3893,6 +3923,12 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[2];    
     } 
+    if($target eq 'tex') {
+	# TODO: Ensure this tag is within a table:
+
+	my $table = $Apache::londefdef::table[-1];
+	$table->end_body();
+    }
     return $currentstring;
 }
 
@@ -3903,6 +3939,11 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[4];     
     } 
+    if ($target eq 'tex') {
+        # TODO: ensure this is within a table tag.
+	my $table = $Apache::londefdef::table[-1];
+	$table->start_foot();
+    }
     return $currentstring;
 }
 
@@ -3912,6 +3953,11 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[2];    
     } 
+    if ($target eq 'tex') {
+	#  TODO: Ensure this is in side a table 
+	my $table = $Apache::londefdef::table[-1];
+	$table->end_foot();
+    }
     return $currentstring;
 }
 
@@ -3922,6 +3968,11 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[4];     
     } 
+    if ($target eq 'tex') {
+	# Assume we're in a table... TODO: Verify that and ignore tag if not.
+	my $table = $Apache::londefdef::table[-1];
+	$table->start_head();
+    }
     return $currentstring;
 }
 
@@ -3931,6 +3982,12 @@
     if ($target eq 'web' || $target eq 'webgrade') {
 	$currentstring = $token->[2];    
     } 
+    if ($target eq 'tex') {
+     	# TODO: Verify we are in a table and ignore tag if not.
+
+	my $table = $Apache::londefdef::table[-1];
+	$table->end_head();
+    }
     return $currentstring;
 }
 
Index: loncom/xml/lonlatextable.pm
diff -u loncom/xml/lonlatextable.pm:1.2 loncom/xml/lonlatextable.pm:1.3
--- loncom/xml/lonlatextable.pm:1.2	Fri Aug 27 09:42:48 2010
+++ loncom/xml/lonlatextable.pm	Wed Apr 13 10:08:06 2011
@@ -1,6 +1,6 @@
 #  Generating TeX tables.
 #
-# $Id: lonlatextable.pm,v 1.2 2010/08/27 09:42:48 foxr Exp $
+# $Id: lonlatextable.pm,v 1.3 2011/04/13 10:08:06 foxr Exp $
 # 
 #
 # Copyright Michigan State University Board of Trustees
@@ -78,6 +78,8 @@
 =cut
 
 package Apache::lonlatextable;
+use Data::Dumper;
+use Apache::lonnet;
 use strict;
 
 =pod
@@ -146,6 +148,8 @@
 
 =back
 
+Calling this multiple times will continue to append cell data.
+
 =head3 Example
 
     $table->set_data([ ['Gnu', '92.52'], [], ['Emu', '33.33'] ]);
@@ -157,11 +161,19 @@
     |   Emu        | 33.33        |
     +--------------+--------------+
 
+
 =cut
 
 sub set_data {
     my ($self, $data) = @_;
-    $self->{'data'}  = $data;
+    &Apache::lonnet::logthis("--------------- set_data ------------");
+    &Apache::lonnet::logthis(Dumper($self->{'data'}));
+    &Apache::lonnet::logthis("---------------------------------------");
+    &Apache::lonnet::logthis(Dumper($data));
+    my $current_data = $self->{'data'};
+    push (@$current_data, @$data);
+    $self->{'data'} = $current_data;
+
 
 }
 
Index: loncom/xml/lontable.pm
diff -u loncom/xml/lontable.pm:1.16 loncom/xml/lontable.pm:1.17
--- loncom/xml/lontable.pm:1.16	Tue Apr  5 10:02:58 2011
+++ loncom/xml/lontable.pm	Wed Apr 13 10:08:06 2011
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 #  Generating TeX tables.
 #
-# $Id: lontable.pm,v 1.16 2011/04/05 10:02:58 foxr Exp $
+# $Id: lontable.pm,v 1.17 2011/04/13 10:08:06 foxr Exp $
 # 
 #
 # Copyright Michigan State University Board of Trustees
@@ -57,8 +57,9 @@
 use strict;
 use Apache::lonlatextable;
 use Apache::lonnet;		# for trace logging.
+use Data::Dumper;
 
-my $tracing = 0;		# Set to 1 to enable log tracing. 2 for local sub tracing.
+my $tracing = 1;		# Set to 1 to enable log tracing. 2 for local sub tracing.
 
 =pod
 
@@ -108,7 +109,7 @@
 
   my $table = lontable::new(\%config_hash)
 
-=over3
+=over 3
 
 
 =item alignment
@@ -211,11 +212,10 @@
 
 =item cells
 
+
 Array of hashes where each element represents the data for a cell.
 The contents of each element of this hash are described below:
 
-=over 3
-
 =item header
 
 If present, the row is a 'header' that is it was made via the
@@ -248,14 +248,13 @@
 
 =back
 
-=back
 
 =cut
 
 sub new {
     my ($class, $configuration) = @_;
 
-
+    if ($tracing) {&Apache::lonnet::logthis("new table"); }
     #  Initialize the object member data with the default values
     #  then override with any stuff in $configuration.
 
@@ -267,8 +266,14 @@
 	theme          => "plain",
 	column_count   => 0,
 	row_open       => 0,
-	rows           => [],
-	col_widths      => {}
+	rows           => {
+	    'body'     => [],
+            'head'     => [],
+	    'foot'     => []
+	},
+	col_widths      => {},
+	part           => 'body'     # one of 'body', 'head', 'foot'.
+
     };
 
     foreach my $key (keys %$configuration) {
@@ -359,8 +364,10 @@
 
 =item 3 - Border at the left and right sides of the cell.
 
+=item 4 - Border around groups (colgroups as well as thead/tfoot/tbody).
 
-=over -2 
+
+=back
 
 =head3 Examples:
 
@@ -430,11 +437,11 @@
 
 =pod
 
-=head 2 width
+=head2 width
 
 Gets and optionally sets the width of the table.
 
-=head 3 Examples:
+=head3 Examples:
 
  my $newwidth = $table->width("10cm");   # 10cm width returns "10cm".
 
@@ -499,7 +506,7 @@
     }
 
     
-    my $rows = $self->{'rows'};
+    my $rows = $self->{'rows'}->{$self->{'part'}};
     push(@$rows, $row_hash);
 
     $self->{"row_open"} = 1;	# Row is now open and ready for business.
@@ -525,8 +532,10 @@
 	
 	# Mostly we need to determine if this row has the maximum
 	# cell count of any row in existence in the table:
-
-	my $row        = $self->{'rows'}->[-1];
+	
+	&Apache::lonnet::logthis($self->{'part'});
+	&Apache::lonnet::logthis(Dumper($self->{'rows'}));
+	my $row        = $self->{'rows'}->{$self->{'part'}}->[-1];
 	my $cells      = $row->{'cells'};
 
 	if ($row->{'cell_width'} > $self->{'column_count'}) {
@@ -574,7 +583,7 @@
 	$self->start_row();
     }
     
-    my $row = $self->{'rows'}[-1];
+    my $row = $self->{'rows'}->{$self->{'part'}}->[-1];
     foreach my $config_item (keys %$config) {
 	$row->{$config_item} = $config->{$config_item};
     }
@@ -629,6 +638,8 @@
 
 =back
 
+=back 
+
 =cut
 
 sub add_cell {
@@ -641,7 +652,7 @@
     if (!$self->{'row_open'}) {
 	$self->start_row();
     }
-    my $rows          = $self->{'rows'};
+    my $rows          = $self->{'rows'}->{$self->{'part'}};
     my $current_row   = $rows->[-1];
     my $current_cells = $current_row->{'cells'}; 
     my $last_coord    = $current_row->{'cell_width'};
@@ -754,14 +765,178 @@
     my ($this, $text) = @_;
 
     if($tracing) {&Apache::lonnet::logthis("append_cell_text: $text"); }
-    my $rows         = $this->{'rows'};
+    my $rows         = $this->{'rows'}->{$this->{'part'}};
     my $current_row  = $rows->[-1];
     my $cells        = $current_row->{'cells'};
     my $current_cell = $cells->[-1];
     $current_cell->{'contents'} .= $text;
     
 }
+#-------------------------- Support for row/column groups.   ----
+
+=pod 
+
+=head2 start_head 
+
+starts the table head.  This corresponds to the <thead> tag in 
+html/xml.  All rows defined in this group will be
+collected and placed at the front of the table come rendering time.
+Furthermore, if the table has group borders enabled, a rule will be
+rendered following and preceding this group of rows.
+
+=cut
+
+sub start_head {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("start_head"); }
+    $this->{'part'}  = 'head';
+}
+
+=pod     
+
+=head2 end_head   
+
+Ends a table head.  This corresponds to the
+</thead> closing tag in html/xml.
+
+=cut
+
+sub end_head {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("end_head"); }
+    $this->{'part'} = 'body';
+}
+
+=pod
+
+=head2 start_foot
+
+Starts the table footer.  All of the rows generated in the footer will
+be rendered at the bottom of the table.  This sub corresponds to the
+<tfoot> tag in html/xml.  If the table has group borders enabled, a rule
+will be rendered at the top and bottom of the set of columns in this
+group
+
+=cut
+
+sub start_foot {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("start_foot"); }
+    $this->{'part'}   = 'foot';
+}
+
+=pod
+
+=head2 end_foot
+
+Ends the set of rows in the table footer.  This corresponds to the
+</tfoot> end tag in xml/html.
+
+=cut
+
+sub end_foot {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("end_foot") }
+    $this->{'part'}  = 'body';
+}
+
+=pod
+
+=head2 start_body
+
+Starts the set of rows that will be in the table body.   Note that if
+we are not in the header or footer, body rows are implied.
+This correspondes to the presence of a <tbody> tag in html/xml.
+If group borders are on, a rule will be rendered at the top and bottom
+of the body rows.
+
+=cut
+
+sub start_body {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("start_body"); }
+    $this->{'part'}  = 'body';
+}
+
+=pod
+ 
+=head2 end_body
+
+Ends the set of rows in a table body.  Note that in the event we are not
+in  the header or footer groups this code assumes we are in the body
+group.  I believe this is a good match to how mot browsers render.
+
+=cut
+
+sub end_body {
+    my ($this) = @_;
+    if ($tracing) { &Apache::lonnet::logthis("end_body"); }
+
+}
+
+=pod
+
+=head2 define_colgroup
+
+Define a column group  a column group corresponds to the
+<cgroup> tag in Html/Xml. A column group as we implement it has
+the following properties tht will be shared amongst all cells in the
+columns in the group unless overidden in the specific oell definition:
+
+=over 2
+
+=item span 
+
+The number of columns in the column group.  This defaults to 1.
+
+=item halign
+
+Horizontal alignment of the cells.  This defaults to left.
+Other values are left, center, right (justify and char are 
+accepted but treated as left).
+  
+=item valign
+
+Vertical alignment of the cells.  This defaults to middle.
+Other values are top middle, bottom, (baseline is accepted and
+treated as top).
+
+=back   
+
+If group borders are turned on, a rule will be rendered
+at the left and right side of the column group.
+
+=head3 parameters
+
+=over 2
+
+=item definition
+
+This is a hash that contains any of the keys described above that
+define the column group.
+
+=back
+
+
+=head3 Example
+
+ $table->define_colgroup({
+    'span'    => 2,
+    'halign'  => 'center'
+                         })
+
+
+
+=cut
+
+sub define_colgroup {
+    my ($this, $attributes)  = @_;
+    if ($tracing) { &Apache::lonnet::logthis("col_group"); }
+    
+
+}
 
+#------------------------- Render the table ---------------------
 
 =pod
 
@@ -774,6 +949,7 @@
 The caller can then ask the table object to generate LaTeX.
 
 =cut
+
 sub generate {
     my ($this) = @_;
     my $useP   = 0;
@@ -784,7 +960,14 @@
     if($tracing) {&Apache::lonnet::logthis("generate"); }
     my $table = Apache::lonlatextable->new();
 
+    my $inner_border = $this->{'inner_border'};
+    my $outer_border = $this->{'outer_border'};
+    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;
+    my $part_border   = ($inner_border == 4);
+ 
     # Add the caption if supplied.
 
     if ($this->{'caption'} ne "") {
@@ -848,13 +1031,93 @@
         }
     }
 
-	
+    if ($tracing) { &Apache::lonnet::logthis("rendering head"); }
+    $this->render_part('head', $table, $useP, $default_width);
+    if ($tracing) { &Apache::lonnet::logthis("rendering body"); }
+    $this->render_part('body', $table, $useP, $default_width);
+    if ($tracing) { &Apache::lonnet::logthis("rendering footer"); }
+    $this->render_part('foot', $table, $useP, $default_width);
+
+
+
+
+    
+    my $coldef = "";
+    if ($outer_border || $cell_lr_border) {
+	$coldef .= '|';
+    }
+    for (my $i =0; $i < $column_count; $i++) {
+	if ($useP) {
+	    $coldef .= "p{$default_width $colunits}";
+	} else {
+	    $coldef .= 'l';
+	}
+	if ($cell_lr_border || 
+	    ($outer_border && ($i == $column_count-1))) {
+	    $coldef .= '|';
+	}
+    }
+    $table->{'coldef'} = $coldef;
+
+    # Return the table:
+
+    if ($tracing) { &Apache::lonnet::logthis("Leaving generate"); }
+
+
+    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.
+}
+
+#
+#  Render a part of the table.  The valid table parts are
+#  head, body and foot.  These corresopnd to the set of rows
+#  define within <thead></thead>, <tbody></tbody> and <tfoot></tfoot>
+#  respectively.
+#
+sub render_part {
+    my ($this, $part, $table, $useP, $default_width) = @_;
+
+    if ($tracing) { &Apache::lonnet::logthis("render_part: $part") };
+
+    # Do nothing if that part of the table is empty:
+
+    &Apache::lonnet::logthis(Dumper($this->{'rows'}));
+    if ($this->{'rows'}->{$part} == undef) {
+	if ($tracing) {&Apache::lonnet::logthis("$part is empty"); }
+	return;
+    }
 
 
     # Build up the data:
 
     my @data;
-    my $rows      = $this->{'rows'};
+    my $colwidths        = $this->{'col_widths'};
+    my $rows      = $this->{'rows'}->{$part}; # TODO: Render header, body footer as groups.
     my $row_count = scalar(@$rows);
     my $inner_border = $this->{'inner_border'};
     my $outer_border = $this->{'outer_border'};
@@ -862,10 +1125,14 @@
 
     my $cell_ul_border = (($inner_border == 1) || ($inner_border == 2)) ? 1 : 0;
     my $cell_lr_border = (($inner_border == 1) || ($inner_border == 3)) ? 1 : 0;
- 
+    my $part_border   = ($inner_border == 4);
+    my $colunits    = 'cm';	# All units in cm.
+
     # Add a top line if the outer or inner border is enabled:
+    # or if group rules are on.
+    #
 
-    if ($outer_border || $cell_ul_border) {
+    if ($outer_border || $cell_ul_border || $part_border) {
 	push(@data, ["\\cline{1-$column_count}"]);	     
 
     }
@@ -974,60 +1241,13 @@
     # Add bottom border if necessary: if the inner border was on, the loops above
     # will have done a bottom line under the last cell.
     #
-    if ($outer_border && !$cell_ul_border) {
+    if (($outer_border || $part_border) && !$cell_ul_border) {
 	push(@data, ["\\cline{1-$column_count}"]);	     
 
     }
-    $table->set_data(\@data);
-    
-    my $coldef = "";
-    if ($outer_border || $cell_lr_border) {
-	$coldef .= '|';
-    }
-    for (my $i =0; $i < $column_count; $i++) {
-	if ($useP) {
-	    $coldef .= "p{$default_width $colunits}";
-	} else {
-	    $coldef .= 'l';
-	}
-	if ($cell_lr_border || 
-	    ($outer_border && ($i == $column_count-1))) {
-	    $coldef .= '|';
-	}
-    }
-    $table->{'coldef'} = $coldef;
-
-    # Return the table:
-
-    if ($tracing) { &Apache::lonnet::logthis("Leaving generate"); }
-
-
-    return $table;
-
+    $table->set_data(\@data);    
 }
-#---------------------------------------------------------------------------
-#
-#  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.
 
@@ -1042,7 +1262,7 @@
     my ($self, $row) = @_;
     if ($tracing > 1) { &Apache::lonnet::logthis("get_row"); }
 
-    my $rows = $self->{'rows'};	  # ref to an array....
+    my $rows = $self->{'rows'}->{$self->{'part'}};	  # ref to an array....
     return $rows->[$row];         # ref to the row hash for the selected row.
 }
 
@@ -1052,4 +1272,4 @@
 
 1;
 __END__
- 
+

--foxr1302689287--