File:
[LON-CAPA] /
loncom /
interface /
spreadsheet /
studentcalc.pm
Revision
1.35:
download - view:
text,
annotated -
select for diffs
Fri Aug 26 20:46:46 2005 UTC (19 years ago) by
albertel
Branches:
MAIN
CVS tags:
version_2_1_X,
version_2_1_3,
version_2_1_2,
version_2_1_1,
version_2_1_0,
version_2_0_X,
version_2_0_99_1,
version_2_0_2,
version_2_0_1,
HEAD
- fixes bug #4296 spreadsheet can't be edited
1: #
2: # $Id: studentcalc.pm,v 1.35 2005/08/26 20:46:46 albertel Exp $
3: #
4: # Copyright Michigan State University Board of Trustees
5: #
6: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
7: #
8: # LON-CAPA is free software; you can redistribute it and/or modify
9: # it under the terms of the GNU General Public License as published by
10: # the Free Software Foundation; either version 2 of the License, or
11: # (at your option) any later version.
12: #
13: # LON-CAPA is distributed in the hope that it will be useful,
14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: # GNU General Public License for more details.
17: #
18: # You should have received a copy of the GNU General Public License
19: # along with LON-CAPA; if not, write to the Free Software
20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21: #
22: # /home/httpd/html/adm/gpl.txt
23: #
24: # http://www.lon-capa.org/
25: #
26: # The LearningOnline Network with CAPA
27: # Spreadsheet/Grades Display Handler
28: #
29: # POD required stuff:
30:
31: =head1 NAME
32:
33: studentcalc
34:
35: =head1 SYNOPSIS
36:
37: =head1 DESCRIPTION
38:
39: =over 4
40:
41: =cut
42:
43: ###################################################
44: ### StudentSheet ###
45: ###################################################
46: package Apache::studentcalc;
47:
48: use warnings FATAL=>'all';
49: no warnings 'uninitialized';
50:
51: use strict;
52: use Apache::Constants qw(:common :http);
53: use Apache::lonnet;
54: use Apache::loncommon();
55: use Apache::loncoursedata();
56: use Apache::lonnavmaps;
57: use Apache::Spreadsheet();
58: use Apache::assesscalc();
59: use HTML::Entities();
60: use Time::HiRes;
61: use Apache::lonlocal;
62:
63: @Apache::studentcalc::ISA = ('Apache::Spreadsheet');
64:
65: my @Sequences = ();
66: my $navmap;
67: my %Exportrows = ();
68:
69: my $current_course;
70:
71: sub initialize {
72: &initialize_sequence_cache();
73: &Apache::assesscalc::initialize($navmap);
74: }
75:
76: sub initialize_package {
77: $current_course = $env{'request.course.id'};
78: &initialize_sequence_cache();
79: &load_cached_export_rows();
80: }
81:
82: sub ensure_correct_sequence_data {
83: if ($current_course ne $env{'request.course.id'}) {
84: &initialize_sequence_cache();
85: $current_course = $env{'request.course.id'};
86: }
87: return;
88: }
89:
90: sub initialize_sequence_cache {
91: #
92: # Set up the sequences and assessments
93: undef(@Sequences);
94: undef($navmap);
95: $navmap = Apache::lonnavmaps::navmap->new();
96: if (!defined($navmap)) {
97: &Apache::lonnet::logthis('student spreadsheet:Can not open Coursemap');
98: }
99: my @all_sequences = $navmap->retrieveResources(undef,
100: sub { shift->is_map(); },1,0,1);
101: for my $sequence ($navmap->getById('0.0'), @all_sequences) {
102: if ($navmap->hasResource($sequence,sub { shift->is_problem(); }, 0)){
103: push(@Sequences,$sequence);
104: &get_resources($sequence);
105: }
106: }
107: }
108:
109: my %res_memoize;
110: sub get_resources {
111: my ($seq) = @_;
112: if (exists($res_memoize{$seq->symb()})) {
113: return @{$res_memoize{$seq->symb()}};
114: }
115: return () if (! defined($navmap) || ! ref($navmap));
116: my @resources = $navmap->retrieveResources($seq,
117: sub { shift->is_problem(); },
118: 0,0,0);
119: $res_memoize{$seq->symb()}=\@resources;
120: return @resources;
121: }
122:
123: sub clear_package {
124: undef(@Sequences);
125: undef(%Exportrows);
126: undef(%res_memoize);
127: undef($navmap);
128: &Apache::assesscalc::clear_package();
129: }
130:
131: sub get_title {
132: my $self = shift;
133: my @title = ();
134: #
135: # Determine the students name
136: my $name = &Apache::loncommon::plainname($self->{'name'},
137: $self->{'domain'});
138: push (@title,$name);
139: push (@title,$self->{'coursedesc'});
140: push (@title,&Apache::lonlocal::locallocaltime(time));
141: return @title;
142: }
143:
144: sub get_html_title {
145: my $self = shift;
146: my ($name,$desc,$time) = $self->get_title();
147: my $title = '<h1>'.$name;
148: if ($env{'user.name'} ne $self->{'name'} &&
149: $env{'user.domain'} ne $self->{'domain'}) {
150: $title .= ' '.&Apache::loncommon::aboutmewrapper
151: ($self->{'name'}.'@'.$self->{'domain'},
152: $self->{'name'},$self->{'domain'});
153: }
154: $title .= "</h1>\n";
155: $title .= '<h2>'.$desc."</h2>\n";
156: $title .= '<h3>'.$time.'</h3>';
157: return $title;
158: }
159:
160: sub parent_link {
161: my $self = shift;
162: return '<p><a href="/adm/classcalc">'.&mt('Course level sheet').'</a></p>'."\n";
163: }
164:
165: sub convenience_links {
166: my $self = shift;
167: my ($resource) = @_;
168: my $result=&Apache::loncommon::submlink('<img src="/adm/lonMisc/subm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
169: $result .= &Apache::loncommon::pgrdlink('<img src="/adm/lonMisc/pgrd_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
170: $result .= &Apache::loncommon::pprmlink('<img src="/adm/lonMisc/pprm_button.gif" border="0" />',$self->{'name'},$self->{'domain'},$resource->symb,'LONcatInfo');
171: return $result;
172: }
173:
174: sub outsheet_html {
175: my $self = shift;
176: my ($r) = @_;
177: my $importcolor = '#FFFFAA';
178: my $exportcolor = '#88FF88';
179: ####################################
180: # Get the list of assessment files #
181: ####################################
182: my @AssessFileNames = $self->othersheets('assesscalc');
183: my $editing_is_allowed = &Apache::lonnet::allowed('mgr',
184: $env{'request.course.id'});
185: ####################################
186: # Report any calculation errors #
187: ####################################
188: $r->print($self->html_report_error());
189: ####################################
190: # Determine table structure #
191: ####################################
192: my $num_uneditable = 26;
193: my $num_left = 52-$num_uneditable;
194: my %lt=&Apache::lonlocal::texthash(
195: 'st' => 'Student',
196: 'im' => 'Import',
197: 'ca' => 'Calculations',
198: 'as' => 'Assessment',
199: 'ro' => 'Row',
200: );
201: my $tableheader =<<"END";
202: <p>
203: <table border="2">
204: <tr>
205: <th colspan="2" rowspan="2"><font size="+2">$lt{'st'}</font></th>
206: <td bgcolor="$importcolor" colspan="$num_uneditable">
207: <b><font size="+1">$lt{'im'}</font></b></td>
208: <td colspan="$num_left">
209: <b><font size="+1">$lt{'ca'}</font></b></td>
210: </tr><tr>
211: END
212: my $label_num = 0;
213: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
214: if ($label_num<$num_uneditable) {
215: $tableheader .='<td bgcolor="'.$importcolor.'">';
216: } else {
217: $tableheader .='<td>';
218: }
219: $tableheader .="<b><font size=+1>$_</font></b></td>";
220: $label_num++;
221: }
222: $tableheader .="</tr>\n";
223: if ($self->blackout()) {
224: $r->print('<font color="red" size="+2"><p>'.
225: &mt('Some computations are not available at this time.').'<br />'.
226: &mt('There are problems whose status you are not allowed to view.').
227: '</font></p>'."\n");
228: } else {
229: $r->print($tableheader);
230: #
231: # Print out template row
232: if (exists($env{'request.role.adv'}) && $env{'request.role.adv'}) {
233: $r->print('<tr><td>Template</td><td> </td>'.
234: $self->html_template_row($num_uneditable,
235: $importcolor)."</tr>\n");
236: }
237: #
238: # Print out summary/export row
239: $r->print('<tr><td>'.&mt('Summary').'</td><td>0</td>'.
240: $self->html_export_row($exportcolor)."</tr>\n");
241: }
242: $r->print("</table>\n");
243: #
244: # Prepare to output rows
245: if (exists($env{'request.role.adv'}) && $env{'request.role.adv'}) {
246: $tableheader =<<"END";
247: </p><p>
248: <table border="2">
249: <tr><th>$lt{'ro'}</th><th> </th><th>$lt{'as'}</th>
250: END
251: } else {
252: $tableheader =<<"END";
253: </p><p>
254: <table border="2">
255: <tr><th> </th><th>$lt{'as'}</th>
256: END
257: }
258: foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
259: if ($label_num<$num_uneditable) {
260: $tableheader.='<td bgcolor="#FFDDDD">';
261: } else {
262: $tableheader.='<td>';
263: }
264: $tableheader.="<b><font size=+1>$_</font></b></td>";
265: }
266: $tableheader.="\n";
267: #
268: my $num_output = 1;
269: if (scalar(@Sequences)< 1) {
270: &initialize_sequence_cache();
271: }
272: foreach my $Sequence (@Sequences) {
273: $r->print("<h3>".$Sequence->compTitle."</h3>\n");
274: $r->print($tableheader);
275: foreach my $resource (&get_resources($Sequence)) {
276: my $rownum = $self->get_row_number_from_key($resource->symb);
277: my $assess_filename = $self->{'row_source'}->{$rownum};
278: my $row_output = '<tr>';
279: if ($editing_is_allowed) {
280: $row_output .= '<td>'.$rownum.'</td>';
281: $row_output .= '<td>'.$self->convenience_links($resource).'</td>';
282: $row_output .= '<td>'.
283: '<a href="/adm/assesscalc?sname='.$self->{'name'}.
284: '&sdomain='.$self->{'domain'}.
285: '&filename='.$assess_filename.
286: '&usymb='.&Apache::lonnet::escape($resource->symb).
287: '">'.$resource->compTitle.'</a><br />';
288: $row_output .= &assess_file_selector($rownum,
289: $assess_filename,
290: \@AssessFileNames).
291: '</td>';
292: } else {
293: $row_output .= '<td><a href="'.$resource->src.'?symb='.
294: &Apache::lonnet::escape($resource->symb).
295: '">Go To</a>';
296: $row_output .= '</td><td>'.$resource->compTitle.'</td>';
297: }
298: if ($self->blackout() && $self->{'blackout_rows'}->{$rownum}>0) {
299: $row_output .=
300: '<td colspan="52">'.&mt('Unavailable at this time').'</td></tr>'."\n";
301: } else {
302: $row_output .= $self->html_row($num_uneditable,$rownum,
303: $exportcolor,$importcolor).
304: "</tr>\n";
305: }
306: $r->print($row_output);
307: }
308: $r->print("</table>\n");
309: }
310: $r->print("</p>\n");
311: return;
312: }
313:
314: ########################################################
315: ########################################################
316:
317: =pod
318:
319: =item &assess_file_selector()
320:
321: =cut
322:
323: ########################################################
324: ########################################################
325: sub assess_file_selector {
326: my ($row,$default,$AssessFiles)=@_;
327: if (!defined($AssessFiles) || ! @$AssessFiles) {
328: return '';
329: }
330: return '' if (! &Apache::lonnet::allowed('mgr',$env{'request.course.id'}));
331: my $element_name = 'FileSelect_'.$row;
332: my $load_dialog = '<select size="1" name="'.$element_name.'" '.
333: 'onchange="'.
334: "document.sheet.cell.value='source_$row';".
335: "document.sheet.newformula.value=document.sheet.$element_name\.value;".
336: 'document.sheet.submit()" '.'>'."\n";
337: foreach my $file (@{$AssessFiles}) {
338: $load_dialog .= ' <option name="'.$file.'"';
339: $load_dialog .= ' selected' if ($default eq $file);
340: $load_dialog .= '>'.$file."</option>\n";
341: }
342: $load_dialog .= "</select>\n";
343: return $load_dialog;
344: }
345:
346: sub modify_cell {
347: my $self = shift;
348: my ($cell,$formula) = @_;
349: if ($cell =~ /^source_(\d+)$/) {
350: # Need to make sure $formula is a valid filename....
351: my $row = $1;
352: $cell = 'A'.$row;
353: $self->{'row_source'}->{$row} = $formula;
354: my $original_source = $self->formula($cell);
355: if ($original_source =~ /__&&&__/) {
356: ($original_source,undef) = split('__&&&__',$original_source);
357: }
358: $formula = $original_source.'__&&&__'.$formula;
359: } elsif ($cell =~ /([A-z])\-/) {
360: $cell = 'template_'.$1;
361: } elsif ($cell !~ /^([A-z](\d+)|template_[A-z])$/) {
362: return;
363: }
364: $self->set_formula($cell,$formula);
365: $self->rebuild_stats();
366: return;
367: }
368:
369: sub csv_rows {
370: # writes the meat of the spreadsheet to an excel worksheet. Called
371: # by Spreadsheet::outsheet_excel;
372: my $self = shift;
373: my ($connection,$filehandle) = @_;
374: #
375: # Write a header row
376: $self->csv_output_row($filehandle,undef,
377: (&mt('Sequence or Folder'),&mt('Assessment title')));
378: #
379: # Write each assessments row
380: if (scalar(@Sequences)< 1) {
381: &initialize_sequence_cache();
382: }
383: foreach my $Sequence (@Sequences) {
384: foreach my $resource (&get_resources($Sequence)) {
385: my $rownum = $self->get_row_number_from_key($resource->symb);
386: my @assessdata = ($Sequence->compTitle,
387: $resource->compTitle);
388: $self->csv_output_row($filehandle,$rownum,@assessdata);
389: }
390: }
391: return;
392: }
393:
394: sub excel_rows {
395: # writes the meat of the spreadsheet to an excel worksheet. Called
396: # by Spreadsheet::outsheet_excel;
397: my $self = shift;
398: my ($connection,$worksheet,$cols_output,$rows_output,$format) = @_;
399: #
400: # Write a header row
401: $cols_output = 0;
402: foreach my $value ('Container','Assessment title') {
403: $worksheet->write($rows_output,$cols_output++,&mt($value),$format->{'h4'});
404: }
405: $rows_output++;
406: #
407: # Write each assessments row
408: if (scalar(@Sequences)< 1) {
409: &initialize_sequence_cache();
410: }
411: foreach my $Sequence (@Sequences) {
412: foreach my $resource (&get_resources($Sequence)) {
413: my $rownum = $self->get_row_number_from_key($resource->symb);
414: my @assessdata = ($Sequence->compTitle,
415: $resource->compTitle);
416: $self->excel_output_row($worksheet,$rownum,$rows_output++,
417: @assessdata);
418: }
419: }
420: return;
421: }
422:
423: sub outsheet_recursive_excel {
424: my $self = shift;
425: my ($r) = @_;
426: }
427:
428: ##
429: ## Routines to deal with sequences in the safe space
430: ##
431: sub get_rows_in_sequence {
432: my $self = shift();
433: my ($sequence) = @_;
434: my @Rows;
435: my @resources = &get_resources($sequence);
436: foreach my $resource (@resources) {
437: my $rownum = $self->get_row_number_from_key($resource->symb);
438: push (@Rows,$rownum);
439: }
440: return @Rows;
441: }
442:
443: sub remove_sequence_data_from_safe_space {
444: my $self = shift();
445: my $command = 'undef(%Sequence_Rows);';
446: $self->{'safe'}->reval($command);
447: }
448:
449: sub put_sequence_data_in_safe_space {
450: my $self = shift();
451: my $data = 'undef(%Sequence_Rows);';
452: # Build up the %Sequence_Rows hash - each sequence title is associated with
453: # an array pointer, which holds the rows in the sequence.
454: foreach my $seq (@Sequences) {
455: my @Rows = $self->get_rows_in_sequence($seq);
456: #
457: # Potential problems with sequence titles:
458: # 1. duplicate titles - they get the total for the titles
459: # 2. control characters in titles - use q{} around the string to
460: # deal with it.
461: my $title = &HTML::Entities::decode($seq->title());
462: $title =~ s/&\#058;/:/g;
463: if (@Rows) {
464: $data .= 'push(@{$Sequence_Rows{"'.quotemeta($title).'"}},'.
465: '('.join(',',@Rows).'));'."\n";;
466: }
467: }
468: my $new_code = $data.<<'END';
469: sub SUMSEQ {
470: my ($col,@titles) = @_;
471: return 'bad column: '.$col if ($col !~ /^[A-z]$/);
472: my $sum = 0;
473: foreach my $title (@titles) {
474: while (my ($seq_title,$rows) = each(%Sequence_Rows)) {
475: my $regexp;
476: if ($title =~ /^regexp:(.*)$/) {
477: $regexp = $1;
478: } elsif (lc($title) eq 'all') {
479: $regexp = '.';
480: }
481: if (defined($regexp)) {
482: next if ($seq_title !~ /$regexp/);
483: } else {
484: next if ($seq_title ne $title);
485: }
486: foreach my $rownum (@{$rows}) {
487: my $cell = $col.$rownum;
488: if (exists($sheet_values{$cell})) {
489: $sum += $sheet_values{$cell};
490: }
491: }
492: }
493: }
494: return $sum;
495: }
496: END
497: $self->{'safe'}->reval($new_code);
498: return;
499: }
500:
501: ##
502: ## Main computation method
503: ##
504: sub compute {
505: my $self = shift;
506: my ($r) = @_;
507: if (! defined($current_course) ||
508: $current_course ne $env{'request.course.id'} ||
509: ! @Sequences ) {
510: $current_course = $env{'request.course.id'};
511: &clear_package();
512: &initialize_sequence_cache();
513: }
514: $self->initialize_safe_space();
515: &Apache::assesscalc::initialize_package($self->{'name'},$self->{'domain'},
516: $navmap);
517: my %f = $self->formulas();
518: #
519: # Process the formulas list -
520: # the formula for the A column of a row is symb__&&__filename
521: my %c = $self->constants();
522: foreach my $seq (@Sequences) {
523: foreach my $resource (&get_resources($seq)) {
524: my $rownum = $self->get_row_number_from_key($resource->symb);
525: my $cell = 'A'.$rownum;
526: my $assess_filename = 'Default';
527: if (exists($self->{'row_source'}->{$rownum})) {
528: $assess_filename = $self->{'row_source'}->{$rownum};
529: } else {
530: $self->{'row_source'}->{$rownum} = $assess_filename;
531: }
532: $f{$cell} = $resource->symb.'__&&&__'.$assess_filename;
533: my $assessSheet;
534: $assessSheet = Apache::assesscalc->new($self->{'name'},
535: $self->{'domain'},
536: $assess_filename,
537: $resource->symb);
538: my @exportdata = $assessSheet->export_data($r);
539: #
540: if ($assessSheet->badcalc()) {
541: $self->set_calcerror(
542: &mt('Error computing row for assessment "[_1]" (row [_2]):[_3]',
543: $assessSheet->get_title(),$rownum,$assessSheet->calcerror()));
544: }
545: #
546: if ($assessSheet->blackout()) {
547: $self->blackout(1);
548: $self->{'blackout_rows'}->{$rownum} = 1;
549: }
550: #
551: # Be sure not to disturb the formulas in the 'A' column
552: my $data = shift(@exportdata);
553: $c{$cell} = $data if (defined($data));
554: #
555: # Deal with the remaining columns
556: my $i=0;
557: foreach (split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ')) {
558: my $cell = $_.$rownum;
559: my $data = shift(@exportdata);
560: if (defined($data)) {
561: $f{$cell} = 'import';
562: $c{$cell} = $data;
563: }
564: $i++;
565: }
566: }
567: }
568: $self->constants(\%c);
569: $self->formulas(\%f);
570: $self->put_sequence_data_in_safe_space();
571: $self->calcsheet();
572: $self->remove_sequence_data_from_safe_space();
573: #
574: # Store export row in cache
575: my @exportarray=$self->exportrow();
576: my $student = $self->{'name'}.':'.$self->{'domain'};
577: $Exportrows{$student}->{'time'} = time;
578: $Exportrows{$student}->{'data'} = \@exportarray;
579: # save export row
580: $self->save_export_data();
581: #
582: $self->save() if ($self->need_to_save());
583: return;
584: }
585:
586: sub set_row_sources {
587: my $self = shift;
588: $self->check_formulas_loaded();
589: while (my ($cell,$value) = each(%{$self->{'formulas'}})) {
590: next if ($cell !~ /^A(\d+)$/ || $1 < 1);
591: my $row = $1;
592: (undef,$value) = split('__&&&__',$value);
593: $value = 'Default' if (! defined($value));
594: $self->{'row_source'}->{$row} = $value;
595: }
596: return;
597: }
598:
599: sub set_row_numbers {
600: my $self = shift;
601: $self->check_formulas_loaded();
602: while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {
603: next if ($cell !~ /^A(\d+)/);
604: my $row = $1;
605: next if ($row == 0);
606: my ($symb,undef) = split('__&&&__',$formula);
607: $self->{'row_numbers'}->{$symb} = $row;
608: $self->{'maxrow'} = $row if ($row > $self->{'maxrow'});
609: }
610: }
611:
612: sub get_row_number_from_symb {
613: my $self = shift;
614: my ($key) = @_;
615: ($key,undef) = split('__&&&__',$key) if ($key =~ /__&&&__/);
616: return $self->get_row_number_from_key($key);
617: }
618:
619: #############################################
620: #############################################
621:
622: =pod
623:
624: =item &load_cached_export_rows
625:
626: Retrieves and parsers the export rows of the student spreadsheets.
627: These rows are saved in the courses directory in the format:
628:
629: sname:sdom:studentcalc:.time => time
630:
631: sname:sdom:studentcalc => ___=___Adata___;___Bdata___;___Cdata___;___ .....
632:
633: =cut
634:
635: #############################################
636: #############################################
637: sub load_cached_export_rows {
638: undef(%Exportrows);
639: my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets',
640: $env{'course.'.$env{'request.course.id'}.'.domain'},
641: $env{'course.'.$env{'request.course.id'}.'.num'},undef);
642: my %Selected_Assess_Sheet;
643: if ($tmp[0] =~ /^error/) {
644: &Apache::lonnet::logthis('unable to read cached student export rows '.
645: 'for course '.$env{'request.course.id'});
646: return;
647: }
648: my %tmp = @tmp;
649: while (my ($key,$sheetdata) = each(%tmp)) {
650: my ($sname,$sdom,$sheettype,$remainder) = split(':',$key);
651: my $student = $sname.':'.$sdom;
652: if ($remainder =~ /\.time/) {
653: $Exportrows{$student}->{'time'} = $sheetdata;
654: } else {
655: $sheetdata =~ s/^___=___//;
656: my @Data = split('___;___',$sheetdata);
657: $Exportrows{$student}->{'data'} = \@Data;
658: }
659: }
660: }
661:
662: #############################################
663: #############################################
664:
665: =pod
666:
667: =item &save_export_data()
668:
669: Writes the export data for this student to the course cache.
670:
671: =cut
672:
673: #############################################
674: #############################################
675: sub save_export_data {
676: my $self = shift;
677: my $student = $self->{'name'}.':'.$self->{'domain'};
678: return if ($self->temporary());
679: if ($self->badcalc()){
680: # do not save data away when calculations have not been done properly.
681: delete($Exportrows{$student});
682: return;
683: }
684: return if (! exists($Exportrows{$student}));
685: &Apache::assesscalc::save_cached_export_rows($self->{'name'},
686: $self->{'domain'});
687: return if (! $self->is_default());
688: my $key = join(':',($self->{'name'},$self->{'domain'},'studentcalc')).':';
689: my $timekey = $key.'.time';
690: my $newstore = join('___;___',
691: @{$Exportrows{$student}->{'data'}});
692: $newstore = '___=___'.$newstore;
693: my $result= &Apache::lonnet::put('nohist_calculatedsheets',
694: { $key => $newstore,
695: $timekey => $Exportrows{$student}->{'time'} },
696: $self->{'cdom'},
697: $self->{'cnum'});
698: return;
699: }
700:
701: #############################################
702: #############################################
703:
704: =pod
705:
706: =item &export_data()
707:
708: Returns the export data associated with the spreadsheet. Computes the
709: spreadsheet only if necessary.
710:
711: =cut
712:
713: #############################################
714: #############################################
715: sub export_data {
716: my $self = shift;
717: my ($r) = @_;
718: my $connection = $r->connection();
719: my $student = $self->{'name'}.':'.$self->{'domain'};
720: if (! exists($Exportrows{$student}) ||
721: ! defined($Exportrows{$student}) ||
722: ! exists($Exportrows{$student}->{'data'}) ||
723: ! defined($Exportrows{$student}->{'data'}) ||
724: ! exists($Exportrows{$student}->{'time'}) ||
725: ! defined($Exportrows{$student}->{'time'}) ||
726: ! $self->check_expiration_time($Exportrows{$student}->{'time'})) {
727: $self->compute($r);
728: }
729: if ($connection->aborted()) { $self->cleanup(); return; }
730: my @Data;
731: if ($self->badcalc()) {
732: @Data = ();
733: } else {
734: @Data = @{$Exportrows{$student}->{'data'}};
735: for (my $i=0; $i<=$#Data;$i++) {
736: if ($Data[$i]=~/\D/ && defined($Data[$i])) {
737: $Data[$i]="'".$Data[$i]."'";
738: }
739: }
740: }
741: return @Data;
742: }
743:
744: 1;
745:
746: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>