File:  [LON-CAPA] / loncom / xml / lontable.pm
Revision 1.10: download - view: text, annotated - select for diffs
Fri Apr 17 20:17:48 2009 UTC (15 years ago) by raeburn
Branches: MAIN
CVS tags: version_2_9_99_0, version_2_9_0, version_2_8_99_1, version_2_8_99_0, bz6209-base, bz6209, bz5969, bz2851, PRINT_INCOMPLETE_base, PRINT_INCOMPLETE, HEAD, GCI_3, GCI_2, BZ5971-printing-apage, BZ5434-fox
- Reversing 1.9 (1/26/2009).
  -  Follow the instructions found at: http://mail.lon-capa.org/pipermail/lon-capa-dev/2009-April/001952.html to update development machines to use LONCAPA-prerequisites 1-13 (which includes the perl-LaTeX-Table dependency).

    1: # The LearningOnline Network with CAPA
    2: #  Generating TeX tables.
    3: #
    4: # $Id: lontable.pm,v 1.10 2009/04/17 20:17:48 raeburn Exp $
    5: # 
    6: #
    7: # Copyright Michigan State University Board of Trustees
    8: #
    9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
   10: #
   11: # LON-CAPA is free software; you can redistribute it and/or modify
   12: # it under the terms of the GNU General Public License as published by
   13: # the Free Software Foundation; either version 2 of the License, or
   14: # (at your option) any later version.
   15: #
   16: # LON-CAPA is distributed in the hope that it will be useful,
   17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19: # GNU General Public License for more details.
   20: #
   21: # You should have received a copy of the GNU General Public License
   22: # along with LON-CAPA; if not, write to the Free Software
   23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   24: #
   25: # /home/httpd/html/adm/gpl.txt
   26: #
   27: # http://www.lon-capa.org/
   28: ## Copyright for TtHfunc and TtMfunc by Ian Hutchinson. 
   29: # TtHfunc and TtMfunc (the "Code") may be compiled and linked into 
   30: # binary executable programs or libraries distributed by the 
   31: # Michigan State University (the "Licensee"), but any binaries so 
   32: # distributed are hereby licensed only for use in the context
   33: # of a program or computational system for which the Licensee is the 
   34: # primary author or distributor, and which performs substantial 
   35: # additional tasks beyond the translation of (La)TeX into HTML.
   36: # The C source of the Code may not be distributed by the Licensee
   37: # to any other parties under any circumstances.
   38: #
   39: 
   40: # This module is a support packkage that helps londefdef generate
   41: # LaTeX tables using the LaTeX::Table package.  A prerequisite is that
   42: # the print generator must have added the following to the LaTeX 
   43: #
   44: #  \usepackage{xtab}
   45: #  \usepackage{booktabs}
   46: #  \usepackage{array}
   47: #  \usepackage{colortbl}
   48: #  \usepackage{xcolor}
   49: #
   50: #  These packages are installed in the packaged LaTeX distributions we know of as of
   51: #  11/24/2008
   52: #
   53: 
   54: 
   55: 
   56: package Apache::lontable;
   57: use strict;
   58: use LaTeX::Table;
   59: use Apache::lonnet;		# for trace logging.
   60: 
   61: my $tracing = 0;		# Set to 1 to enable log tracing. 2 for local sub tracing.
   62: 
   63: =pod
   64: 
   65: =head1  lontable Table generation assistant for the LaTeX target
   66: 
   67: This module contains support software for generating tables in LaTeX output mode 
   68: In this implementation, we use the LaTeX::Table package to do the actual final formatting.
   69: Each table creates a new object.  Table objects can have global properties configured.
   70: The main operations on a table object are:
   71: 
   72: =over 3
   73: 
   74: =item start_row  
   75: 
   76: Opens a new table row.
   77: 
   78: =item end_row
   79: 
   80: Closes a table row.
   81: 
   82: =item configure_row
   83: 
   84: Modifies a configuration item in the currently open row.
   85: 
   86: =item generate
   87: 
   88: Returns the generated table string.
   89: 
   90: =item configure
   91: 
   92: Configures a table's global configuration.
   93: 
   94: =item add_cell
   95: 
   96: Add and configure a cell to the current row.6
   97: 
   98: =back
   99: 
  100: =cut
  101: 
  102: =pod
  103: 
  104: =head2 new - create a new object.
  105: 
  106: Create a new table object.  Any of the raw table configuration items can be
  107: modified by this.  These configuration items include:
  108: 
  109:   my $table = lontable::new(\%config_hash)
  110: 
  111: =over3
  112: 
  113: 
  114: =item alignment
  115: 
  116: Table alignment.  Some table styles support this but not all.
  117: 
  118: =item tableborder
  119: 
  120: If true, a border is drawn around the table.
  121: 
  122: =item cellborder
  123: 
  124: If true, borders are drawn around the cells inside a table.
  125: 
  126: =item caption
  127: 
  128: The table caption text.
  129: 
  130: =item theme
  131: 
  132: The theme of the table to use.  Defaults to Zurich.  Themes we know about are:
  133: NYC, NYC2, Zurich, Berlin, Dresden, Houston, Miami, plain, Paris.  Other themes can be added
  134: to the LaTeX::Table package, and they will become supported automatically, as theme names are
  135: not error checked.  Any use of a non-existent theme is reported by the LaTeX::Table package
  136: when the table text is generated.
  137: 
  138: =item width
  139: 
  140: The width of the table.   in any
  141: TeX unit measure e.g.  10.8cm  This forces the table to the
  142: tabularx environment.  It also forces the declarations for
  143: cells to be paragraph mode which supports more internal formatting.
  144: 
  145: =back
  146: 
  147: =head3 Member data
  148: 
  149: The object hash has the following members:
  150: 
  151: =over 3
  152: 
  153: =item column_count 
  154: 
  155: Maintained internally, the number of colums in the widest row.
  156: 
  157: =item alignment
  158: 
  159: Table alignment (configurable) "left", "center", or "right".
  160: 
  161: =item outer_border
  162: 
  163: True if a border should be drawn around the entire table (configurable)
  164: 
  165: =item inner_borders
  166: 
  167: True if a border should be drawn around all cells (configurable).
  168: 
  169: =item caption
  170: 
  171: Table caption (configurable).
  172: 
  173: =item theme
  174: 
  175: Theme desired (configurable).
  176: 
  177: =item width
  178: 
  179: If defined, the width of the table (should be supplied
  180: in fraction of column width e.g. .75 for 75%.
  181: 
  182: =item row_open 
  183: 
  184: True if a row is open and not yet closed.
  185: 
  186: =item rows
  187: 
  188: Array of row data. This is an array of hashes described below.
  189: 
  190: =back
  191: 
  192: =head3 Row data.
  193: 
  194: Each row of table data is an element of the rows hash array.  Hash elements are
  195: 
  196: =over 3
  197: 
  198: 
  199: =item default_halign 
  200: 0
  201: Default horizontal alignment for cells in this row.
  202: 
  203: =item default_valign
  204: 
  205: Default vertical alignment for cells in this row (may be ignored).
  206: 
  207: =item cell_width
  208:  
  209: The width of the row in cells.  This is the sum of the column spans 
  210: of the cells in the row.
  211: 
  212: =item cells
  213: 
  214: Array of hashes where each element represents the data for a cell.
  215: The contents of each element of this hash are described below:
  216: 
  217: =over 3
  218: 
  219: =item header
  220: 
  221: If present, the row is a 'header' that is it was made via the
  222: <th> tag.
  223: 
  224: =item halign
  225: 
  226: If present, overrides the row default horizontal alignment.
  227: 
  228: =item valign
  229: 
  230: if present, override the row default vertical alignment.
  231: 
  232: =item rowspan
  233: 
  234: If present, indicates the number of rows this cell spans.
  235: 
  236: =item colspan
  237: 
  238: If present indicates the number of columns this cell spans.
  239: Note that a cell can span both rows and columns.
  240: 
  241: =item start_col
  242: 
  243: The starting column of the cell in the table grid.
  244: 
  245: =item contents
  246: 
  247: The contents of the cell.
  248: 
  249: =back
  250: 
  251: =back
  252: 
  253: =cut
  254: 
  255: sub new {
  256:     my ($class, $configuration) = @_;
  257: 
  258:     if($tracing) {&Apache::lonnet::logthis("new table object");}
  259: 
  260:     #  Initialize the object member data with the default values
  261:     #  then override with any stuff in $configuration.
  262: 
  263:     my $self = {
  264: 	alignment      => "left",
  265: 	outer_border   => 0,
  266: 	inner_border  => 0,
  267: 	caption        => "",
  268: 	theme          => "Zurich",
  269: 	column_count   => 0,
  270: 	row_open       => 0,
  271: 	rows           => [],
  272:     };
  273: 
  274:     foreach my $key (keys %$configuration) {
  275: 	$self->{$key} = $$configuration{$key};
  276:     }
  277: 
  278:     bless($self, $class);
  279: 
  280:     return $self;
  281: }
  282: 
  283: 
  284: #-------------------------------------------------------------------------
  285: #
  286: #  Methods that get/set table global configuration.
  287: #
  288: 
  289: =pod
  290: 
  291: =head2 Gets/set alignment.  
  292: 
  293: If the method is passed a new alignment value, that replaces the current one.
  294: Regardless, the current alignment is used:
  295: 
  296: =head3 Examples:
  297: 
  298:  my $align = $table->alignment(); # Return current alignment
  299:  $table->alignment("center");     # Attempt centered alignment.
  300: 
  301: =cut
  302: 
  303: sub alignment {
  304:     my ($self, $new_value) = @_;
  305: 
  306:     if ($tracing) {&Apache::lonnet::logthis("alignment = $new_value");}
  307: 
  308:     if (defined($new_value)) {
  309: 	$self->{'alignment'} = $new_value;
  310:     }
  311:     return $self->{'alignment'};
  312: }
  313: 
  314: =pod
  315: 
  316: =head2 table_border
  317: 
  318: Set or get the presence of an outer border in the table.
  319: If passed a parameter, that parameter replaces the current request
  320: for or not for an outer border. Regardless, the function returns
  321: the final value of the outer_border request.
  322: 
  323: =head3 Examples:
  324: 
  325:   $table->table_border(1);      # Request an outer border.
  326:   my $outer_requested = $table->table_border();
  327: 
  328: =cut
  329: 
  330: sub table_border {
  331:     my ($self, $new_value) = @_;
  332: 
  333:     if ($tracing) {&Apache::lonnet::logthis("table_border $new_value");}
  334: 
  335:     if (defined($new_value)) {
  336: 	$self->{'outer_border'} = $new_value;
  337:     }
  338:     return $self->{'outer_border'};
  339: }
  340: 
  341: 
  342: =pod
  343: 
  344: =head2 cell_border
  345: 
  346: Set or get the presence of a request for cells to have borders
  347: drawn around them.  If a paramter is passed, it will be treated as
  348: a new value for the cell border configuration.  Regardless,the final
  349: value of that configuration parameter is returned.
  350: 
  351: =head3 Examples:
  352: 
  353:  my $cell_border = $table->cell_border(); # ask if cell borders are requested.
  354:  $table->cell_border(1);	# Request cell borders.
  355: 
  356: =cut
  357: 
  358: sub cell_border {
  359:     my ($self, $new_value) = @_;
  360:     if($tracing) {&Apache::lonnet::logthis("cell_border: $new_value"); }
  361:     if (defined($new_value)) {
  362: 	$self->{'inner_border'} = $new_value;
  363:     }
  364:     return $self->{'inner_border'};
  365: }
  366: 
  367: =pod
  368: 
  369: =head2 caption
  370: 
  371: Gets and/or sets the caption string for the table.  The caption string appears to label
  372: the table.  If a parameter is supplied it will become the new caption string.k
  373: 
  374: =head3 Examples:
  375: 
  376: 
  377:   $my caption = $table->caption();
  378:   $table->caption("This is the new table caption");
  379: 
  380: =cut
  381: 
  382: sub caption {
  383:     my ($self, $new_value) = @_;
  384: 
  385:     if($tracing) {&Apache::lonnet::logthis("caption: $new_value"); }
  386:     if (defined($new_value)) {
  387: 	$self->{'caption'} = $new_value;
  388:     }
  389: 
  390:     return $self->{'caption'};
  391: }
  392: 
  393: =pod
  394: 
  395: =head2 theme
  396: 
  397: Gets and optionally sets the table theme.  The table theme describes how the
  398: table will be typset by the table package.  If a parameter is supplied it
  399: will be the new theme selection.
  400: 
  401: =head3 Examples:
  402: 
  403:   my $theme = $table->theme();
  404:   $table->theme("Dresden");
  405: 
  406: =cut
  407: 
  408: sub theme {
  409:     my ($self, $new_value) = @_;
  410:     if($tracing) {&Apache::lonnet::logthis("theme $new_value"); }
  411:     if (defined($new_value)) {
  412: 	$self->{'theme'} = $new_value;
  413:     }
  414:     return $self->{'theme'};
  415: }
  416: 
  417: =pod
  418: 
  419: =head 2 width
  420: 
  421: Gets and optionally sets the width of the table.
  422: 
  423: =head 3 Examples:
  424: 
  425:  my $newwidth = $table->width("10cm");   # 10cm width returns "10cm".
  426: 
  427: =cut
  428: sub width {
  429:     my ($self, $new_value) = @_;
  430:     if($tracing) {&Apache::lonnet::logthis("width = $new_value"); }
  431: 
  432:     if (defined($new_value)) {
  433: 	$self->{'width'} = $new_value;
  434:     }
  435:     return $self->{'width'}; 	# Could be undef.
  436: }
  437: 
  438: =pod
  439: 
  440: =head2 start_row
  441: 
  442: Begins a new row in the table.  If a row is already open, that row is
  443: closed off prior to starting the new row.  Rows can have the following attributes
  444: which are specified by an optional hash passed in to this function.
  445: 
  446: =over 3
  447: 
  448: =item default_halign
  449: 
  450: The default horizontal alignment of the row. This can be "left", "center", or "right"
  451: 
  452: =item default_valign
  453: 
  454: The default vertical alignment of the row.  This can be "top", "center", or "bottom"
  455: 
  456: =back
  457: 
  458: =head3 Examples:
  459: 
  460:   $table_start_row();                  # no attributes.
  461:   $table_start({default_halign => "center",
  462:                 default_valign => "bottom"}); # Create setting the attrbutes.
  463: 
  464: =cut
  465: 
  466: sub start_row {
  467:     my ($self, $config) = @_;
  468:     if($tracing) {&Apache::lonnet::logthis("start_row"); }
  469:     if ($self->{'row_open'}) { 
  470: 	$self->end_row();
  471:     }
  472:     my $row_hash = {
  473: 	default_halign => "left",
  474: 	default_valign => "top",
  475: 	cell_width     =>  0,
  476: 	cells          => []
  477:     };
  478: 
  479:     # Override the defaults if the config hash is present:
  480: 
  481:     if (defined($config)) {
  482: 	foreach my $key  (keys %$config) {
  483: 	    $row_hash->{$key} = $config->{$key};
  484: 	}
  485:     }
  486: 
  487:     
  488:     my $rows = $self->{'rows'};
  489:     push(@$rows, $row_hash);
  490: 
  491:     $self->{"row_open"} = 1;	# Row is now open and ready for business.
  492: }
  493: 
  494: =pod
  495: 
  496: =head2  end_row 
  497: 
  498: Closes off a row.  Once closed, cells cannot be added to this row again.
  499: 
  500: =head3 Examples:
  501: 
  502:    $table->end_row();
  503: 
  504: 
  505: =cut
  506: 
  507: sub end_row {
  508:     my ($self) = @_;
  509:     if($tracing) {&Apache::lonnet::logthis("end_row"); }
  510:     if ($self->{'row_open'}) {
  511: 	
  512: 	# Mostly we need to determine if this row has the maximum
  513: 	# cell count of any row in existence in the table:
  514: 
  515: 	my $row        = $self->{'rows'}->[-1];
  516: 	my $cells      = $row->{'cells'};
  517: 
  518: 	if ($row->{'cell_width'} > $self->{'column_count'}) {
  519: 	    $self->{'column_count'} = $row->{'cell_width'};
  520: 	}
  521: 
  522: 	$self->{'row_open'} = 0;;
  523:     }
  524: }
  525: 
  526: =pod
  527: 
  528: =head2 configure_row
  529: 
  530: Modify the configuration of a row.   If a row is not open, a new one will be opened.
  531: 
  532: =head3 Parameters:
  533: 
  534: config_hash - A hash that contains new values for the set of row confiuguration 
  535: items to be modified.  There is currently no check/penalty for items that are not in
  536: the set of defined configuration properties which are:
  537: 
  538: =over 2
  539: 
  540: =item default_halign
  541: 
  542: The default horizontal alignment for text in  cells in the row.  This can be any of:
  543: "left", "right" or "center".
  544: 
  545: =item default_valign
  546: 
  547: The default vertical alignment for text in cells in the row.  This can be any of:
  548: 
  549: "top", "bottom" or "center"
  550: 
  551: =back 
  552: 
  553: =cut
  554: 
  555: sub configure_row {
  556:     my ($self, $config) = @_;
  557:     if($tracing) {&Apache::lonnet::logthis("configure_row");}
  558:     if (!$self->{'row_open'}) {
  559: 	$self->start_row();
  560:     }
  561:     
  562:     my $row = $self->{'rows'}[-1];
  563:     foreach my $config_item (keys %$config) {
  564: 	$row->{$config_item} = $config->{$config_item};
  565:     }
  566: }
  567: 
  568: 
  569: =pod
  570: 
  571: =head2 add_cell
  572: 
  573: Add a new cell to a row.  If there is a row above us, we need to 
  574: watch out for row spans that may force additional blank cell entries
  575: to fill in the span. 
  576: 
  577: =head3 Parameters:
  578: 
  579: =over 2
  580: 
  581: =item text
  582: 
  583: Text to put in the cell.
  584: 
  585: =item cell_config
  586: 
  587: Hash of configuration options that override the defaults.   The recognized options,
  588: and their defaults are:
  589: 
  590: =over 2
  591: 
  592: =item halign 
  593: 
  594: If nonblank overrides the row's default for the cell's horizontal alignment.
  595: 
  596: =item valign
  597: 
  598: If nonblank, overrides the row's default for the cdell's vertical alignment.
  599: 
  600: =item rowspan
  601: 
  602: Number of rows the cell spans.
  603: 
  604: =item colspan
  605: 
  606: Number of columns the cell spans.
  607: 
  608: =back
  609: 
  610: =cut
  611: 
  612: sub add_cell {
  613:     my ($self, $text, $config) = @_;
  614: 
  615:     if($tracing) {&Apache::lonnet::logthis("add_cell : $text"); }
  616: 
  617:     # If a row is not open, we must open it:
  618: 
  619:     if (!$self->{'row_open'}) {
  620: 	$self->start_row();
  621:     }
  622:     my $rows          = $self->{'rows'};
  623:     my $current_row   = $rows->[-1];
  624:     my $current_cells = $current_row->{'cells'}; 
  625:     my $last_coord    = $current_row->{'cell_width'};
  626: 
  627:     #  We have to worry about row spans if there is a prior row:
  628: 
  629:     if (scalar(@$rows) > 1) {
  630: 
  631: 	my $last_row = $rows->[-2];
  632: 	if ($last_coord < $last_row->{'cell_width'}) {
  633: 	    my $prior_coord       = 0;
  634: 	    my $prior_cell_index  = 0;
  635: 	    while ($prior_coord <= $last_coord) {
  636: 		
  637: 		# Pull a cell down if it's coord matches our start coord
  638: 		# And there's a row span > 1.
  639: 		# Having done so, we adjust our $last_coord to match the
  640: 		# end point of the pulled down cell.
  641: 
  642: 		my $prior_cell = $last_row->{'cells'}->[$prior_cell_index];
  643: 		if (!defined($prior_cell)) {
  644: 		    last;
  645: 		}
  646: 		if (($prior_cell->{'start_col'} == $last_coord) &&
  647: 		    ($prior_cell->{'rowspan'}  > 1)) {
  648: 		    
  649: 		    #  Need to drop the cell down
  650: 
  651: 		    my %dropped_down_cell = %$prior_cell;
  652: 		    $dropped_down_cell{'rowspan'}--;
  653: 		    $dropped_down_cell{'contents'} = '';
  654: 
  655: 		    push(@$current_cells, \%dropped_down_cell);
  656: 		    $last_coord += $dropped_down_cell{'colspan'};
  657: 		    $current_row->{'cell_width'} = $last_coord;
  658: 		    
  659: 		}
  660: 		$prior_coord += $prior_cell->{'colspan'};
  661: 		$prior_cell_index++;
  662: 	    }
  663: 	}
  664: 
  665:     }
  666: 
  667:     #
  668:     # Now we're ready to build up our cell:
  669: 
  670:     my $cell = {
  671: 	rowspan    => 1,
  672: 	colspan    => 1,
  673: 	start_col  => $last_coord,
  674: 	contents   => $text
  675:     };
  676:     
  677:     if (defined($config)) {
  678: 	foreach my $key (keys(%$config)) {
  679: 	    $cell->{$key} = $config->{$key};
  680: 	}
  681:     }
  682:     $current_row->{'cell_width'} += $cell->{'colspan'};
  683: 
  684:     push(@$current_cells, $cell);
  685: 
  686:     if ($tracing) { &Apache::lonnet::logthis("add_cell done"); }
  687: }
  688: 
  689: 
  690: =pod
  691: 
  692: =head2  append_cell_text
  693: 
  694: Sometimes it's necessary to create/configure the cell and then later add text to it.
  695: This sub allows text to be appended to the most recently created cell.
  696: 
  697: =head3 Parameters
  698: 
  699: The text to add to the cell.
  700: 
  701: =cut
  702: sub append_cell_text {
  703:     my ($this, $text) = @_;
  704: 
  705:     if($tracing) {&Apache::lonnet::logthis("append_cell_text: $text"); }
  706:     my $rows         = $this->{'rows'};
  707:     my $current_row  = $rows->[-1];
  708:     my $cells        = $current_row->{'cells'};
  709:     my $current_cell = $cells->[-1];
  710:     $current_cell->{'contents'} .= $text;
  711:     
  712: }
  713: 
  714: 
  715: =pod
  716: 
  717: =head2 generate
  718: 
  719: Call this when the structures for the table have been built.
  720: This will generate and return the table object that can be used
  721: to generate the table.  Returning the table object allows for
  722: a certain amount of testing to be done on the generated table.
  723: The caller can then ask the table object to generate LaTeX.
  724: 
  725: =cut
  726: sub generate {
  727:     my ($this) = @_;
  728:     my $useP   = 0;
  729:     my $colwidth;
  730:     my $colunits;
  731: 
  732:     if($tracing) {&Apache::lonnet::logthis("generate"); }
  733:     my $table = LaTeX::Table->new();
  734:     $table->set_center(0);	# loncapa tables don't float.
  735:     $table->set_environment(0);
  736: 
  737: 
  738:     # Add the caption if supplied.
  739: 
  740:     if ($this->{'caption'} ne "") {
  741: 	$table->set_caption($this->caption);
  742:     }
  743:     
  744:     # Set the width if defined:
  745: 
  746:     if (defined ($this->{'width'})) {
  747: #	$table->set_width($this->{'width'});
  748: #	$table->set_width_environment('tabularx');
  749: 	$useP = 1;
  750: 	($colwidth, $colunits) = split(/ /, $this->{'width'});
  751: 	$colwidth = $colwidth/$this->{'column_count'};
  752: 
  753:     }
  754: 
  755:     # Build up the data:
  756: 
  757:     my @data;
  758:     my $rows      = $this->{'rows'};
  759:     my $row_count = scalar(@$rows);
  760:     my $inner_border = $this->{'inner_border'};
  761:     my $outer_border = $this->{'outer_border'};
  762:     my $column_count = $this->{'column_count'};
  763: 
  764:     for (my $row = 0; $row < $row_count; $row++) {
  765: 	my @row;
  766: 	my $cells      = $rows->[$row]->{'cells'};
  767: 	my $def_halign = $rows->[$row]->{'default_halign'};
  768: 	my $cell_count = scalar(@$cells);
  769: 	my $startcol   = 1;
  770: 	my @underlines;		# Array of \cline cells if cellborder on.
  771: 
  772: 
  773: 	for (my $cell  = 0; $cell < $cell_count; $cell++) {
  774: 	    my $contents = $cells->[$cell]->{'contents'};
  775: 
  776: 	    #
  777: 	    #  Cell alignment is the default alignment unless
  778: 	    #  explicitly specified in the cell.
  779: 	    #  NOTE: at this point I don't know how to do vert alignment.
  780: 	    #
  781: 
  782: 	    my $halign   = $def_halign;
  783: 	    if (defined ($cells->[$cell]->{'halign'})) {
  784: 		$halign = $cells->[$cell]->{'halign'};
  785: 	    }
  786: 
  787: 	    # Create the horizontal alignment character:
  788: 
  789: 	    my $col_align = 'l';
  790: 	    my $embeddedAlignStart = "";
  791: 	    my $embeddedAlignEnd   = "";
  792: 
  793: 	    if ($halign eq 'right') {
  794: 		$col_align = 'r';
  795: 		$embeddedAlignStart = '\begin{flushright} ';
  796: 		$embeddedAlignEnd   = ' \end{flushright}';
  797: 	    }
  798: 	    if ($halign eq 'center') {
  799: 		$col_align = 'c';
  800: 		$embeddedAlignStart = '\begin{center}';
  801: 		$embeddedAlignEnd   = '\end{center}';
  802: 	    }
  803: 
  804: 	    # If the width has been specified, turn these into
  805: 	    # para mode; and wrap the contents in the start/stop stuff:
  806: 
  807: 	    if ($useP) {
  808: 		my $cw = $colwidth * $cells->[$cell]->{'colspan'};
  809: 		$col_align = "p{$cw $colunits}";
  810: 		$contents = $embeddedAlignStart . $contents .  $embeddedAlignEnd;
  811: 	    }
  812: 
  813: 	    if ($inner_border || ($outer_border && ($cell == 0))) {
  814: 		$col_align = '|'.$col_align;
  815: 	    }
  816: 	    if ($inner_border || ($outer_border && ($cell == ($cell_count -1)))) {
  817: 		$col_align = $col_align.'|';
  818: 	    }
  819: 
  820: 	    #factor in spans:
  821: 
  822: 	    my $cspan    = $cells->[$cell]->{'colspan'};
  823: 	    my $nextcol  = $startcol + $cspan;
  824: 
  825: 	    # If we can avoid the \multicolumn directive that's best as
  826: 	    # that makes some things like \parpic invalid in LaTeX which
  827:             # screws everything up.
  828: 
  829: 	    if (($cspan > 1) || !($col_align =~ /l/)) {
  830: 
  831: 		$contents = '\multicolumn{'.$cspan.'}{'.$col_align.'}{'.$contents.'}';
  832: 
  833: 		# A nasty edge case.  If there's only one cell, the software will assume
  834: 		# we're in complete control of the row so we need to end the row ourselves.
  835: 		
  836: 		if ($cell_count == 1) {
  837: 		    $contents .= '  \\\\';
  838: 		}
  839: 	    }
  840: 	    if ($inner_border && ($cells->[$cell]->{'rowspan'} == 1)) {
  841: 		my $lastcol = $nextcol -1;
  842: 		push(@underlines, "\\cline{$startcol-$lastcol}");
  843: 	    }
  844: 	    $startcol = $nextcol;
  845: 	    # Rowspans should take care of themselves.
  846: 	    
  847: 	    push(@row, $contents);
  848: 
  849: 	}
  850: 	push(@data, \@row);
  851: 	if ($inner_border) {
  852: 	    for (my $i =0; $i < scalar(@underlines); $i++) {
  853: 		push(@data, [$underlines[$i]]);
  854: 	    }
  855: 	}
  856: 
  857:     }
  858:     $table->set_data(\@data);
  859:     
  860:     my $coldef = "";
  861:     if ($outer_border || $inner_border) {
  862: 	$coldef .= '|';
  863:     }
  864:     for (my $i =0; $i < $column_count; $i++) {
  865: 	if ($useP) {
  866: 	    $coldef .= "p{$colwidth $colunits}";
  867: 	} else {
  868: 	    $coldef .= 'l';
  869: 	}
  870: 	if ($inner_border || 
  871: 	    ($outer_border && ($i == $column_count-1))) {
  872: 	    $coldef .= '|';
  873: 	}
  874:     }
  875:     $table->{'coldef'} = $coldef;
  876: 
  877:     # Return the table:
  878: 
  879:     if ($tracing) { &Apache::lonnet::logthis("Leaving generate"); }
  880: 
  881:     return $table;
  882: 
  883: }
  884: #----------------------------------------------------------------------------
  885: # The following methods allow for testability.
  886: 
  887: 
  888: sub get_object_attribute {
  889:     my ($self, $attribute) = @_;
  890:     if ($tracing > 1) { &Apache::lonnet::logthis("get_object_attribute: $attribute"); }
  891:     return $self->{$attribute};
  892: }
  893: 
  894: sub get_row {
  895:     my ($self, $row) = @_;
  896:     if ($tracing > 1) { &Apache::lonnet::logthis("get_row"); }
  897: 
  898:     my $rows = $self->{'rows'};	  # ref to an array....
  899:     return $rows->[$row];         # ref to the row hash for the selected row.
  900: }
  901: #   Mandatory initialization.
  902: BEGIN{
  903: }
  904: 
  905: 1;
  906: __END__

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