Annotation of loncom/xml/lontable.pm, revision 1.9
1.1 foxr 1: # The LearningOnline Network with CAPA
2: # Generating TeX tables.
3: #
1.9 ! bisitz 4: # $Id: lontable.pm,v 1.8 2009/01/20 12:01:01 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;
1.9 ! bisitz 58: # use LaTeX::Table;
1.8 foxr 59: use Apache::lonnet; # for trace logging.
1.1 foxr 60:
1.8 foxr 61: my $tracing = 0; # Set to 1 to enable log tracing. 2 for local sub tracing.
1.1 foxr 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:
1.3 foxr 94: =item add_cell
95:
96: Add and configure a cell to the current row.6
97:
1.1 foxr 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:
1.7 foxr 113:
1.1 foxr 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:
1.7 foxr 138: =item width
139:
1.8 foxr 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.
1.7 foxr 144:
1.1 foxr 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:
1.6 foxr 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:
1.1 foxr 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
1.3 foxr 200: 0
1.1 foxr 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:
1.6 foxr 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:
1.1 foxr 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:
1.3 foxr 219: =item header
220:
221: If present, the row is a 'header' that is it was made via the
222: <th> tag.
223:
1.1 foxr 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:
1.6 foxr 241: =item start_col
242:
243: The starting column of the cell in the table grid.
244:
1.1 foxr 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:
1.8 foxr 258: if($tracing) {&Apache::lonnet::logthis("new table object");}
259:
1.1 foxr 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,
1.2 foxr 266: inner_border => 0,
1.1 foxr 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:
1.3 foxr 283:
1.1 foxr 284: #-------------------------------------------------------------------------
285: #
286: # Methods that get/set table global configuration.
1.2 foxr 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:
1.8 foxr 306: if ($tracing) {&Apache::lonnet::logthis("alignment = $new_value");}
307:
1.2 foxr 308: if (defined($new_value)) {
1.5 foxr 309: $self->{'alignment'} = $new_value;
1.2 foxr 310: }
1.5 foxr 311: return $self->{'alignment'};
1.2 foxr 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:
1.8 foxr 333: if ($tracing) {&Apache::lonnet::logthis("table_border $new_value");}
334:
1.2 foxr 335: if (defined($new_value)) {
1.5 foxr 336: $self->{'outer_border'} = $new_value;
1.2 foxr 337: }
1.5 foxr 338: return $self->{'outer_border'};
1.2 foxr 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:
1.4 foxr 353: my $cell_border = $table->cell_border(); # ask if cell borders are requested.
1.2 foxr 354: $table->cell_border(1); # Request cell borders.
355:
356: =cut
357:
1.4 foxr 358: sub cell_border {
1.2 foxr 359: my ($self, $new_value) = @_;
1.8 foxr 360: if($tracing) {&Apache::lonnet::logthis("cell_border: $new_value"); }
1.2 foxr 361: if (defined($new_value)) {
1.5 foxr 362: $self->{'inner_border'} = $new_value;
1.2 foxr 363: }
1.5 foxr 364: return $self->{'inner_border'};
1.2 foxr 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:
1.8 foxr 385: if($tracing) {&Apache::lonnet::logthis("caption: $new_value"); }
1.2 foxr 386: if (defined($new_value)) {
1.5 foxr 387: $self->{'caption'} = $new_value;
1.2 foxr 388: }
389:
1.5 foxr 390: return $self->{'caption'};
1.2 foxr 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:
1.1 foxr 402:
1.2 foxr 403: my $theme = $table->theme();
404: $table->theme("Dresden");
405:
406: =cut
407:
408: sub theme {
409: my ($self, $new_value) = @_;
1.8 foxr 410: if($tracing) {&Apache::lonnet::logthis("theme $new_value"); }
1.2 foxr 411: if (defined($new_value)) {
1.5 foxr 412: $self->{'theme'} = $new_value;
1.2 foxr 413: }
1.5 foxr 414: return $self->{'theme'};
1.2 foxr 415: }
416:
417: =pod
418:
1.7 foxr 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) = @_;
1.8 foxr 430: if($tracing) {&Apache::lonnet::logthis("width = $new_value"); }
431:
1.7 foxr 432: if (defined($new_value)) {
433: $self->{'width'} = $new_value;
434: }
435: return $self->{'width'}; # Could be undef.
436: }
437:
438: =pod
439:
1.2 foxr 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 {
1.5 foxr 467: my ($self, $config) = @_;
1.8 foxr 468: if($tracing) {&Apache::lonnet::logthis("start_row"); }
1.5 foxr 469: if ($self->{'row_open'}) {
1.4 foxr 470: $self->end_row();
1.2 foxr 471: }
472: my $row_hash = {
473: default_halign => "left",
474: default_valign => "top",
1.6 foxr 475: cell_width => 0,
1.2 foxr 476: cells => []
477: };
478:
479: # Override the defaults if the config hash is present:
480:
1.5 foxr 481: if (defined($config)) {
482: foreach my $key (keys %$config) {
483: $row_hash->{$key} = $config->{$key};
1.2 foxr 484: }
485: }
1.5 foxr 486:
1.2 foxr 487:
1.5 foxr 488: my $rows = $self->{'rows'};
1.2 foxr 489: push(@$rows, $row_hash);
490:
1.5 foxr 491: $self->{"row_open"} = 1; # Row is now open and ready for business.
1.2 foxr 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:
1.4 foxr 502: $table->end_row();
1.2 foxr 503:
504:
505: =cut
506:
1.4 foxr 507: sub end_row {
1.2 foxr 508: my ($self) = @_;
1.8 foxr 509: if($tracing) {&Apache::lonnet::logthis("end_row"); }
1.5 foxr 510: if ($self->{'row_open'}) {
1.2 foxr 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:
1.6 foxr 515: my $row = $self->{'rows'}->[-1];
1.5 foxr 516: my $cells = $row->{'cells'};
1.3 foxr 517:
1.6 foxr 518: if ($row->{'cell_width'} > $self->{'column_count'}) {
519: $self->{'column_count'} = $row->{'cell_width'};
1.2 foxr 520: }
521:
1.5 foxr 522: $self->{'row_open'} = 0;;
1.2 foxr 523: }
524: }
525:
526: =pod
527:
1.3 foxr 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:
1.2 foxr 533:
1.3 foxr 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:
1.2 foxr 537:
1.3 foxr 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
1.2 foxr 552:
553: =cut
554:
1.3 foxr 555: sub configure_row {
556: my ($self, $config) = @_;
1.8 foxr 557: if($tracing) {&Apache::lonnet::logthis("configure_row");}
1.5 foxr 558: if (!$self->{'row_open'}) {
1.3 foxr 559: $self->start_row();
560: }
561:
1.5 foxr 562: my $row = $self->{'rows'}[-1];
1.3 foxr 563: foreach my $config_item (keys %$config) {
564: $row->{$config_item} = $config->{$config_item};
565: }
1.2 foxr 566: }
1.1 foxr 567:
568:
1.3 foxr 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:
1.8 foxr 615: if($tracing) {&Apache::lonnet::logthis("add_cell : $text"); }
616:
1.3 foxr 617: # If a row is not open, we must open it:
618:
1.5 foxr 619: if (!$self->{'row_open'}) {
1.3 foxr 620: $self->start_row();
621: }
1.6 foxr 622: my $rows = $self->{'rows'};
623: my $current_row = $rows->[-1];
1.5 foxr 624: my $current_cells = $current_row->{'cells'};
1.6 foxr 625: my $last_coord = $current_row->{'cell_width'};
1.3 foxr 626:
1.6 foxr 627: # We have to worry about row spans if there is a prior row:
1.3 foxr 628:
1.6 foxr 629: if (scalar(@$rows) > 1) {
1.3 foxr 630:
1.6 foxr 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];
1.8 foxr 643: if (!defined($prior_cell)) {
644: last;
645: }
1.6 foxr 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: }
1.3 foxr 663: }
1.6 foxr 664:
1.3 foxr 665: }
1.6 foxr 666:
1.3 foxr 667: #
668: # Now we're ready to build up our cell:
669:
670: my $cell = {
671: rowspan => 1,
672: colspan => 1,
1.6 foxr 673: start_col => $last_coord,
1.3 foxr 674: contents => $text
675: };
676:
677: if (defined($config)) {
678: foreach my $key (keys(%$config)) {
679: $cell->{$key} = $config->{$key};
680: }
681: }
1.6 foxr 682: $current_row->{'cell_width'} += $cell->{'colspan'};
683:
1.3 foxr 684: push(@$current_cells, $cell);
1.8 foxr 685:
686: if ($tracing) { &Apache::lonnet::logthis("add_cell done"); }
1.3 foxr 687: }
688:
1.8 foxr 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:
1.6 foxr 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) = @_;
1.8 foxr 728: my $useP = 0;
729: my $colwidth;
730: my $colunits;
1.6 foxr 731:
1.8 foxr 732: if($tracing) {&Apache::lonnet::logthis("generate"); }
1.6 foxr 733: my $table = LaTeX::Table->new();
1.8 foxr 734: $table->set_center(0); # loncapa tables don't float.
735: $table->set_environment(0);
736:
1.6 foxr 737:
1.7 foxr 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'})) {
1.8 foxr 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:
1.7 foxr 753: }
754:
1.6 foxr 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'};
1.7 foxr 767: my $def_halign = $rows->[$row]->{'default_halign'};
1.6 foxr 768: my $cell_count = scalar(@$cells);
769: my $startcol = 1;
770: my @underlines; # Array of \cline cells if cellborder on.
771:
1.8 foxr 772:
1.6 foxr 773: for (my $cell = 0; $cell < $cell_count; $cell++) {
774: my $contents = $cells->[$cell]->{'contents'};
1.7 foxr 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';
1.8 foxr 790: my $embeddedAlignStart = "";
791: my $embeddedAlignEnd = "";
792:
1.7 foxr 793: if ($halign eq 'right') {
794: $col_align = 'r';
1.8 foxr 795: $embeddedAlignStart = '\begin{flushright} ';
796: $embeddedAlignEnd = ' \end{flushright}';
1.7 foxr 797: }
798: if ($halign eq 'center') {
799: $col_align = 'c';
1.8 foxr 800: $embeddedAlignStart = '\begin{center}';
801: $embeddedAlignEnd = '\end{center}';
1.7 foxr 802: }
1.8 foxr 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:
1.7 foxr 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:
1.6 foxr 822: my $cspan = $cells->[$cell]->{'colspan'};
823: my $nextcol = $startcol + $cspan;
1.8 foxr 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: }
1.6 foxr 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++) {
1.8 foxr 865: if ($useP) {
866: $coldef .= "p{$colwidth $colunits}";
867: } else {
868: $coldef .= 'l';
869: }
1.6 foxr 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:
1.8 foxr 879: if ($tracing) { &Apache::lonnet::logthis("Leaving generate"); }
880:
1.6 foxr 881: return $table;
882:
883: }
884: #----------------------------------------------------------------------------
1.5 foxr 885: # The following methods allow for testability.
1.4 foxr 886:
887:
888: sub get_object_attribute {
889: my ($self, $attribute) = @_;
1.8 foxr 890: if ($tracing > 1) { &Apache::lonnet::logthis("get_object_attribute: $attribute"); }
1.4 foxr 891: return $self->{$attribute};
892: }
893:
1.5 foxr 894: sub get_row {
895: my ($self, $row) = @_;
1.8 foxr 896: if ($tracing > 1) { &Apache::lonnet::logthis("get_row"); }
897:
1.5 foxr 898: my $rows = $self->{'rows'}; # ref to an array....
899: return $rows->[$row]; # ref to the row hash for the selected row.
900: }
1.1 foxr 901: # Mandatory initialization.
1.4 foxr 902: BEGIN{
903: }
1.1 foxr 904:
905: 1;
906: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>