Annotation of loncom/xml/lontable.pm, revision 1.3
1.1 foxr 1: # The LearningOnline Network with CAPA
2: # Generating TeX tables.
3: #
1.3 ! foxr 4: # $Id: lontable.pm,v 1.2 2008/11/25 12:27:34 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
42: # the print generator must have added the following to the LaTeX header:
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:
111: =item alignment
112:
113: Table alignment. Some table styles support this but not all.
114:
115: =item tableborder
116:
117: If true, a border is drawn around the table.
118:
119: =item cellborder
120:
121: If true, borders are drawn around the cells inside a table.
122:
123: =item caption
124:
125: The table caption text.
126:
127: =item theme
128:
129: The theme of the table to use. Defaults to Zurich. Themes we know about are:
130: NYC, NYC2, Zurich, Berlin, Dresden, Houston, Miami, plain, Paris. Other themes can be added
131: to the LaTeX::Table package, and they will become supported automatically, as theme names are
132: not error checked. Any use of a non-existent theme is reported by the LaTeX::Table package
133: when the table text is generated.
134:
135: =back
136:
137: =head3 Member data
138:
139: The object hash has the following members:
140:
141: =over 3
142:
143: =item column_count
144:
145: Maintained internally, the number of colums in the widest row.
146:
147: =item alignment
148:
149: Table alignment (configurable) "left", "center", or "right".
150:
151: =item outer_border
152:
153: True if a border should be drawn around the entire table (configurable)
154:
155: =item inner_borders
156:
157: True if a border should be drawn around all cells (configurable).
158:
159: =item caption
160:
161: Table caption (configurable).
162:
163: =item theme
164:
165: Theme desired (configurable).
166:
167: =item row_open
168:
169: True if a row is open and not yet closed.
170:
171: =item rows
172:
173: Array of row data. This is an array of hashes described below.
174:
175: =back
176:
177: =head3 Row data.
178:
179: Each row of table data is an element of the rows hash array. Hash elements are
180:
181: =over 3
182:
183:
184: =item default_halign
1.3 ! foxr 185: 0
1.1 foxr 186: Default horizontal alignment for cells in this row.
187:
188: =item default_valign
189:
190: Default vertical alignment for cells in this row (may be ignored).
191:
192: =item cells
193:
194: Array of hashes where each element represents the data for a cell.
195: The contents of each element of this hash are described below:
196:
197: =over 3
198:
1.3 ! foxr 199: =item header
! 200:
! 201: If present, the row is a 'header' that is it was made via the
! 202: <th> tag.
! 203:
1.1 foxr 204: =item halign
205:
206: If present, overrides the row default horizontal alignment.
207:
208: =item valign
209:
210: if present, override the row default vertical alignment.
211:
212: =item rowspan
213:
214: If present, indicates the number of rows this cell spans.
215:
216: =item colspan
217:
218: If present indicates the number of columns this cell spans.
219: Note that a cell can span both rows and columns.
220:
221: =item contents
222:
223: The contents of the cell.
224:
225: =back
226:
227: =back
228:
229: =cut
230:
231: sub new {
232: my ($class, $configuration) = @_;
233:
234: # Initialize the object member data with the default values
235: # then override with any stuff in $configuration.
236:
237: my $self = {
238: alignment => "left",
239: outer_border => 0,
1.2 foxr 240: inner_border => 0,
1.1 foxr 241: caption => "",
242: theme => "Zurich",
243: column_count => 0,
244: row_open => 0,
245: rows => [],
246: };
247:
248: foreach my $key (keys %$configuration) {
249: $self->{$key} = $$configuration{$key};
250: }
251:
252: bless($self, $class);
253:
254: return $self;
255: }
256:
1.3 ! foxr 257:
1.1 foxr 258: #-------------------------------------------------------------------------
259: #
260: # Methods that get/set table global configuration.
1.2 foxr 261: #
262:
263: =pod
264:
265: =head2 Gets/set alignment.
266:
267: If the method is passed a new alignment value, that replaces the current one.
268: Regardless, the current alignment is used:
269:
270: =head3 Examples:
271:
272: my $align = $table->alignment(); # Return current alignment
273: $table->alignment("center"); # Attempt centered alignment.
274:
275: =cut
276:
277: sub alignment {
278: my ($self, $new_value) = @_;
279:
280: if (defined($new_value)) {
281: $self->{alignment} = $new_value;
282: }
283: return $self->{alignment};
284: }
285:
286: =pod
287:
288: =head2 table_border
289:
290: Set or get the presence of an outer border in the table.
291: If passed a parameter, that parameter replaces the current request
292: for or not for an outer border. Regardless, the function returns
293: the final value of the outer_border request.
294:
295: =head3 Examples:
296:
297: $table->table_border(1); # Request an outer border.
298: my $outer_requested = $table->table_border();
299:
300: =cut
301:
302: sub table_border {
303: my ($self, $new_value) = @_;
304:
305: if (defined($new_value)) {
306: $self->{outer_border} = $new_value;
307: }
308: return $self->{outer_border};
309: }
310:
311:
312: =pod
313:
314: =head2 cell_border
315:
316: Set or get the presence of a request for cells to have borders
317: drawn around them. If a paramter is passed, it will be treated as
318: a new value for the cell border configuration. Regardless,the final
319: value of that configuration parameter is returned.
320:
321: =head3 Examples:
322:
323: my $cell_borders = $table->cell_border(); # ask if cell borders are requested.
324: $table->cell_border(1); # Request cell borders.
325:
326: =cut
327:
328: sub cell_borders {
329: my ($self, $new_value) = @_;
330:
331: if (defined($new_value)) {
332: $self->{inner_border} = $new_value;
333: }
334: reurn $self->{inner_border};
335: }
336:
337: =pod
338:
339: =head2 caption
340:
341: Gets and/or sets the caption string for the table. The caption string appears to label
342: the table. If a parameter is supplied it will become the new caption string.k
343:
344: =head3 Examples:
345:
346:
347: $my caption = $table->caption();
348: $table->caption("This is the new table caption");
349:
350: =cut
351:
352: sub caption {
353: my ($self, $new_value) = @_;
354:
355: if (defined($new_value)) {
356: $self->catpion = $new_value;
357: }
358:
359: return $self->caption;
360: }
361:
362: =pod
363:
364: =head2 theme
365:
366: Gets and optionally sets the table theme. The table theme describes how the
367: table will be typset by the table package. If a parameter is supplied it
368: will be the new theme selection.
369:
370: =head3 Examples:
1.1 foxr 371:
1.2 foxr 372: my $theme = $table->theme();
373: $table->theme("Dresden");
374:
375: =cut
376:
377: sub theme {
378: my ($self, $new_value) = @_;
379:
380: if (defined($new_value)) {
381: $self->theme = $new_value;
382: }
383: return $self->theme;
384: }
385:
386: =pod
387:
388: =head2 start_row
389:
390: Begins a new row in the table. If a row is already open, that row is
391: closed off prior to starting the new row. Rows can have the following attributes
392: which are specified by an optional hash passed in to this function.
393:
394: =over 3
395:
396: =item default_halign
397:
398: The default horizontal alignment of the row. This can be "left", "center", or "right"
399:
400: =item default_valign
401:
402: The default vertical alignment of the row. This can be "top", "center", or "bottom"
403:
404: =back
405:
406: =head3 Examples:
407:
408: $table_start_row(); # no attributes.
409: $table_start({default_halign => "center",
410: default_valign => "bottom"}); # Create setting the attrbutes.
411:
412: =cut
413:
414: sub start_row {
415: my ($self, %config) = @_;
416:
417: if ($self->row_open) {
418: $self->end_row;
419: }
420: my $row_hash = {
421: default_halign => "left",
422: default_valign => "top",
423: cells => []
424: };
425:
426: # Override the defaults if the config hash is present:
427:
428: if (defined(%config)) {
429: foreach my $key (keys %config) {
430: $row_hash->{$key} = $config{$key};
431: }
432: }
433:
434: my $rows = $self->{rows};
435: push(@$rows, $row_hash);
436:
437: $self->row_open = 1; # Row is now open and ready for business.
438: }
439:
440: =pod
441:
442: =head2 end_row
443:
444: Closes off a row. Once closed, cells cannot be added to this row again.
445:
446: =head3 Examples:
447:
448: $table->close_row();
449:
450:
451: =cut
452:
453: sub close_row {
454: my ($self) = @_;
455:
456: if ($self->row_open) {
457:
458: # Mostly we need to determine if this row has the maximum
459: # cell count of any row in existence in the table:
460:
461: my $row = $self->{rows}[-1];
462: my $cells = $row->{cells};
1.3 ! foxr 463: my $raw_cell_count = scalar(@$cells);
! 464:
! 465: # Need to iterate through the columns as
! 466: # colspans affect the count:
! 467: #
! 468: my $cell_count = 0;
! 469: for (my $i =0; $i < $raw_cell_count; $i++) {
! 470: $cell_count = $cell_count + $cells->[$i]->{colspan};
! 471: }
1.2 foxr 472: if ($cell_count > $self->{column_count}) {
473: $self->{column_count} = $cell_count;
474: }
475:
476: $self->row_closed;
477: }
478: }
479:
480: =pod
481:
1.3 ! foxr 482: =head2 configure_row
! 483:
! 484: Modify the configuration of a row. If a row is not open, a new one will be opened.
! 485:
! 486: =head3 Parameters:
1.2 foxr 487:
1.3 ! foxr 488: config_hash - A hash that contains new values for the set of row confiuguration
! 489: items to be modified. There is currently no check/penalty for items that are not in
! 490: the set of defined configuration properties which are:
1.2 foxr 491:
1.3 ! foxr 492: =over 2
! 493:
! 494: =item default_halign
! 495:
! 496: The default horizontal alignment for text in cells in the row. This can be any of:
! 497: "left", "right" or "center".
! 498:
! 499: =item default_valign
! 500:
! 501: The default vertical alignment for text in cells in the row. This can be any of:
! 502:
! 503: "top", "bottom" or "center"
! 504:
! 505: =back
1.2 foxr 506:
507: =cut
508:
1.3 ! foxr 509: sub configure_row {
! 510: my ($self, $config) = @_;
1.2 foxr 511:
1.3 ! foxr 512: if (!$self->row_open) {
! 513: $self->start_row();
! 514: }
! 515:
! 516: my $row = $self->{rows}[-1];
! 517: foreach my $config_item (keys %$config) {
! 518: $row->{$config_item} = $config->{$config_item};
! 519: }
1.2 foxr 520: }
1.1 foxr 521:
522:
1.3 ! foxr 523: =pod
! 524:
! 525: =head2 add_cell
! 526:
! 527: Add a new cell to a row. If there is a row above us, we need to
! 528: watch out for row spans that may force additional blank cell entries
! 529: to fill in the span.
! 530:
! 531: =head3 Parameters:
! 532:
! 533: =over 2
! 534:
! 535: =item text
! 536:
! 537: Text to put in the cell.
! 538:
! 539: =item cell_config
! 540:
! 541: Hash of configuration options that override the defaults. The recognized options,
! 542: and their defaults are:
! 543:
! 544: =over 2
! 545:
! 546: =item halign
! 547:
! 548: If nonblank overrides the row's default for the cell's horizontal alignment.
! 549:
! 550: =item valign
! 551:
! 552: If nonblank, overrides the row's default for the cdell's vertical alignment.
! 553:
! 554: =item rowspan
! 555:
! 556: Number of rows the cell spans.
! 557:
! 558: =item colspan
! 559:
! 560: Number of columns the cell spans.
! 561:
! 562: =back
! 563:
! 564: =cut
! 565:
! 566: sub add_cell {
! 567: my ($self, $text, $config) = @_;
! 568:
! 569: # If a row is not open, we must open it:
! 570:
! 571: if (!$self->row_open) {
! 572: $self->start_row();
! 573: }
! 574:
! 575: my $current_row = $self->{rows}->[-1];
! 576: my $current_cells = $current_row->{cells};
! 577:
! 578: # The way we handle row spans is to insert additional
! 579: # blank cells as needed to reach this column. Each
! 580: # cell that is inserted is empty, but has a row span decreased by one
! 581: # from the row above. Column spans are propagated down from the row above
! 582: # and handled when the table's LaTeX is generated.
! 583: # There must be at least two rows in the row table to need to do this:
! 584:
! 585: my $row_count = scalar(@$self->{rows});
! 586: if ($row_count > 1) {
! 587: my $prior_row = $self->{rows}->[-2];
! 588: my $curr_colcount = scaler(@$current_row->{cells});
! 589: my $prior_colcount = scaler(@$prior_row->{cells});
! 590:
! 591: while (($curr_colcount < $prior_colcount) &&
! 592: $prior_row->{cells}->[$curr_colcount]->{rowspan} > 1) {
! 593: my %cell = $prior_row->{cells}->[$curr_colcount];
! 594: %cell->{rowspan}--;
! 595: %cell->{contents} = "";
! 596: push(@$current_cells, \%cell);
! 597: }
! 598: }
! 599: #
! 600: # Now we're ready to build up our cell:
! 601:
! 602: my $cell = {
! 603: rowspan => 1,
! 604: colspan => 1,
! 605: contents => $text
! 606: };
! 607:
! 608: if (defined($config)) {
! 609: foreach my $key (keys(%$config)) {
! 610: $cell->{$key} = $config->{$key};
! 611: }
! 612: }
! 613: push(@$current_cells, $cell);
! 614: }
! 615:
1.1 foxr 616:
617: # Mandatory initialization.
618:
619: 1;
620: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>