--- loncom/interface/Attic/lonspreadsheet.pm 2001/01/20 12:29:37 1.35 +++ loncom/interface/Attic/lonspreadsheet.pm 2001/03/10 22:30:18 1.42 @@ -3,10 +3,11 @@ # # 11/11,11/15,11/27,12/04,12/05,12/06,12/07, # 12/08,12/09,12/11,12/12,12/15,12/16,12/18,12/19,12/30, -# 01/01/01,02/01,03/01,19/01,20/01 Gerd Kortemeyer +# 01/01/01,02/01,03/01,19/01,20/01,22/01, +# 03/05,03/08,03/10 Gerd Kortemeyer package Apache::lonspreadsheet; - + use strict; use Safe; use Safe::Hole; @@ -17,6 +18,13 @@ use GDBM_File; use HTML::TokeParser; # +# Cache for stores of an individual user +# + +my $cachedassess; +my %cachedstores; + +# # These cache hashes need to be independent of user, resource and course # (user and course can/should be in the keys) # @@ -44,7 +52,7 @@ my $tmpdir; # ===================================== Implements an instance of a spreadsheet sub initsheet { - my $safeeval = new Safe; + my $safeeval = new Safe(shift); my $safehole = new Safe::Hole; $safeeval->permit("entereval"); $safeeval->permit(":base_math"); @@ -61,11 +69,11 @@ sub initsheet { # c: preloaded constants (A-column) # rl: row label -%v=(); -%t=(); -%f=(); -%c=(); -%rl=(); +undef %v; +undef %t; +undef %f; +undef %c; +undef %rl; $maxrow=0; $sheettype=''; @@ -309,6 +317,7 @@ sub sett { $t{$lb}=~s/\#/$trow/g; $t{$lb}=~s/\.\.+/\,/g; $t{$lb}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; + $t{$lb}=~s/(^|[^\"\'])\[(\w+)\]/$1\$c\{\'$2\'\}/g; } } } keys %f; @@ -317,7 +326,8 @@ sub sett { } keys %f; map { if (($f{$_}) && ($_!~/template\_/)) { - if ($_=~/^$pattern/) { + my $matches=($_=~/^$pattern(\d+)/); + if (($matches) && ($1)) { unless ($f{$_}=~/^\!/) { $t{$_}=$c{$_}; } @@ -325,12 +335,14 @@ sub sett { $t{$_}=$f{$_}; $t{$_}=~s/\.\.+/\,/g; $t{$_}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; + $t{$_}=~s/(^|[^\"\'])\[([\w\.]+)\]/$1\$c\{\'$2\'\}/g; } } } keys %f; $t{'A0'}=$f{'A0'}; $t{'A0'}=~s/\.\.+/\,/g; $t{'A0'}=~s/(^|[^\"\'])([A-Za-z]\d+)/$1\$v\{\'$2\'\}/g; + $t{'A0'}=~s/(^|[^\"\'])\[([\w\.]+)\]/$1\$c\{\'$2\'\}/g; } sub calc { @@ -779,7 +791,7 @@ sub readsheet { sub makenewsheet { my ($uname,$udom,$stype,$usymb)=@_; - my $safeeval=initsheet(); + my $safeeval=initsheet($stype); $safeeval->reval( '$uname="'.$uname. '";$udom="'.$udom. @@ -1083,8 +1095,8 @@ sub updatestudentassesssheet { &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}). '___'.$resid.'___'. &Apache::lonnet::declutter($srcf); - $allassess{$symb}=$bighash{'title_'.$id}; - + $allassess{$symb}= + ''.$bighash{'title_'.$id}.''; if ($stype eq 'assesscalc') { map { if (($_=~/^stores\_(.*)/) || ($_=~/^parameter\_(.*)/)) { @@ -1092,9 +1104,10 @@ sub updatestudentassesssheet { my $display= &Apache::lonnet::metadata($srcf,$key.'.display'); unless ($display) { - $display= + $display.= &Apache::lonnet::metadata($srcf,$key.'.name'); } + $display.='
'.$key; $allkeys{$key}=$display; } } split(/\,/,&Apache::lonnet::metadata($srcf,'keys')); @@ -1116,8 +1129,6 @@ sub updatestudentassesssheet { } $updatedata{$ENV{'request.course.fn'}.'_'.$stype}= join('___;___',%current); - undef %allkeys; - undef %allassess; } else { return 'Could not access course data'; } @@ -1171,19 +1182,40 @@ sub loadstudent { my $safeeval=shift; my %c=(); my %f=&getformulas($safeeval); + $cachedassess=&getuname($safeeval).':'.&getudom($safeeval); + %cachedstores=(); + { + my $reply=&Apache::lonnet::reply('dump:'.&getudom($safeeval).':'. + &getuname($safeeval).':'. + &getcid($safeeval), + &getuhome($safeeval)); + unless ($reply=~/^error\:/) { + map { + my ($name,$value)=split(/\=/,$_); + $cachedstores{&Apache::lonnet::unescape($name)}= + &Apache::lonnet::unescape($value); + } split(/\&/,$reply); + } + } + my @assessdata=(); map { if ($_=~/^A(\d+)/) { my $row=$1; - unless ($f{$_}=~/^\!/) { - my @assessdata=&exportsheet(&getuname($safeeval), - &getudom($safeeval), - 'assesscalc',$f{$_}); + unless (($f{$_}=~/^\!/) || ($row==0)) { + @assessdata=&exportsheet(&getuname($safeeval), + &getudom($safeeval), + 'assesscalc',$f{$_}); my $index=0; map { if ($assessdata[$index]) { - $c{$_.$row}=$assessdata[$index]; - unless ($_ eq 'A') { - $f{$_.$row}='import'; + my $col=$_; + if ($assessdata[$index]=~/\D/) { + $c{$col.$row}="'".$assessdata[$index]."'"; + } else { + $c{$col.$row}=$assessdata[$index]; + } + unless ($col eq 'A') { + $f{$col.$row}='import'; } } $index++; @@ -1192,6 +1224,8 @@ sub loadstudent { } } } keys %f; + $cachedassess=''; + undef %cachedstores; &setformulas($safeeval,%f); &setconstants($safeeval,%c); } @@ -1199,25 +1233,54 @@ sub loadstudent { # --------------------------------------------------- Load data for one student sub loadcourse { - my $safeeval=shift; + my ($safeeval,$r)=@_; my %c=(); my %f=&getformulas($safeeval); + my $total=0; + map { + if ($_=~/^A(\d+)/) { + unless ($f{$_}=~/^\!/) { $total++; } + } + } keys %f; + my $now=0; + my $since=time; + $r->print(< + popwin=open('','popwin','width=400,height=100'); + popwin.document.writeln(''+ + '

Spreadsheet Calculation Progress

'+ + '
'+ + '
'+ + ''); + popwin.document.close(); + popwin.close(); + +ENDPOP + $r->rflush(); map { if ($_=~/^A(\d+)/) { my $row=$1; - unless (($f{$_}=~/^\!/) -|| ($row>200)) - { - my @studentdata=&exportsheet(&getuname($safeeval), - &getudom($safeeval), + unless (($f{$_}=~/^\!/) || ($row==0)) { + my @studentdata=&exportsheet(split(/\:/,$f{$_}), 'studentcalc'); - undef %userrdatas; + undef %userrdatas; + $now++; + $r->print(''); + $r->rflush(); + my $index=0; map { if ($studentdata[$index]) { - $c{$_.$row}=$studentdata[$index]; - unless ($_ eq 'A') { - $f{$_.$row}='import'; + my $col=$_; + if ($studentdata[$index]=~/\D/) { + $c{$col.$row}="'".$studentdata[$index]."'"; + } else { + $c{$col.$row}=$studentdata[$index]; + } + unless ($col eq 'A') { + $f{$col.$row}='import'; } } $index++; @@ -1228,6 +1291,8 @@ sub loadcourse { } keys %f; &setformulas($safeeval,%f); &setconstants($safeeval,%c); + $r->print(''); + $r->rflush(); } # ------------------------------------------------ Load data for one assessment @@ -1248,11 +1313,31 @@ sub loadassessment { unless ($namespace=$cid) { return ''; } # ----------------------------------------------------------- Get stored values + + my %returnhash=(); + + if ($cachedassess eq $uname.':'.$udom) { +# +# get data out of the dumped stores +# + + my $version=$cachedstores{'version:'.$symb}; + my $scope; + for ($scope=1;$scope<=$version;$scope++) { + map { + $returnhash{$_}=$cachedstores{$scope.':'.$symb.':'.$_}; + } split(/\:/,$cachedstores{$scope.':keys:'.$symb}); + } + + } else { +# +# restore individual +# + my $answer=&Apache::lonnet::reply( "restore:$udom:$uname:". &Apache::lonnet::escape($namespace).":". &Apache::lonnet::escape($symb),$uhome); - my %returnhash=(); map { my ($name,$value)=split(/\=/,$_); $returnhash{&Apache::lonnet::unescape($name)}= @@ -1264,6 +1349,7 @@ sub loadassessment { $returnhash{$_}=$returnhash{$version.':'.$_}; } split(/\:/,$returnhash{$version.':keys'}); } + } # ----------------------------- returnhash now has all stores for this resource # ---------------------------- initialize coursedata and userdata for this user @@ -1287,7 +1373,7 @@ sub loadassessment { my ($name,$value)=split(/\=/,$_); $courseopt{$userprefix.&Apache::lonnet::unescape($name)}= &Apache::lonnet::unescape($value); - } split(/\&/,$courserdatas{$ENV{'request.course.id'}}); + } split(/\&/,$courserdatas{$cid}); # --------------------------------------------------- Get userdata (if present) unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) { @@ -1304,7 +1390,6 @@ sub loadassessment { &Apache::lonnet::unescape($value); } split(/\&/,$userrdatas{$uname.'___'.$udom}); } - # ----------------- now courseopt, useropt initialized for this user and course # (used by parmval) @@ -1317,12 +1402,16 @@ sub loadassessment { if ($_=~/^A/) { unless ($f{$_}=~/^\!/) { if ($f{$_}=~/^parameter/) { - $c{$_}=&parmval($f{$_},$safeeval); + my $val=&parmval($f{$_},$safeeval); + $c{$_}=$val; + $c{$f{$_}}=$val; } else { my $key=$f{$_}; + my $ckey=$key; $key=~s/^stores\_/resource\./; $key=~s/\_/\./; $c{$_}=$returnhash{$key}; + $c{$ckey}=$returnhash{$key}; } } } @@ -1376,11 +1465,11 @@ sub updatesheet { # Import the data for rows # -sub loadrows() { - my $safeeval=shift; +sub loadrows { + my ($safeeval,$r)=@_; my $stype=&gettype($safeeval); if ($stype eq 'classcalc') { - &loadcourse($safeeval); + &loadcourse($safeeval,$r); } elsif ($stype eq 'studentcalc') { &loadstudent($safeeval); } else { @@ -1394,15 +1483,14 @@ sub loadrows() { # sub exportsheet { + my ($uname,$udom,$stype,$usymb,$fn)=@_; my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb); &readsheet($thissheet,$fn); &updatesheet($thissheet); &loadrows($thissheet); &calcsheet($thissheet); - my @returnthis=&exportdata($thissheet); - undef $thissheet; - return @returnthis; + return &exportdata($thissheet); } # ================================================================ Main handler @@ -1576,9 +1664,18 @@ ENDSCRIPT # ----------------------------------------------------- Update sheet, load rows + $r->print("Loaded sheet, updating rows ...
\n"); + $r->rflush(); + &updatesheet($asheet); - &loadrows($asheet); + $r->print("Updated rows, loading row data ...
\n"); + $r->rflush(); + + &loadrows($asheet,$r); + + $r->print("Loaded row data, calculating sheet ...
\n"); + $r->rflush(); my $calcoutput=&calcsheet($asheet); $r->print('

'.$calcoutput.'

'); @@ -1586,10 +1683,6 @@ ENDSCRIPT &outsheet($r,$asheet); $r->print(''); -# --------------------------------- We know this leaks, so terminate this child - - $r->child_terminate(); - # ------------------------------------------------------------------------ Done } else { # ----------------------------- Not in a course, or not allowed to modify parms