File:  [LON-CAPA] / loncom / interface / spreadsheet / assesscalc.pm
Revision 1.17: download - view: text, annotated - select for diffs
Tue Jul 29 05:22:56 2003 UTC (20 years, 11 months ago) by albertel
Branches: MAIN
CVS tags: version_1_0_2, version_1_0_1, version_1_0_0, version_0_99_5, version_0_99_4, HEAD
- Fixes for BUG#1991, (maybe packages.tab will finally be handled correctly? One can only hope)
- Made thes changes I said I was going to in the bugreport (copied below for conviene and commit padding)
1) stop metadata from parsing packages.tab values and sticking them in the
metadata of the problem
2) add new function get pacakages_tab_default() to lonnet, takeas a full parm
signifier (resource.partid_responseid.name) (just like EXT takes) figures out
what kind of response/part the things is and returns the proper default value
from packages.tab
3) add to EXT to check this new function for the packages.tab default for
anythings it can't find a value for
4) check that all other parmval funtions also do this

4) turned out to be assesscalc.pm and lonnavmaps.pm, and executive decision was made to leave lonparmset.pm out of the fix, as there is nothing the user can do about these values, adn they see the defaults appear in the 'Current session value' column.

(as it is it would be difficult to add these values to the parmset screen, one would need a colun at the very end that said "if ther are no other values set anywhere else, we'll use this one.)

Anyhoo.

    1: #
    2: # $Id: assesscalc.pm,v 1.17 2003/07/29 05:22:56 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: assesscalc
   34: 
   35: =head1 SYNOPSIS
   36: 
   37: =head1 DESCRIPTION
   38: 
   39: =cut
   40: 
   41: ###################################################
   42: ###                 AssessSheet                 ###
   43: ###################################################
   44: package Apache::assesscalc;
   45: 
   46: use strict;
   47: use Apache::Constants qw(:common :http);
   48: use Apache::lonnet;
   49: use Apache::loncommon;
   50: use Apache::Spreadsheet;
   51: use HTML::Entities();
   52: use Spreadsheet::WriteExcel;
   53: use GDBM_File;
   54: use Time::HiRes;
   55: 
   56: @Apache::assesscalc::ISA = ('Apache::Spreadsheet');
   57: 
   58: ########################################################
   59: ########################################################
   60: 
   61: =pod
   62: 
   63: =head2 Package Variables
   64: 
   65: =over 4
   66: 
   67: =item %Exportrows
   68: 
   69: =item $current_name
   70: 
   71: =item $current_domain
   72: 
   73: =item $current_course
   74: 
   75: =item %parmhash
   76: 
   77: =item %nice_parameter_name
   78: 
   79: =item %useropt
   80: 
   81: =item %courseopt
   82: 
   83: =back 
   84: 
   85: =cut
   86: 
   87: ########################################################
   88: ########################################################
   89: 
   90: my %Exportrows;
   91: 
   92: my $current_name;
   93: my $current_domain;
   94: my $current_course;
   95: 
   96: my %parmhash;
   97: my %nice_parameter_name;
   98: 
   99: my %useropt;
  100: my %courseopt;
  101: 
  102: ########################################################
  103: ########################################################
  104: 
  105: =pod
  106: 
  107: =head2 Package Subroutines
  108: 
  109: =item &clear_package()
  110: 
  111: Reset all package variables.  
  112: 
  113: =cut
  114: 
  115: ########################################################
  116: ########################################################
  117: sub clear_package {
  118:     undef(%Exportrows);
  119:     undef($current_name);
  120:     undef($current_domain);
  121:     undef($current_course);
  122:     undef(%useropt);
  123:     undef(%courseopt);
  124: }
  125: 
  126: sub initialize {
  127:     &clear_package();
  128: }
  129: 
  130: ########################################################
  131: ########################################################
  132: 
  133: =pod
  134: 
  135: =item &initialize_package()
  136: 
  137: =cut
  138: 
  139: ########################################################
  140: ########################################################
  141: sub initialize_package {
  142:     my ($sname,$sdomain) = @_;
  143:     $current_name   = $sname;
  144:     $current_domain = $sdomain;
  145:     if ($current_course ne $ENV{'request.course.id'}) {
  146:         $current_course = $ENV{'request.course.id'};
  147:         undef(%courseopt);
  148:     }
  149:     &load_cached_export_rows();
  150:     &load_parameter_caches();
  151: }
  152: 
  153: ########################################################
  154: ########################################################
  155: 
  156: =pod
  157: 
  158: =item &load_parameter_caches()
  159: 
  160: =cut
  161: 
  162: ########################################################
  163: ########################################################
  164: sub load_parameter_caches {
  165:     my $userprefix = $current_name.':'.$current_domain.'_';
  166:     $userprefix =~ s/:/_/g;
  167:     #
  168:     # Course Parameters Cache
  169:     if (! %courseopt) {
  170:         &Apache::lonnet::logthis("loading course options");
  171:         $current_course = $ENV{'request.course.id'};
  172:         undef(%courseopt);
  173:         if (! defined($current_name) || ! defined($current_domain)) {
  174:             &Apache::lonnet::logthis('bad call to setup_parameter_caches');
  175:             return;
  176:         }
  177:         my $dom = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
  178:         my $id  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};
  179:         my %Tmp = &Apache::lonnet::dump('resourcedata',$dom,$id);
  180:         while (my ($name,$value) = each(%Tmp)) {
  181:             $courseopt{$name}=$value;
  182:         }
  183:     }
  184:     if (! %useropt) {
  185:         my %Tmp = &Apache::lonnet::dump('resourcedata',
  186:                                         $current_domain,$current_name);
  187:         while (my ($name,$value) = each(%Tmp)) {
  188:             if ($name =~ /^error: 2/ || $name =~ /no such file/) {
  189:                 undef(%useropt);
  190:                 last;
  191:             }
  192:             $useropt{$userprefix.$name}=$value;
  193:         }
  194:     }
  195: }
  196: 
  197: ########################################################
  198: ########################################################
  199: 
  200: =pod
  201: 
  202: =head2 assesscalc object methods
  203: 
  204: =cut
  205: 
  206: ########################################################
  207: ########################################################
  208: sub ensure_current_parameter_caches {
  209:     my $self = shift;
  210:     if (! defined($current_course) || 
  211:         $current_course ne $ENV{'request.course.id'} ) {
  212:         $current_course = $ENV{'request.course.id'};
  213:         undef(%courseopt); 
  214:     }
  215:     if (! defined($current_name)   || $current_name ne $self->{'name'} ||
  216:         ! defined($current_domain) || $current_domain ne $self->{'domain'}) {
  217:         $current_domain = $self->{'domain'};
  218:         $current_name   = $self->{'name'};
  219:         undef(%useropt);
  220:     }
  221:     &load_parameter_caches();
  222: }
  223: 
  224: ##################################################
  225: ##################################################
  226: 
  227: =pod
  228: 
  229: =item &parmval()
  230: 
  231: Determine the value of a parameter.
  232: 
  233: Inputs: $what, the parameter needed, $symb, $uname, $udom, $csec 
  234: 
  235: Returns: The value of a parameter, or '' if none.
  236: 
  237: This function cascades through the possible levels searching for a value for
  238: a parameter.  The levels are checked in the following order:
  239: user, course (at section level and course level), map, and lonnet::metadata.
  240: This function uses %parmhash, which must be tied prior to calling it.
  241: This function also requires %courseopt and %useropt to be initialized for
  242: this user and course.
  243: 
  244: =cut
  245: 
  246: ##################################################
  247: ##################################################
  248: sub parmval {
  249:     my $self = shift;
  250:     my ($what,$symb,$uname,$udom,$csec,$recurse)=@_;
  251:     $uname = $self->{'name'}    if (! defined($uname));
  252:     $udom  = $self->{'domain'}  if (! defined($udom));
  253:     $csec  = $self->{'section'} if (! defined($csec));
  254:     $symb  = $self->{'symb'}    if (! defined($symb));
  255:     #
  256:     my $result='';
  257:     #
  258:     # This should be a 
  259:     my ($mapname,$id,$fn)=split(/___/,$symb);
  260:     # Cascading lookup scheme
  261:     my $rwhat=$what;
  262:     $what =~ s/^parameter\_//;
  263:     $what =~ s/\_([^\_]+)$/\.$1/;
  264:     #
  265:     my $symbparm = $symb.'.'.$what;
  266:     my $mapparm  = $mapname.'___(all).'.$what;
  267:     my $courseprefix = $self->{'cid'};
  268:     my $usercourseprefix = $uname.'_'.$udom.'_'.$self->{'cid'};
  269:     #
  270:     my $seclevel  = $courseprefix.'.['.$csec.'].'.$what;
  271:     my $seclevelr = $courseprefix.'.['.$csec.'].'.$symbparm;
  272:     my $seclevelm = $courseprefix.'.['.$csec.'].'.$mapparm;
  273:     #
  274:     my $courselevel  = $courseprefix.'.'.$what;
  275:     my $courselevelr = $courseprefix.'.'.$symbparm;
  276:     my $courselevelm = $courseprefix.'.'.$mapparm;
  277:     #
  278:     my $ucourselevel  = $usercourseprefix.'.'.$what;
  279:     my $ucourselevelr = $usercourseprefix.'.'.$symbparm;
  280:     my $ucourselevelm = $usercourseprefix.'.'.$mapparm;
  281:    # check user
  282:     if (defined($uname)) {
  283:         return $useropt{$ucourselevelr} if (defined($useropt{$ucourselevelr}));
  284:         return $useropt{$ucourselevelm} if (defined($useropt{$ucourselevelm}));
  285:         return $useropt{$ucourselevel}  if (defined($useropt{$ucourselevel}));
  286:     }
  287:     # check section
  288:     if (defined($csec)) {
  289:         return $courseopt{$seclevelr} if (defined($courseopt{$seclevelr}));
  290:         return $courseopt{$seclevelm} if (defined($courseopt{$seclevelm}));
  291:         return $courseopt{$seclevel}  if (defined($courseopt{$seclevel}));
  292:     }
  293:     #
  294:     # check course
  295:     return $courseopt{$courselevelr} if (defined($courseopt{$courselevelr}));
  296:     return $courseopt{$courselevelm} if (defined($courseopt{$courselevelm}));
  297:     return $courseopt{$courselevel}  if (defined($courseopt{$courselevel}));
  298:     # check map parms
  299:     my $thisparm = $parmhash{$symbparm};
  300:     return $thisparm if (defined($thisparm));
  301:     # check default
  302:     $thisparm = &Apache::lonnet::metadata($fn,$rwhat.'.default');
  303:     return $thisparm if (defined($thisparm));
  304:     #
  305:     # Cascade Up
  306:     my $space=$what;
  307:     $space=~s/\.\w+$//;
  308:     if ($space ne '0') {
  309: 	my @parts=split(/_/,$space);
  310: 	my $id=pop(@parts);
  311: 	my $part=join('_',@parts);
  312: 	if ($part eq '') { $part='0'; }
  313: 	my $newwhat=$rwhat;
  314: 	$newwhat=~s/\Q$space\E/$part/;
  315: 	my $partgeneral=$self->parmval($newwhat,$symb,$uname,$udom,$csec,1);
  316: 	if (defined($partgeneral)) { return $partgeneral; }
  317:     }
  318:     if ($recurse) { return undef; }
  319:     my $pack_def=&Apache::lonnet::packages_tab_default($fn,'resource.'.$what);
  320:     if (defined($pack_def)) { return $pack_def; }
  321:     #nothing defined
  322:     return '';
  323: }
  324: 
  325: sub get_html_title {
  326:     my $self = shift;
  327:     my ($assess_title,$name,$time) = $self->get_title();
  328:     my $title = '<h1>'.$assess_title.'</h1>'.
  329:         '<h2>'.$name.', '.
  330:         &Apache::loncommon::aboutmewrapper
  331:                          ($self->{'name'}.'@'.$self->{'domain'},
  332:                           $self->{'name'},$self->{'domain'});
  333:     $title .= '<h3>'.$time.'</h3>';
  334:     return $title;
  335: }
  336: 
  337: sub get_title {
  338:     my $self = shift;
  339:     my @title = ();
  340:     if (($self->{'symb'} eq '_feedback') ||
  341:         ($self->{'symb'} eq '_evaluation') ||
  342:         ($self->{'symb'} eq '_discussion') ||
  343:         ($self->{'symb'} eq '_tutoring')) {
  344:         my $assess_title = ucfirst($self->{'symb'});
  345:         $assess_title =~ s/^_//;
  346:         push(@title,$assess_title);
  347:     } else {
  348:         push(@title,&Apache::lonnet::gettitle($self->{'symb'}));
  349:     }
  350:     # Look up the users identifying information
  351:     # Get the users information
  352:     my %userenv = &Apache::loncoursedata::GetUserName($self->{'name'},
  353:                                                       $self->{'domain'});
  354:     my $name = 
  355:         join(' ',@userenv{'firstname','middlename','lastname','generation'});
  356:     $name =~ s/\s+$//;
  357:     push (@title,$name);
  358:     push (@title,scalar(localtime(time)));
  359:     return @title;
  360: }
  361: 
  362: sub parent_link {
  363:     my $self = shift;
  364:     my $link .= '<p><a href="/adm/studentcalc?'.
  365:         'sname='.$self->{'name'}.
  366:             '&sdomain='.$self->{'domain'}.'">'.
  367:                 'Student level sheet</a></p>'."\n";
  368:     return $link;
  369: }
  370: 
  371: sub outsheet_html {
  372:     my $self = shift;
  373:     my ($r) = @_;
  374:     ###################################
  375:     # Determine table structure
  376:     ###################################
  377:     my $importcolor = '#FFFFFF';
  378:     my $exportcolor = '#FFFFAA';
  379:     my $num_uneditable = 1;
  380:     my $num_left = 52-$num_uneditable;
  381:     my $tableheader =<<"END";
  382: <table border="2">
  383: <tr>
  384:   <th colspan="2" rowspan="2"><font size="+2">Assessment</font></th>
  385:   <td bgcolor="$importcolor" colspan="$num_uneditable">&nbsp;</td>
  386:   <td colspan="$num_left">
  387:       <b><font size="+1">Calculations</font></b></td>
  388: </tr><tr>
  389: END
  390:     my $label_num = 0;
  391:     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
  392:         if ($label_num<$num_uneditable) { 
  393:             $tableheader .= '<td bgcolor="'.$importcolor.'">';
  394:         } else {
  395:             $tableheader .= '<td>';
  396:         }
  397:         $tableheader .= "<b><font size=+1>$_</font></b></td>";
  398:         $label_num++;
  399:     }
  400:     $tableheader.="</tr>\n";
  401:     #
  402:     $r->print($tableheader);
  403:     #
  404:     # Print out template row
  405:     $r->print('<tr><td>Template</td><td>&nbsp;</td>'.
  406: 	      $self->html_template_row($num_uneditable,$importcolor).
  407:               "</tr>\n");
  408:     #
  409:     # Print out summary/export row
  410:     $r->print('<tr><td>Export</td><td>0</td>'.
  411: 	      $self->html_export_row($exportcolor)."</tr>\n");
  412:     #
  413:     # Prepare to output rows
  414:     $tableheader =<<"END";
  415: <table border="2">
  416: <tr><th>row</th><th>Item</th>
  417: END
  418:     foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){
  419: 	if ($label_num<$num_uneditable) { 
  420:             $tableheader.='<th bgcolor="'.$importcolor.'">';
  421:         } else {
  422:             $tableheader.='<th>';
  423:         }
  424:         $tableheader.="<b><font size=+1>$_</font></b></th>";
  425:     }
  426:     #
  427:     my $num_output = 0;
  428:     foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
  429: 	if ($num_output++ % 50 == 0) {
  430: 	    $r->print("</table>\n".$tableheader);
  431: 	}
  432: 	$r->print('<tr><td>'.$rownum.'</td>'.
  433:                   $self->assess_html_row($rownum,$importcolor)."</tr>\n");
  434:     }
  435:     $r->print("</table>\n");
  436:     return;
  437: }
  438: 
  439: sub assess_html_row {
  440:     my $self = shift();
  441:     my ($row,$importcolor) = @_;
  442:     my $parameter_name = $self->{'formulas'}->{'A'.$row};
  443:     my @rowdata = $self->get_row($row);
  444:     my $num_cols_output = 0;
  445:     my $row_html;
  446:     if (exists($nice_parameter_name{$parameter_name})) {
  447:         my $name = $nice_parameter_name{$parameter_name};
  448:         $name =~ s/ /\&nbsp;/g;
  449:         $row_html .= '<td>'.$name.'<br />'.$parameter_name.'</td>';
  450:     } else {
  451:         $row_html .= '<td>'.$parameter_name.'</td>';
  452:     }
  453:     foreach my $cell (@rowdata) {
  454:         if ($num_cols_output < 1) {
  455:             $row_html .= '<td bgcolor="'.$importcolor.'">';
  456:             $row_html .= &Apache::Spreadsheet::html_uneditable_cell($cell,
  457:                                                                     '#FFDDDD');
  458:         } else {
  459:             $row_html .= '<td bgcolor="#EOFFDD">';
  460:             $row_html .= &Apache::Spreadsheet::html_editable_cell($cell,
  461:                                                                   '#E0FFDD',1);
  462:         }
  463: 	$row_html .= '</td>';
  464:         $num_cols_output++;
  465:     }
  466:     return $row_html;
  467: }
  468: 
  469: sub csv_rows {
  470:     # writes the meat of the spreadsheet to an excel worksheet.  Called
  471:     # by Spreadsheet::outsheet_excel;
  472:     my $self = shift;
  473:     my ($filehandle) = @_;
  474:     #
  475:     # Write a header row
  476:     $self->csv_output_row($filehandle,undef,
  477:                           ('Parameter','Description','Value'));
  478:     #
  479:     # Write each row
  480:     foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
  481:         my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
  482:         my $description = '';
  483:         if (exists($nice_parameter_name{$parameter_name})) {
  484:             $description = $nice_parameter_name{$parameter_name};
  485:         }
  486:         $self->csv_output_row($filehandle,$rownum,
  487:                               $parameter_name,$description);
  488:     }
  489:     return;
  490: }
  491: 
  492: sub excel_rows {
  493:     # writes the meat of the spreadsheet to an excel worksheet.  Called
  494:     # by Spreadsheet::outsheet_excel;
  495:     my $self = shift;
  496:     my ($worksheet,$cols_output,$rows_output) = @_;
  497:     #
  498:     # Write a header row
  499:     $cols_output = 0;
  500:     foreach my $value ('Parameter','Description','Value') {
  501:         $worksheet->write($rows_output,$cols_output++,$value);
  502:     }
  503:     $rows_output++;    
  504:     #
  505:     # Write each row
  506:     foreach my $rownum (sort {$a <=> $b} ($self->rows())) {
  507:         my $parameter_name = $self->{'formulas'}->{'A'.$rownum};
  508:         my $description = '';
  509:         if (exists($nice_parameter_name{$parameter_name})) {
  510:             $description = $nice_parameter_name{$parameter_name};
  511:         }
  512:         $self->excel_output_row($worksheet,$rownum,$rows_output++,
  513:                                 $parameter_name,$description);
  514:     }
  515:     return;
  516: }
  517: 
  518: sub compute {
  519:     my $self = shift;
  520: #    $self->logthis('computing');
  521:     $self->initialize_safe_space();
  522:     #########################################
  523:     #########################################
  524:     ###                                   ###
  525:     ###  Retrieve the problem parameters  ###
  526:     ###                                   ###
  527:     #########################################
  528:     #########################################
  529:     my @Mandatory_parameters = ("stores_0_solved",
  530:                                 "stores_0_awarddetail",
  531:                                 "stores_0_awarded",
  532:                                 "timestamp",
  533:                                 "stores_0_tries",
  534:                                 "stores_0_award");
  535:     #
  536:     # Definitions
  537:     undef(%nice_parameter_name);
  538:     my %parameters;   # holds underscored parameters by name
  539:     #
  540:     # Get the metadata fields and determine their proper names
  541:     my ($symap,$syid,$srcf)=split(/___/,$self->{'symb'});
  542:     my @Metadata = split(/\,/,&Apache::lonnet::metadata($srcf,'keys'));
  543:     foreach my $parm (@Mandatory_parameters,@Metadata) {
  544:         next if ($parm !~ /^(resource\.|stores|parameter)_/);
  545:         my $cleaned_name = $parm;
  546:         $cleaned_name =~ s/^resource\./stores_/;
  547:         $cleaned_name =~ s/\./_/g;
  548:         my $display = &Apache::lonnet::metadata($srcf,
  549:                                                 $cleaned_name.'.display');
  550:         if (! $display) {
  551:             $display .= &Apache::lonnet::metadata($srcf,$cleaned_name.'.name');
  552:         }
  553:         $parameters{$cleaned_name}++;
  554:         $nice_parameter_name{$cleaned_name} = $display;
  555:     }
  556:     #
  557:     # Get the values of the metadata fields
  558:     $self->ensure_current_parameter_caches();
  559:     my $filename = $self->{'coursefilename'}.'_parms.db';
  560:     if (tie(%parmhash,'GDBM_File',
  561:             $self->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) {
  562:         foreach my $parmname (keys(%parameters)) {
  563:             my $value = $self->parmval($parmname);
  564:             $parameters{$parmname} =$value;
  565:         }
  566:         untie(%parmhash);
  567:     } else {
  568:         $self->logthis('unable to tie '.$filename);
  569:     }
  570:     #
  571:     # Clean out unnecessary parameters
  572:     foreach (keys(%parameters)) {
  573:         delete($parameters{$_}) if (! /(resource\.|stores_|parameter_)/);
  574:     }
  575:     #
  576:     # Get the students performance data
  577:     my %student_parameters = 
  578:         &Apache::loncoursedata::get_current_state($self->{'name'},
  579:                                                   $self->{'domain'},
  580:                                                   $self->{'symb'},
  581:                                                   $self->{'cid'});
  582:     while (my ($parm,$value) = each(%student_parameters)) {
  583:         $parm =~ s/^resource\./stores_/;
  584:         $parm =~ s/\./_/g;
  585:         $parameters{$parm} = $value;
  586:     }
  587:     #
  588:     # Set up the formulas and parameter values
  589:     my %f=$self->formulas();
  590:     my %c;
  591:     #
  592:     # Check for blackout requirements
  593:     if ((!exists($ENV{'request.role.adv'}) || !$ENV{'request.role.adv'})) {
  594:         while (my ($parm,$value) = each(%parameters)) {
  595:             last if ($self->blackout());
  596:             next if ($parm !~ /^(parameter_.*)_problemstatus$/);
  597:             next if ($parameters{$1.'_answerdate'}<time);
  598:             if (lc($value) eq 'no') {
  599:                 # We must blackout this sheet
  600:                 $self->blackout(1);
  601:             }
  602:         }
  603:     }
  604:     #
  605:     # Move the parameters into the spreadsheet
  606:     while (my ($parm,$value) = each(%parameters)) {
  607:         my $cell = 'A'.$self->get_row_number_from_key($parm);
  608:         $f{$cell} = $parm;
  609:         $value = '"'.$value.'"' if ($value =~/[^0-9.]/);
  610:         $c{$parm} = $value;
  611:     }
  612:     $self->formulas(\%f);
  613:     $self->constants(\%c);
  614:     $self->calcsheet();
  615:     #
  616:     # Store export row in cache
  617:     my @exportarray = $self->exportrow();
  618:     $Exportrows{$self->{'symb'}}->{'time'} = time;
  619:     $Exportrows{$self->{'symb'}}->{$self->{'filename'}} = \@exportarray;
  620:     #
  621:     # Save the export data
  622:     $self->save_export_data();
  623:     $self->save() if ($self->need_to_save());
  624:     return;
  625: }
  626: 
  627: ##
  628: ## sett overrides Spreadsheet::sett
  629: ##
  630: sub sett {
  631:     my $self = shift;
  632:     my %t=();
  633:     #
  634:     # Deal with the template row by copying the template formulas into each
  635:     # row.
  636:     foreach my $col ($self->template_cells()) {
  637:         next if ($col=~/^A/);
  638:         foreach my $row ($self->rows()) {
  639:             # Get the name of this cell
  640:             my $cell=$col.$row;
  641:             # Grab the template declaration
  642:             $t{$cell}=$self->formula('template_'.$col);
  643:             # Replace '#' with the row number
  644:             $t{$cell}=~s/\#/$row/g;
  645:             # Replace '....' with ','
  646:             $t{$cell}=~s/\.\.+/\,/g;
  647:             # Replace 'A0' with the value from 'A0'
  648:             $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
  649:             # Replace parameters
  650:             $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/ge;
  651:         }
  652:     }
  653:     #
  654:     # Deal with the cells which have formulas
  655:     while (my ($cell,$formula) = each(%{$self->{'formulas'}})) {
  656: 	next if ($cell =~ /template_/);
  657:         if ($cell =~ /^A/ && $cell ne 'A0') {
  658:             if ($formula !~ /^\!/) {
  659:                 $t{$cell}=$self->{'constants'}->{$formula};
  660:             }
  661:         } else {
  662:             $t{$cell}=$formula;
  663:             $t{$cell}=~s/\.\.+/\,/g;
  664:             $t{$cell}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$sheet_values\{\'$2\'\}/g;
  665:             $t{$cell}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.$self->expandnamed($2)/ge;
  666:         }
  667:     }
  668:     # Put %t into the safe space
  669:     %{$self->{'safe'}->varglob('t')}=%t;
  670: }
  671: 
  672: 
  673: ########################################################
  674: ########################################################
  675: 
  676: =pod
  677: 
  678: =item &load_cached_export_rows()
  679: 
  680: Retrieves and parsers the export rows of the assessment spreadsheets.
  681: These rows are saved in the students directory in the format:
  682: 
  683:  sname:sdom:assesscalc:symb.time => time
  684: 
  685:  sname:sdom:assesscalc:symb => filename___=___Adata___;___Bdata___;___ ...
  686: 
  687: =cut
  688: 
  689: ########################################################
  690: ########################################################
  691: sub load_cached_export_rows {
  692:     %Exportrows = undef;
  693:     my @tmp = &Apache::lonnet::dump('nohist_calculatedsheets_'.
  694:                                     $ENV{'request.course.id'},
  695:                                     $current_domain,$current_name,undef);
  696:     if ($tmp[0]!~/^error/) {
  697:         my %tmp = @tmp;
  698:         my $default_filename =  $ENV{'course.'.$ENV{'request.course.id'}.
  699:                                          '.spreadsheet_default_assesscalc'};
  700:         # We only got one key, so we will access it directly.
  701:         while (my ($key,$sheetdata) = each(%tmp)) {
  702:             my ($sname,$sdom,$sheettype,$symb) = split(':',$key);
  703:             if ($symb =~ /\.time$/) {
  704:                 $symb =~ s/\.time$//;
  705:                 $Exportrows{$symb}->{'time'} = $sheetdata;
  706:             } else {
  707:                 $sheetdata =~ s/^(.*)___=___//;
  708:                 my $filename = $1;
  709:                 $filename = $default_filename if (! defined($filename));
  710:                 my @Data = split('___;___',$sheetdata);
  711:                 $Exportrows{$symb}->{$filename} = \@Data;
  712:             }
  713:         }
  714:     }
  715: }
  716: 
  717: #############################################
  718: #############################################
  719: 
  720: =pod
  721: 
  722: =item &export_data
  723: 
  724: Returns the export data associated with the spreadsheet.  Computes the
  725: spreadsheet only if necessary.
  726: 
  727: =cut
  728: 
  729: #############################################
  730: #############################################
  731: sub export_data {
  732:     my $self = shift;
  733:     my $symb = $self->{'symb'};
  734:     if (! exists($ENV{'request.role.adv'}) || ! $ENV{'request.role.adv'} ||
  735:         ! exists($Exportrows{$symb}) || ! defined($Exportrows{$symb})  ||
  736:         ! $self->check_expiration_time($Exportrows{$symb}->{'time'}) ||
  737:         ! exists($Exportrows{$symb}->{$self->{'filename'}}) ||
  738:         ! defined($Exportrows{$symb}->{$self->{'filename'}})) {
  739:         $self->compute();
  740:     }
  741:     my @Data = @{$Exportrows{$symb}->{$self->{'filename'}}};
  742:     if ($Data[0] =~ /^(.*)___=___/) {
  743:         $self->{'sheetname'} = $1;
  744:         $Data[0] =~ s/^(.*)___=___//;
  745:     }
  746:     for (my $i=0;$i<$#Data;$i++) {
  747:         $Data[$i]="'".$Data[$i]."'" if ($Data[$i]=~/\D/ && defined($Data[$i]));
  748:     }
  749:     return @Data;
  750: }
  751: 
  752: #############################################
  753: #############################################
  754: 
  755: =pod
  756: 
  757: =item &save_export_data()
  758: 
  759: Writes the export data for this spreadsheet to the students cache.
  760: 
  761: =cut
  762: 
  763: #############################################
  764: #############################################
  765: sub save_export_data {
  766:     my $self = shift;
  767:     return if ($self->temporary());
  768:     my $student = $self->{'name'}.':'.$self->{'domain'};
  769:     my $symb    = $self->{'symb'};
  770:     if (! exists($Exportrows{$symb}) || 
  771:         ! exists($Exportrows{$symb}->{$self->{'filename'}})) {
  772:         return;
  773:     }
  774:     my $key = join(':',($self->{'name'},$self->{'domain'},'assesscalc',$symb));
  775:     my $timekey = $key.'.time';
  776:     my $newstore= join('___;___',@{$Exportrows{$symb}->{$self->{'filename'}}});
  777:     $newstore = $self->{'filename'}.'___=___'.$newstore;
  778:     my $result = &Apache::lonnet::put
  779:         ('nohist_calculatedsheets_'.$ENV{'request.course.id'},
  780:          { $key     => $newstore,
  781:            $timekey => $Exportrows{$symb}->{'time'} },
  782:          $self->{'domain'},
  783:          $self->{'name'});
  784: 
  785:     return;
  786: }
  787: 
  788: 1;
  789: 
  790: __END__

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