--- loncom/interface/Attic/lonspreadsheet.pm 2002/10/21 17:59:36 1.119 +++ loncom/interface/Attic/lonspreadsheet.pm 2002/10/22 18:54:53 1.123 @@ -1,5 +1,5 @@ # -# $Id: lonspreadsheet.pm,v 1.119 2002/10/21 17:59:36 matthew Exp $ +# $Id: lonspreadsheet.pm,v 1.123 2002/10/22 18:54:53 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -208,7 +208,6 @@ sub initsheet { $safeeval->deny(":base_io"); $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT'); $safehole->wrap(\&Apache::lonspreadsheet::mask,$safeeval,'&mask'); - $safehole->wrap(\&Apache::lonspreadsheet::templaterow,$safeeval,'&templaterow'); $safeeval->share('$@'); my $code=<<'ENDDEFS'; # ---------------------------------------------------- Inside of the safe space @@ -755,7 +754,6 @@ parametername should be a string such as sub MINPARM { my ($expression) = @_; my $min = undef; - study($expression); foreach $parameter (keys(%c)) { next if ($parameter !~ /$expression/); if ((! defined($min)) || ($min > $c{$parameter})) { @@ -778,7 +776,6 @@ parametername should be a string such as sub MAXPARM { my ($expression) = @_; my $max = undef; - study($expression); foreach $parameter (keys(%c)) { next if ($parameter !~ /$expression/); if ((! defined($min)) || ($max < $c{$parameter})) { @@ -830,7 +827,6 @@ sub expandnamed { my $returnvalue = ''; my @matches = (); $#matches = -1; - study $expression; foreach $parameter (keys(%c)) { push @matches,$parameter if ($parameter =~ /$expression/); } @@ -919,57 +915,60 @@ sub sett { $t{'A0'}=~s/(^|[^\"\'])\[([^\]]+)\]/$1.&expandnamed($2)/ge; } -sub calc { - undef %sheet_values; - &sett(); - my $notfinished=1; - my $lastcalc=''; - my $depth=0; - while ($notfinished) { - $notfinished=0; - foreach (keys(%t)) { - my $old=$sheet_values{$_}; - $sheet_values{$_}=eval $t{$_}; - if ($@) { - undef %sheet_values; - return $_.': '.$@; - } - if ($sheet_values{$_} ne $old) { $notfinished=1; $lastcalc=$_; } - } - $depth++; - if ($depth>100) { - undef %sheet_values; - return $lastcalc.': Maximum calculation depth exceeded'; - } - } - return ''; +# ------------------------------------------- End of "Inside of the safe space" +ENDDEFS + $safeeval->reval($code); + return $safeeval; } # # This is actually used for the student spreadsheet, not the assessment sheet # Do not be fooled by the name! # +sub templaterow { + my $sheet = shift; + my @cols=(); + $cols[0]='Template'; + foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', + 'a','b','c','d','e','f','g','h','i','j','k','l','m', + 'n','o','p','q','r','s','t','u','v','w','x','y','z') { + my $fm=$sheet->{'f'}->{'template_'.$_}; + $fm=~s/[\'\"]/\&\#34;/g; + push(@cols,"'template_$_','$fm'".'___eq___'.$fm); + } + return @cols; +} + + sub outrowassess { # $n is the current row number - my $n=shift; + my $sheet = shift; + my $n=shift; + my $csv = $ENV{'form.showcsv'}; my @cols=(); if ($n) { - my ($usy,$ufn)=split(/__&&&\__/,$f{'A'.$n}); - if ($rowlabel{$usy}) { - $cols[0]=$rowlabel{$usy}.'
'. + my ($usy,$ufn)=split(/__&&&\__/,$sheet->{'f'}->{'A'.$n}); + if ($sheet->{'rowlabel'}->{$usy}) { + $cols[0]=$sheet->{'rowlabel'}->{$usy}; + if (! $csv) { + $cols[0].='
'. ''; } - $cols[0].=''; } else { $cols[0]='Export'; } @@ -977,18 +976,19 @@ sub outrowassess { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z') { - my $fm=$f{$_.$n}; + my $fm=$sheet->{'f'}->{$_.$n}; $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n}); + push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n}); } return @cols; } sub outrow { + my $sheet=shift; my $n=shift; my @cols=(); if ($n) { - $cols[0]=$rowlabel{$f{'A'.$n}}; + $cols[0]=$sheet->{'rowlabel'}->{$sheet->{'f'}->{'A'.$n}}; } else { $cols[0]='Export'; } @@ -996,53 +996,55 @@ sub outrow { 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z') { - my $fm=$f{$_.$n}; + my $fm=$sheet->{'f'}->{$_.$n}; $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n}); + push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n}); } return @cols; } -sub exportrowa { - my @exportarray=(); - foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', - 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z') { - push(@exportarray,$sheet_values{$_.'0'}); - } - return @exportarray; -} - -sub templaterow { - my @cols=(); - $cols[0]='Template'; - foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', - 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', - 'a','b','c','d','e','f','g','h','i','j','k','l','m', - 'n','o','p','q','r','s','t','u','v','w','x','y','z') { - my $fm=$f{'template_'.$_}; - $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'template_$_','$fm'".'___eq___'.$fm); - } - return @cols; +# ------------------------------------------------ Add or change formula values +sub update_values { + my $sheet = shift; + %{$sheet->{'safe'}->varglob('sheet_values')}=%{$sheet->{'values'}}; + return undef; } - -# ------------------------------------------- End of "Inside of the safe space" -ENDDEFS - $safeeval->reval($code); - return $safeeval; +sub setvalues { + my $sheet=shift; + my ($values) = @_; + $values = {} if (! defined($values)); + if (! ref($values)) { + my %tmp = @_; + $values = \%tmp; + } + $sheet->{'values'} = $values; + %{$sheet->{'safe'}->varglob('sheet_values')}=%{$sheet->{'values'}}; + return undef; } - -# ------------------------------------------------ Add or change formula values sub setformulas { - my ($sheet)=shift; + my $sheet=shift; + my ($formulas) = @_; + $formulas = {} if (! defined($formulas)); + if (! ref($formulas)) { + my %tmp = @_; + $formulas = \%tmp; + } + $sheet->{'f'} = $formulas; %{$sheet->{'safe'}->varglob('f')}=%{$sheet->{'f'}}; + return undef; } # ------------------------------------------------ Add or change formula values sub setconstants { my ($sheet)=shift; + my ($constants) = @_; + if (! ref($constants)) { + my %tmp = @_; + $constants = \%tmp; + } + $sheet->{'constants'} = $constants; return %{$sheet->{'safe'}->varglob('c')}=%{$sheet->{'constants'}}; } @@ -1064,7 +1066,38 @@ sub setrowlabels { # ------------------------------------------------------- Calculate spreadsheet sub calcsheet { my $sheet=shift; - return $sheet->{'safe'}->reval('&calc();'); + &setvalues($sheet,undef); + $sheet->{'safe'}->reval('&sett();'); + my %t = %{$sheet->{'safe'}->varglob('t')}; + my $notfinished=1; + my $lastcalc=''; + my $depth=0; + while ($notfinished) { + $notfinished=0; + foreach (keys(%t)) { + my $old=$sheet->{'values'}->{$_}; + $sheet->{'values'}->{$_}=$sheet->{'safe'}->reval($t{$_}.';'); + if ($@) { + &setvalues($sheet,undef); + return $_.': '.$@; + } + if ($sheet->{'values'}->{$_} ne $old) { + $notfinished=1; + $lastcalc=$_; + } + } + if ($notfinished) { + %{$sheet->{'safe'}->varglob('sheet_values')} = + %{$sheet->{'values'}}; + } + + $depth++; + if ($depth>100) { + &setvalues($sheet,undef); + return $lastcalc.': Maximum calculation depth exceeded'; + } + } + return ; } # ---------------------------------------------------------------- Get formulas @@ -1083,10 +1116,14 @@ sub getfa { # ------------------------------------------------------------- Export of A-row sub exportdata { my $sheet=shift; - return $sheet->{'safe'}->reval('&exportrowa()'); + my @exportarray=(); + foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', + 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z') { + push(@exportarray,$sheet->{'values'}->{$_.'0'}); + } + return @exportarray; } - # ========================================================== End of Spreadsheet # ============================================================================= @@ -1111,27 +1148,32 @@ sub rown { $rowdata.="\n".'"'.$n.'"'; } my $showf=0; - my $proc; + # + # Determine how many pink (uneditable) cells there are in this sheet. my $maxred=1; my $sheettype=$sheet->{'sheettype'}; if ($sheettype eq 'studentcalc') { - $proc='&outrowassess'; $maxred=26; - } else { - $proc='&outrow'; - } - if ($sheettype eq 'assesscalc') { + } elsif ($sheettype eq 'assesscalc') { $maxred=1; } else { $maxred=26; } - if (&getfa($sheet,$n)=~/^[\~\-]/) { $maxred=1; } + $maxred=1 if (&getfa($sheet,$n)=~/^[\~\-]/); + # + # Get the proper row + my @rowdata; if ($n eq '-') { - $proc='&templaterow'; + @rowdata = &templaterow($sheet); $n=-1; $dataflag=1; + } elsif ($sheettype eq 'studentcalc') { + @rowdata = &outrowassess($sheet,$n); + } else { + @rowdata = &outrow($sheet,$n); } - foreach ($sheet->{'safe'}->reval($proc.'('.$n.')')) { + # + foreach (@rowdata) { my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD'); my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_); if ((($vl ne '') || ($vl eq '0')) && @@ -1339,8 +1381,7 @@ sub readsheet { my $fstring=''; if ($fstring=$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}) { my %tmp = split(/___;___/,$fstring); - $sheet->{'f'} = \%tmp; - &setformulas($sheet); + &setformulas($sheet,\%tmp); } else { # Not cached, need to read my %f=(); @@ -1375,8 +1416,7 @@ sub readsheet { } # Cache and set $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f); - $sheet->{'f'}=\%f; - &setformulas($sheet); + &setformulas($sheet,\%f); } } @@ -1522,8 +1562,7 @@ sub tmpread { } else { if ($nfield) { $fo{$nfield}=$nform; } } - $sheet->{'f'}=\%fo; - &setformulas($sheet); + &setformulas($sheet,\%fo); } ################################################## @@ -1653,7 +1692,7 @@ sub updateclasssheet { } $existing{$f{$_}}=1; unless ((defined($currentlist{$f{$_}})) || (!$1) || - ($f{$_}=~/^(\~\~\~|\-\-\-)/)) { + ($f{$_}=~/^(~~~|---)/)) { $f{$_}='!!! Obsolete'; $changed=1; } @@ -1669,8 +1708,7 @@ sub updateclasssheet { } } if ($changed) { - $sheet->{'f'} = \%f; - &setformulas($sheet,%f); + &setformulas($sheet,\%f); } # $sheet->{'rowlabel'} = \%currentlist; @@ -1710,16 +1748,26 @@ sub updatestudentassesssheet { if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})){ $adduserstr='&uname='.$uname.'&udom='.$udom; } - my %allassess = - ('_feedback' =>'Feedback', - '_evaluation' =>'Evaluation', - '_tutoring' =>'Tutoring', - '_discussion' =>'Discussion' - ); + my %allassess; + if (! $ENV{'form.showcsv'}) { + %allassess = + ('_feedback' =>'Feedback', + '_evaluation' =>'Evaluation', + '_tutoring' =>'Tutoring', + '_discussion' =>'Discussion' + ); + } else { + %allassess = + ('_feedback' => "Feedback", + '_evaluation' => "Evaluation", + '_tutoring' => "Tutoring", + '_discussion' => "Discussion", + ); + } while (($_,undef) = each(%bighash)) { next if ($_!~/^src\_(\d+)\.(\d+)$/); my $mapid=$1; @@ -1730,9 +1778,13 @@ sub updatestudentassesssheet { my $symb= &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}). '___'.$resid.'___'.&Apache::lonnet::declutter($srcf); - $allassess{$symb}= - ''. - $bighash{'title_'.$id}.''; + if (! $ENV{'form.showcsv'}) { + $allassess{$symb}= + ''. + $bighash{'title_'.$id}.''; + } else { + $allassess{$symb}=$bighash{'title_'.$id}; + } next if ($stype ne 'assesscalc'); foreach my $key (split(/\,/, &Apache::lonnet::metadata($srcf,'keys') @@ -1780,7 +1832,7 @@ sub updatestudentassesssheet { $existing{$usy}=1; unless ((exists($sheet->{'rowlabel'}->{$usy}) && (defined($sheet->{'rowlabel'}->{$usy})) || (!$1) || - ($f{$_}=~/^(\~\~\~|\-\-\-)/))){ + ($f{$_}=~/^(~~~|---)/))){ $f{$_}='!!! Obsolete'; $changed=1; } elsif ($ufn) { @@ -1797,8 +1849,7 @@ sub updatestudentassesssheet { } } if ($changed) { - $sheet->{'f'} = \%f; - &setformulas($sheet); + &setformulas($sheet,\%f); } &setrowlabels($sheet); # @@ -1850,10 +1901,8 @@ sub loadstudent { } $cachedassess=''; undef %cachedstores; - $sheet->{'f'} = \%f; - $sheet->{'constants'} = \%c; - &setformulas($sheet); - &setconstants($sheet); + &setformulas($sheet,\%f); + &setconstants($sheet,\%c); } # --------------------------------------------------- Load data for one student @@ -1912,10 +1961,8 @@ ENDPOP } } } - $sheet->{'f'}=\%f; - $sheet->{'constants'}=\%c; - &setformulas($sheet); - &setconstants($sheet); + &setformulas($sheet,\%f); + &setconstants($sheet,\%c); $r->print(''); $r->rflush(); } @@ -2039,8 +2086,7 @@ sub loadassessment { } untie(%parmhash); } - $sheet->{'constants'}=\%c; - &setconstants($sheet); + &setconstants($sheet,\%c); } # --------------------------------------------------------- Various form fields @@ -2113,7 +2159,7 @@ sub forcedrecalc { if ($ENV{'form.forcerecalc'}) { return 1; } unless ($time) { return 1; } if ($stype eq 'assesscalc') { - my $map=(split(/\_\_\_/,$usymb))[0]; + my $map=(split(/___/,$usymb))[0]; if (&checkthis('::assesscalc:',$time) || &checkthis('::assesscalc:'.$map,$time) || &checkthis('::assesscalc:'.$usymb,$time) || @@ -2132,14 +2178,10 @@ sub forcedrecalc { } # ============================================================== Export handler -# -# Non-interactive call from with program -# - sub exportsheet { my ($uname,$udom,$stype,$usymb,$fn)=@_; my @exportarr=(); - if (($usymb=~/^\_(\w+)/) && (!$fn)) { + if (defined($usymb) && ($usymb=~/^\_(\w+)/) && (!$fn)) { $fn='default_'.$1; } # @@ -2148,8 +2190,8 @@ sub exportsheet { my $key=$uname.':'.$udom.':'.$stype.':'.$usymb; my $found=''; if ($oldsheets{$key}) { - foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) { - my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_); + foreach (split(/___&\___/,$oldsheets{$key})) { + my ($name,$value)=split(/___=___/,$_); if ($name eq $fn) { $found=$value; } @@ -2158,8 +2200,8 @@ sub exportsheet { unless ($found) { &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom)); if ($oldsheets{$key}) { - foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) { - my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_); + foreach (split(/___&\___/,$oldsheets{$key})) { + my ($name,$value)=split(/___=___/,$_); if ($name eq $fn) { $found=$value; } @@ -2178,72 +2220,65 @@ sub exportsheet { # # Return what was cached # - @exportarr=split(/\_\_\_\;\_\_\_/,$found); - } else { - # - # Not cached - # - my ($sheet)=&makenewsheet($uname,$udom,$stype,$usymb); - &readsheet($sheet,$fn); - &updatesheet($sheet); - &loadrows($sheet); - &calcsheet($sheet); - @exportarr=&exportdata($sheet); - # - # Store now - # - my $cid=$ENV{'request.course.id'}; - my $current=''; - if ($stype eq 'studentcalc') { - $current=&Apache::lonnet::reply('get:'. - $ENV{'course.'.$cid.'.domain'}.':'. - $ENV{'course.'.$cid.'.num'}. - ':nohist_calculatedsheets:'. - &Apache::lonnet::escape($key), - $ENV{'course.'.$cid.'.home'}); - } else { - $current=&Apache::lonnet::reply('get:'.$sheet->{'udom'}.':'. - $sheet->{'uname'}. - ':nohist_calculatedsheets_'. - $ENV{'request.course.id'}.':'. - &Apache::lonnet::escape($key), - $sheet->{'uhome'}); - } - my %currentlystored=(); - unless ($current=~/^error\:/) { - foreach (split(/___&\___/,&Apache::lonnet::unescape($current))) { - my ($name,$value)=split(/___=___/,$_); - $currentlystored{$name}=$value; - } - } - $currentlystored{$fn}=join('___;___',@exportarr); - # - my $newstore=''; - foreach (keys(%currentlystored)) { - if ($newstore) { $newstore.='___&___'; } - $newstore.=$_.'___=___'.$currentlystored{$_}; - } - my $now=time; - if ($stype eq 'studentcalc') { - &Apache::lonnet::reply('put:'. - $ENV{'course.'.$cid.'.domain'}.':'. - $ENV{'course.'.$cid.'.num'}. - ':nohist_calculatedsheets:'. - &Apache::lonnet::escape($key).'='. - &Apache::lonnet::escape($newstore).'&'. - &Apache::lonnet::escape($key).'.time='.$now, - $ENV{'course.'.$cid.'.home'}); - } else { - &Apache::lonnet::reply('put:'. - $sheet->{'udom'}.':'. - $sheet->{'uname'}. - ':nohist_calculatedsheets_'. - $ENV{'request.course.id'}.':'. - &Apache::lonnet::escape($key).'='. - &Apache::lonnet::escape($newstore).'&'. - &Apache::lonnet::escape($key).'.time='.$now, - $sheet->{'uhome'}); - } + @exportarr=split(/___;___/,$found); + return @exportarr; + } + # + # Not cached + # + my ($sheet)=&makenewsheet($uname,$udom,$stype,$usymb); + &readsheet($sheet,$fn); + &updatesheet($sheet); + &loadrows($sheet); + &calcsheet($sheet); + @exportarr=&exportdata($sheet); + # + # Store now + # + my $cid=$ENV{'request.course.id'}; + my $current=''; + if ($stype eq 'studentcalc') { + $current=&Apache::lonnet::reply('get:'. + $ENV{'course.'.$cid.'.domain'}.':'. + $ENV{'course.'.$cid.'.num'}. + ':nohist_calculatedsheets:'. + &Apache::lonnet::escape($key), + $ENV{'course.'.$cid.'.home'}); + } else { + $current=&Apache::lonnet::reply('get:'.$sheet->{'udom'}.':'. + $sheet->{'uname'}. + ':nohist_calculatedsheets_'. + $ENV{'request.course.id'}.':'. + &Apache::lonnet::escape($key), + $sheet->{'uhome'}); + } + my %currentlystored=(); + unless ($current=~/^error\:/) { + foreach (split(/___&\___/,&Apache::lonnet::unescape($current))) { + my ($name,$value)=split(/___=___/,$_); + $currentlystored{$name}=$value; + } + } + $currentlystored{$fn}=join('___;___',@exportarr); + # + my $newstore=''; + foreach (keys(%currentlystored)) { + if ($newstore) { $newstore.='___&___'; } + $newstore.=$_.'___=___'.$currentlystored{$_}; + } + my $now=time; + if ($stype eq 'studentcalc') { + &Apache::lonnet::put('nohist_calculatedsheets', + { $key => $newstore, + $key.time => $now }, + $ENV{'course.'.$cid.'.domain'}, + $ENV{'course.'.$cid.'.num'}) + } else { + &Apache::lonnet::put('nohist_calculatedsheets_'.$sheet->{'cid'}, + { $key => $newstore, + $key.time => $now }, + $sheet->{'udom'}, + $sheet->{'uname'}) } return @exportarr; } @@ -2451,7 +2486,7 @@ ENDSCRIPT &readsheet($sheet,$ENV{'form.ufn'}); } # Print out user information - unless ($sheet->{'sheettype'} eq 'classcalc') { + if ($sheet->{'sheettype'} ne 'classcalc') { $r->print('

User: '.$sheet->{'uname'}. '
Domain: '.$sheet->{'udom'}); $r->print('
Section/Group: '.$sheet->{'csec'}); @@ -2564,7 +2599,7 @@ ENDSCRIPT $r->print('
Show rows with empty A column: '); } else { $r->print('
Show empty rows: '); - } + } # $r->print(&hiddenfield('userselhidden','true'). 'print('>'); + # + # CSV format checkbox (classcalc sheets only) + $r->print(' Output CSV format: print(' checked') if ($ENV{'form.showcsv'}); + $r->print('>'); if ($sheet->{'sheettype'} eq 'classcalc') { - # - # CSV format checkbox (classcalc sheets only) - $r->print(' Output CSV format: print(' checked'); } - $r->print('>'); - # - # Buttons to insert rows $r->print(' Student Status: '. &Apache::lonhtmlcommon::StatusOptions ($ENV{'form.Status'},'sheet')); } + # + # Buttons to insert rows $r->print(<