Annotation of loncom/xml/lontable.pm, revision 1.7

1.1       foxr        1: # The LearningOnline Network with CAPA
                      2: #  Generating TeX tables.
                      3: #
1.7     ! foxr        4: # $Id: lontable.pm,v 1.6 2008/12/23 11:49:32 foxr Exp $
1.1       foxr        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
1.5       foxr       42: # the print generator must have added the following to the LaTeX 
1.1       foxr       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: 
                     60: 
                     61: =pod
                     62: 
                     63: =head1  lontable Table generation assistant for the LaTeX target
                     64: 
                     65: This module contains support software for generating tables in LaTeX output mode 
                     66: In this implementation, we use the LaTeX::Table package to do the actual final formatting.
                     67: Each table creates a new object.  Table objects can have global properties configured.
                     68: The main operations on a table object are:
                     69: 
                     70: =over 3
                     71: 
                     72: =item start_row  
                     73: 
                     74: Opens a new table row.
                     75: 
                     76: =item end_row
                     77: 
                     78: Closes a table row.
                     79: 
                     80: =item configure_row
                     81: 
                     82: Modifies a configuration item in the currently open row.
                     83: 
                     84: =item generate
                     85: 
                     86: Returns the generated table string.
                     87: 
                     88: =item configure
                     89: 
                     90: Configures a table's global configuration.
                     91: 
1.3       foxr       92: =item add_cell
                     93: 
                     94: Add and configure a cell to the current row.6
                     95: 
1.1       foxr       96: =back
                     97: 
                     98: =cut
                     99: 
                    100: =pod
                    101: 
                    102: =head2 new - create a new object.
                    103: 
                    104: Create a new table object.  Any of the raw table configuration items can be
                    105: modified by this.  These configuration items include:
                    106: 
                    107:   my $table = lontable::new(\%config_hash)
                    108: 
                    109: =over3
                    110: 
1.7     ! foxr      111: 
1.1       foxr      112: =item alignment
                    113: 
                    114: Table alignment.  Some table styles support this but not all.
                    115: 
                    116: =item tableborder
                    117: 
                    118: If true, a border is drawn around the table.
                    119: 
                    120: =item cellborder
                    121: 
                    122: If true, borders are drawn around the cells inside a table.
                    123: 
                    124: =item caption
                    125: 
                    126: The table caption text.
                    127: 
                    128: =item theme
                    129: 
                    130: The theme of the table to use.  Defaults to Zurich.  Themes we know about are:
                    131: NYC, NYC2, Zurich, Berlin, Dresden, Houston, Miami, plain, Paris.  Other themes can be added
                    132: to the LaTeX::Table package, and they will become supported automatically, as theme names are
                    133: not error checked.  Any use of a non-existent theme is reported by the LaTeX::Table package
                    134: when the table text is generated.
                    135: 
1.7     ! foxr      136: =item width
        !           137: 
        !           138: The width of the table.  This can be expressed as fractions of full width, or in any
        !           139: TeX unit measure e.g. 0.75 for 75% of the width, or 10.8cm  This forces the table to the
        !           140: tabularx environment.
        !           141: 
1.1       foxr      142: =back
                    143: 
                    144: =head3 Member data
                    145: 
                    146: The object hash has the following members:
                    147: 
                    148: =over 3
                    149: 
                    150: =item column_count 
                    151: 
                    152: Maintained internally, the number of colums in the widest row.
                    153: 
                    154: =item alignment
                    155: 
                    156: Table alignment (configurable) "left", "center", or "right".
                    157: 
                    158: =item outer_border
                    159: 
                    160: True if a border should be drawn around the entire table (configurable)
                    161: 
                    162: =item inner_borders
                    163: 
                    164: True if a border should be drawn around all cells (configurable).
                    165: 
                    166: =item caption
                    167: 
                    168: Table caption (configurable).
                    169: 
                    170: =item theme
                    171: 
                    172: Theme desired (configurable).
                    173: 
1.6       foxr      174: =item width
                    175: 
                    176: If defined, the width of the table (should be supplied
                    177: in fraction of column width e.g. .75 for 75%.
                    178: 
1.1       foxr      179: =item row_open 
                    180: 
                    181: True if a row is open and not yet closed.
                    182: 
                    183: =item rows
                    184: 
                    185: Array of row data. This is an array of hashes described below.
                    186: 
                    187: =back
                    188: 
                    189: =head3 Row data.
                    190: 
                    191: Each row of table data is an element of the rows hash array.  Hash elements are
                    192: 
                    193: =over 3
                    194: 
                    195: 
                    196: =item default_halign 
1.3       foxr      197: 0
1.1       foxr      198: Default horizontal alignment for cells in this row.
                    199: 
                    200: =item default_valign
                    201: 
                    202: Default vertical alignment for cells in this row (may be ignored).
                    203: 
1.6       foxr      204: =item cell_width
                    205:  
                    206: The width of the row in cells.  This is the sum of the column spans 
                    207: of the cells in the row.
                    208: 
1.1       foxr      209: =item cells
                    210: 
                    211: Array of hashes where each element represents the data for a cell.
                    212: The contents of each element of this hash are described below:
                    213: 
                    214: =over 3
                    215: 
1.3       foxr      216: =item header
                    217: 
                    218: If present, the row is a 'header' that is it was made via the
                    219: <th> tag.
                    220: 
1.1       foxr      221: =item halign
                    222: 
                    223: If present, overrides the row default horizontal alignment.
                    224: 
                    225: =item valign
                    226: 
                    227: if present, override the row default vertical alignment.
                    228: 
                    229: =item rowspan
                    230: 
                    231: If present, indicates the number of rows this cell spans.
                    232: 
                    233: =item colspan
                    234: 
                    235: If present indicates the number of columns this cell spans.
                    236: Note that a cell can span both rows and columns.
                    237: 
1.6       foxr      238: =item start_col
                    239: 
                    240: The starting column of the cell in the table grid.
                    241: 
1.1       foxr      242: =item contents
                    243: 
                    244: The contents of the cell.
                    245: 
                    246: =back
                    247: 
                    248: =back
                    249: 
                    250: =cut
                    251: 
                    252: sub new {
                    253:     my ($class, $configuration) = @_;
                    254: 
                    255:     #  Initialize the object member data with the default values
                    256:     #  then override with any stuff in $configuration.
                    257: 
                    258:     my $self = {
                    259: 	alignment      => "left",
                    260: 	outer_border   => 0,
1.2       foxr      261: 	inner_border  => 0,
1.1       foxr      262: 	caption        => "",
                    263: 	theme          => "Zurich",
                    264: 	column_count   => 0,
                    265: 	row_open       => 0,
                    266: 	rows           => [],
                    267:     };
                    268: 
                    269:     foreach my $key (keys %$configuration) {
                    270: 	$self->{$key} = $$configuration{$key};
                    271:     }
                    272: 
                    273:     bless($self, $class);
                    274: 
                    275:     return $self;
                    276: }
                    277: 
1.3       foxr      278: 
1.1       foxr      279: #-------------------------------------------------------------------------
                    280: #
                    281: #  Methods that get/set table global configuration.
1.2       foxr      282: #
                    283: 
                    284: =pod
                    285: 
                    286: =head2 Gets/set alignment.  
                    287: 
                    288: If the method is passed a new alignment value, that replaces the current one.
                    289: Regardless, the current alignment is used:
                    290: 
                    291: =head3 Examples:
                    292: 
                    293:  my $align = $table->alignment(); # Return current alignment
                    294:  $table->alignment("center");     # Attempt centered alignment.
                    295: 
                    296: =cut
                    297: 
                    298: sub alignment {
                    299:     my ($self, $new_value) = @_;
                    300: 
                    301:     if (defined($new_value)) {
1.5       foxr      302: 	$self->{'alignment'} = $new_value;
1.2       foxr      303:     }
1.5       foxr      304:     return $self->{'alignment'};
1.2       foxr      305: }
                    306: 
                    307: =pod
                    308: 
                    309: =head2 table_border
                    310: 
                    311: Set or get the presence of an outer border in the table.
                    312: If passed a parameter, that parameter replaces the current request
                    313: for or not for an outer border. Regardless, the function returns
                    314: the final value of the outer_border request.
                    315: 
                    316: =head3 Examples:
                    317: 
                    318:   $table->table_border(1);      # Request an outer border.
                    319:   my $outer_requested = $table->table_border();
                    320: 
                    321: =cut
                    322: 
                    323: sub table_border {
                    324:     my ($self, $new_value) = @_;
                    325: 
                    326:     if (defined($new_value)) {
1.5       foxr      327: 	$self->{'outer_border'} = $new_value;
1.2       foxr      328:     }
1.5       foxr      329:     return $self->{'outer_border'};
1.2       foxr      330: }
                    331: 
                    332: 
                    333: =pod
                    334: 
                    335: =head2 cell_border
                    336: 
                    337: Set or get the presence of a request for cells to have borders
                    338: drawn around them.  If a paramter is passed, it will be treated as
                    339: a new value for the cell border configuration.  Regardless,the final
                    340: value of that configuration parameter is returned.
                    341: 
                    342: =head3 Examples:
                    343: 
1.4       foxr      344:  my $cell_border = $table->cell_border(); # ask if cell borders are requested.
1.2       foxr      345:  $table->cell_border(1);	# Request cell borders.
                    346: 
                    347: =cut
                    348: 
1.4       foxr      349: sub cell_border {
1.2       foxr      350:     my ($self, $new_value) = @_;
                    351: 
                    352:     if (defined($new_value)) {
1.5       foxr      353: 	$self->{'inner_border'} = $new_value;
1.2       foxr      354:     }
1.5       foxr      355:     return $self->{'inner_border'};
1.2       foxr      356: }
                    357: 
                    358: =pod
                    359: 
                    360: =head2 caption
                    361: 
                    362: Gets and/or sets the caption string for the table.  The caption string appears to label
                    363: the table.  If a parameter is supplied it will become the new caption string.k
                    364: 
                    365: =head3 Examples:
                    366: 
                    367: 
                    368:   $my caption = $table->caption();
                    369:   $table->caption("This is the new table caption");
                    370: 
                    371: =cut
                    372: 
                    373: sub caption {
                    374:     my ($self, $new_value) = @_;
                    375: 
                    376:     if (defined($new_value)) {
1.5       foxr      377: 	$self->{'caption'} = $new_value;
1.2       foxr      378:     }
                    379: 
1.5       foxr      380:     return $self->{'caption'};
1.2       foxr      381: }
                    382: 
                    383: =pod
                    384: 
                    385: =head2 theme
                    386: 
                    387: Gets and optionally sets the table theme.  The table theme describes how the
                    388: table will be typset by the table package.  If a parameter is supplied it
                    389: will be the new theme selection.
                    390: 
                    391: =head3 Examples:
1.1       foxr      392: 
1.2       foxr      393:   my $theme = $table->theme();
                    394:   $table->theme("Dresden");
                    395: 
                    396: =cut
                    397: 
                    398: sub theme {
                    399:     my ($self, $new_value) = @_;
                    400: 
                    401:     if (defined($new_value)) {
1.5       foxr      402: 	$self->{'theme'} = $new_value;
1.2       foxr      403:     }
1.5       foxr      404:     return $self->{'theme'};
1.2       foxr      405: }
                    406: 
                    407: =pod
                    408: 
1.7     ! foxr      409: =head 2 width
        !           410: 
        !           411: Gets and optionally sets the width of the table.
        !           412: 
        !           413: =head 3 Examples:
        !           414: 
        !           415:  $table->width("0.8");    # 80% of the column width.
        !           416:  my $newwidth = $table->width("10cm");   # 10cm width returns "10cm".
        !           417: 
        !           418: =cut
        !           419: sub width {
        !           420:     my ($self, $new_value) = @_;
        !           421:     if (defined($new_value)) {
        !           422: 	$self->{'width'} = $new_value;
        !           423:     }
        !           424:     return $self->{'width'}; 	# Could be undef.
        !           425: }
        !           426: 
        !           427: =pod
        !           428: 
1.2       foxr      429: =head2 start_row
                    430: 
                    431: Begins a new row in the table.  If a row is already open, that row is
                    432: closed off prior to starting the new row.  Rows can have the following attributes
                    433: which are specified by an optional hash passed in to this function.
                    434: 
                    435: =over 3
                    436: 
                    437: =item default_halign
                    438: 
                    439: The default horizontal alignment of the row. This can be "left", "center", or "right"
                    440: 
                    441: =item default_valign
                    442: 
                    443: The default vertical alignment of the row.  This can be "top", "center", or "bottom"
                    444: 
                    445: =back
                    446: 
                    447: =head3 Examples:
                    448: 
                    449:   $table_start_row();                  # no attributes.
                    450:   $table_start({default_halign => "center",
                    451:                 default_valign => "bottom"}); # Create setting the attrbutes.
                    452: 
                    453: =cut
                    454: 
                    455: sub start_row {
1.5       foxr      456:     my ($self, $config) = @_;
1.2       foxr      457: 
1.5       foxr      458:     if ($self->{'row_open'}) { 
1.4       foxr      459: 	$self->end_row();
1.2       foxr      460:     }
                    461:     my $row_hash = {
                    462: 	default_halign => "left",
                    463: 	default_valign => "top",
1.6       foxr      464: 	cell_width     =>  0,
1.2       foxr      465: 	cells          => []
                    466:     };
                    467: 
                    468:     # Override the defaults if the config hash is present:
                    469: 
1.5       foxr      470:     if (defined($config)) {
                    471: 	foreach my $key  (keys %$config) {
                    472: 	    $row_hash->{$key} = $config->{$key};
1.2       foxr      473: 	}
                    474:     }
1.5       foxr      475: 
1.2       foxr      476:     
1.5       foxr      477:     my $rows = $self->{'rows'};
1.2       foxr      478:     push(@$rows, $row_hash);
                    479: 
1.5       foxr      480:     $self->{"row_open"} = 1;	# Row is now open and ready for business.
1.2       foxr      481: }
                    482: 
                    483: =pod
                    484: 
                    485: =head2  end_row 
                    486: 
                    487: Closes off a row.  Once closed, cells cannot be added to this row again.
                    488: 
                    489: =head3 Examples:
                    490: 
1.4       foxr      491:    $table->end_row();
1.2       foxr      492: 
                    493: 
                    494: =cut
                    495: 
1.4       foxr      496: sub end_row {
1.2       foxr      497:     my ($self) = @_;
                    498: 
1.5       foxr      499:     if ($self->{'row_open'}) {
1.2       foxr      500: 	
                    501: 	# Mostly we need to determine if this row has the maximum
                    502: 	# cell count of any row in existence in the table:
                    503: 
1.6       foxr      504: 	my $row        = $self->{'rows'}->[-1];
1.5       foxr      505: 	my $cells      = $row->{'cells'};
1.3       foxr      506: 
1.6       foxr      507: 	if ($row->{'cell_width'} > $self->{'column_count'}) {
                    508: 	    $self->{'column_count'} = $row->{'cell_width'};
1.2       foxr      509: 	}
                    510: 
1.5       foxr      511: 	$self->{'row_open'} = 0;;
1.2       foxr      512:     }
                    513: }
                    514: 
                    515: =pod
                    516: 
1.3       foxr      517: =head2 configure_row
                    518: 
                    519: Modify the configuration of a row.   If a row is not open, a new one will be opened.
                    520: 
                    521: =head3 Parameters:
1.2       foxr      522: 
1.3       foxr      523: config_hash - A hash that contains new values for the set of row confiuguration 
                    524: items to be modified.  There is currently no check/penalty for items that are not in
                    525: the set of defined configuration properties which are:
1.2       foxr      526: 
1.3       foxr      527: =over 2
                    528: 
                    529: =item default_halign
                    530: 
                    531: The default horizontal alignment for text in  cells in the row.  This can be any of:
                    532: "left", "right" or "center".
                    533: 
                    534: =item default_valign
                    535: 
                    536: The default vertical alignment for text in cells in the row.  This can be any of:
                    537: 
                    538: "top", "bottom" or "center"
                    539: 
                    540: =back 
1.2       foxr      541: 
                    542: =cut
                    543: 
1.3       foxr      544: sub configure_row {
                    545:     my ($self, $config) = @_;
1.2       foxr      546: 
1.5       foxr      547:     if (!$self->{'row_open'}) {
1.3       foxr      548: 	$self->start_row();
                    549:     }
                    550:     
1.5       foxr      551:     my $row = $self->{'rows'}[-1];
1.3       foxr      552:     foreach my $config_item (keys %$config) {
                    553: 	$row->{$config_item} = $config->{$config_item};
                    554:     }
1.2       foxr      555: }
1.1       foxr      556: 
                    557: 
1.3       foxr      558: =pod
                    559: 
                    560: =head2 add_cell
                    561: 
                    562: Add a new cell to a row.  If there is a row above us, we need to 
                    563: watch out for row spans that may force additional blank cell entries
                    564: to fill in the span. 
                    565: 
                    566: =head3 Parameters:
                    567: 
                    568: =over 2
                    569: 
                    570: =item text
                    571: 
                    572: Text to put in the cell.
                    573: 
                    574: =item cell_config
                    575: 
                    576: Hash of configuration options that override the defaults.   The recognized options,
                    577: and their defaults are:
                    578: 
                    579: =over 2
                    580: 
                    581: =item halign 
                    582: 
                    583: If nonblank overrides the row's default for the cell's horizontal alignment.
                    584: 
                    585: =item valign
                    586: 
                    587: If nonblank, overrides the row's default for the cdell's vertical alignment.
                    588: 
                    589: =item rowspan
                    590: 
                    591: Number of rows the cell spans.
                    592: 
                    593: =item colspan
                    594: 
                    595: Number of columns the cell spans.
                    596: 
                    597: =back
                    598: 
                    599: =cut
                    600: 
                    601: sub add_cell {
                    602:     my ($self, $text, $config) = @_;
                    603: 
                    604:     # If a row is not open, we must open it:
                    605: 
1.5       foxr      606:     if (!$self->{'row_open'}) {
1.3       foxr      607: 	$self->start_row();
                    608:     }
1.6       foxr      609:     my $rows          = $self->{'rows'};
                    610:     my $current_row   = $rows->[-1];
1.5       foxr      611:     my $current_cells = $current_row->{'cells'}; 
1.6       foxr      612:     my $last_coord    = $current_row->{'cell_width'};
1.3       foxr      613: 
1.6       foxr      614:     #  We have to worry about row spans if there is a prior row:
1.3       foxr      615: 
1.6       foxr      616:     if (scalar(@$rows) > 1) {
1.3       foxr      617: 
1.6       foxr      618: 	my $last_row = $rows->[-2];
                    619: 	if ($last_coord < $last_row->{'cell_width'}) {
                    620: 	    my $prior_coord       = 0;
                    621: 	    my $prior_cell_index  = 0;
                    622: 	    while ($prior_coord <= $last_coord) {
                    623: 		
                    624: 		# Pull a cell down if it's coord matches our start coord
                    625: 		# And there's a row span > 1.
                    626: 		# Having done so, we adjust our $last_coord to match the
                    627: 		# end point of the pulled down cell.
                    628: 
                    629: 		my $prior_cell = $last_row->{'cells'}->[$prior_cell_index];
                    630: 		if (($prior_cell->{'start_col'} == $last_coord) &&
                    631: 		    ($prior_cell->{'rowspan'}  > 1)) {
                    632: 		    
                    633: 		    #  Need to drop the cell down
                    634: 
                    635: 		    my %dropped_down_cell = %$prior_cell;
                    636: 		    $dropped_down_cell{'rowspan'}--;
                    637: 		    $dropped_down_cell{'contents'} = '';
                    638: 
                    639: 		    push(@$current_cells, \%dropped_down_cell);
                    640: 		    $last_coord += $dropped_down_cell{'colspan'};
                    641: 		    $current_row->{'cell_width'} = $last_coord;
                    642: 		    
                    643: 		}
                    644: 		$prior_coord += $prior_cell->{'colspan'};
                    645: 		$prior_cell_index++;
                    646: 	    }
1.3       foxr      647: 	}
1.6       foxr      648: 
1.3       foxr      649:     }
1.6       foxr      650: 
1.3       foxr      651:     #
                    652:     # Now we're ready to build up our cell:
                    653: 
                    654:     my $cell = {
                    655: 	rowspan    => 1,
                    656: 	colspan    => 1,
1.6       foxr      657: 	start_col  => $last_coord,
1.3       foxr      658: 	contents   => $text
                    659:     };
                    660:     
                    661:     if (defined($config)) {
                    662: 	foreach my $key (keys(%$config)) {
                    663: 	    $cell->{$key} = $config->{$key};
                    664: 	}
                    665:     }
1.6       foxr      666:     $current_row->{'cell_width'} += $cell->{'colspan'};
                    667: 
1.3       foxr      668:     push(@$current_cells, $cell);
                    669: }
                    670: 
1.6       foxr      671: =pod
                    672: 
                    673: =head2 generate
                    674: 
                    675: Call this when the structures for the table have been built.
                    676: This will generate and return the table object that can be used
                    677: to generate the table.  Returning the table object allows for
                    678: a certain amount of testing to be done on the generated table.
                    679: The caller can then ask the table object to generate LaTeX.
                    680: 
                    681: =cut
                    682: sub generate {
                    683:     my ($this) = @_;
                    684: 
                    685:     my $table = LaTeX::Table->new();
                    686: 
1.7     ! foxr      687:     # Add the caption if supplied.
        !           688: 
        !           689:     if ($this->{'caption'} ne "") {
        !           690: 	$table->set_caption($this->caption);
        !           691:     }
        !           692: 
        !           693:     
        !           694:     # Set the width if defined:
        !           695: 
        !           696:     if (defined ($this->{'width'})) {
        !           697: 	$table->set_width($this->{'width'});
        !           698: 	$table->set_width_environment('tabularx');
        !           699:     }
        !           700: 
1.6       foxr      701:     # Build up the data:
                    702: 
                    703:     my @data;
                    704:     my $rows      = $this->{'rows'};
                    705:     my $row_count = scalar(@$rows);
                    706:     my $inner_border = $this->{'inner_border'};
                    707:     my $outer_border = $this->{'outer_border'};
                    708:     my $column_count = $this->{'column_count'};
                    709: 
                    710:     for (my $row = 0; $row < $row_count; $row++) {
                    711: 	my @row;
                    712: 	my $cells      = $rows->[$row]->{'cells'};
1.7     ! foxr      713: 	my $def_halign = $rows->[$row]->{'default_halign'};
1.6       foxr      714: 	my $cell_count = scalar(@$cells);
                    715: 	my $startcol   = 1;
                    716: 	my @underlines;		# Array of \cline cells if cellborder on.
                    717: 
                    718: 	for (my $cell  = 0; $cell < $cell_count; $cell++) {
                    719: 	    my $contents = $cells->[$cell]->{'contents'};
1.7     ! foxr      720: 
        !           721: 	    #
        !           722: 	    #  Cell alignment is the default alignment unless
        !           723: 	    #  explicitly specified in the cell.
        !           724: 	    #  NOTE: at this point I don't know how to do vert alignment.
        !           725: 	    #
        !           726: 
        !           727: 	    my $halign   = $def_halign;
        !           728: 	    if (defined ($cells->[$cell]->{'halign'})) {
        !           729: 		$halign = $cells->[$cell]->{'halign'};
        !           730: 	    }
        !           731: 
        !           732: 	    # Create the horizontal alignment character:
        !           733: 
        !           734: 	    my $col_align = 'l';
        !           735: 	    if ($halign eq 'right') {
        !           736: 		$col_align = 'r';
        !           737: 	    }
        !           738: 	    if ($halign eq 'center') {
        !           739: 		$col_align = 'c';
        !           740: 	    }
        !           741: 	    if ($inner_border || ($outer_border && ($cell == 0))) {
        !           742: 		$col_align = '|'.$col_align;
        !           743: 	    }
        !           744: 	    if ($inner_border || ($outer_border && ($cell == ($cell_count -1)))) {
        !           745: 		$col_align = $col_align.'|';
        !           746: 	    }
        !           747: 
        !           748: 	    #factor in spans:
        !           749: 
1.6       foxr      750: 	    my $cspan    = $cells->[$cell]->{'colspan'};
                    751: 	    my $nextcol  = $startcol + $cspan;
1.7     ! foxr      752: 	    $contents = '\multicolumn{'.$cspan.'}{'.$col_align.'}{'.$contents.'}';
1.6       foxr      753: 	    if ($inner_border && ($cells->[$cell]->{'rowspan'} == 1)) {
                    754: 		my $lastcol = $nextcol -1;
                    755: 		push(@underlines, "\\cline{$startcol-$lastcol}");
                    756: 	    }
                    757: 	    $startcol = $nextcol;
                    758: 	    # Rowspans should take care of themselves.
                    759: 	    
                    760: 
                    761: 	    push(@row, $contents);
                    762: 
                    763: 	}
                    764: 	push(@data, \@row);
                    765: 	if ($inner_border) {
                    766: 	    for (my $i =0; $i < scalar(@underlines); $i++) {
                    767: 		push(@data, [$underlines[$i]]);
                    768: 	    }
                    769: 	}
                    770: 
                    771:     }
                    772:     $table->set_data(\@data);
                    773:     
                    774:     my $coldef = "";
                    775:     if ($outer_border || $inner_border) {
                    776: 	$coldef .= '|';
                    777:     }
                    778:     for (my $i =0; $i < $column_count; $i++) {
                    779: 	$coldef .= 'l';
                    780: 	if ($inner_border || 
                    781: 	    ($outer_border && ($i == $column_count-1))) {
                    782: 	    $coldef .= '|';
                    783: 	}
                    784:     }
                    785:     $table->{'coldef'} = $coldef;
                    786: 
                    787:     # Return the table:
                    788: 
                    789:     return $table;
                    790: 
                    791: }
                    792: #----------------------------------------------------------------------------
1.5       foxr      793: # The following methods allow for testability.
1.4       foxr      794: 
                    795: 
                    796: sub get_object_attribute {
                    797:     my ($self, $attribute) = @_;
                    798:     return $self->{$attribute};
                    799: }
                    800: 
1.5       foxr      801: sub get_row {
                    802:     my ($self, $row) = @_;
                    803:     my $rows = $self->{'rows'};	  # ref to an array....
                    804:     return $rows->[$row];         # ref to the row hash for the selected row.
                    805: }
1.1       foxr      806: #   Mandatory initialization.
1.4       foxr      807: BEGIN{
                    808: }
1.1       foxr      809: 
                    810: 1;
                    811: __END__

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