Diff for /loncom/interface/Attic/lonspreadsheet.pm between versions 1.104 and 1.127

version 1.104, 2002/08/30 19:47:47 version 1.127, 2002/10/24 15:34:10
Line 26 Line 26
 # The LearningOnline Network with CAPA  # The LearningOnline Network with CAPA
 # Spreadsheet/Grades Display Handler  # Spreadsheet/Grades Display Handler
 #  #
 # 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,22/01,  
 # 03/05,03/08,03/10,03/12,03/13,03/15,03/17,  
 # 03/19,03/20,03/21,03/27,04/05,04/09,  
 # 07/09,07/14,07/21,09/01,09/10,9/11,9/12,9/13,9/14,9/17,  
 # 10/16,10/17,10/20,11/05,11/28,12/27 Gerd Kortemeyer  
 # 01/14/02 Matthew  
 # 02/04/02 Matthew  
   
 # POD required stuff:  # POD required stuff:
   
 =head1 NAME  =head1 NAME
Line 54  not the grades of their peers.  The spre Line 44  not the grades of their peers.  The spre
 offering the ability to use Perl code to manipulate data, as well as many  offering the ability to use Perl code to manipulate data, as well as many
 built-in functions.  built-in functions.
   
   
 =head2 Functions available to user of lonspreadsheet  =head2 Functions available to user of lonspreadsheet
   
 =over 4  =over 4
Line 72  use Apache::Constants qw(:common :http); Line 61  use Apache::Constants qw(:common :http);
 use GDBM_File;  use GDBM_File;
 use HTML::TokeParser;  use HTML::TokeParser;
 use Apache::lonhtmlcommon;  use Apache::lonhtmlcommon;
   use Apache::loncoursedata;
   #
   # Caches for coursewide information 
   #
   my %Section;
   
 #  #
 # Caches for previously calculated spreadsheets  # Caches for previously calculated spreadsheets
 #  #
Line 122  my $tmpdir; Line 117  my $tmpdir;
 # =============================================================================  # =============================================================================
 # ===================================== Implements an instance of a spreadsheet  # ===================================== Implements an instance of a spreadsheet
   
 sub initsheet {  ##
     my $safeeval = new Safe(shift);  ## mask - used to reside in the safe space.  
     my $safehole = new Safe::Hole;  ##
     $safeeval->permit("entereval");  
     $safeeval->permit(":base_math");  
     $safeeval->permit("sort");  
     $safeeval->deny(":base_io");  
     $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');  
     $safeeval->share('$@');  
     my $code=<<'ENDDEFS';  
 # ---------------------------------------------------- Inside of the safe space  
   
 #  
 # f: formulas  
 # t: intermediate format (variable references expanded)  
 # v: output values  
 # c: preloaded constants (A-column)  
 # rl: row label  
 # os: other spreadsheets (for student spreadsheet only)  
   
 undef %sheet_values;   
 undef %t;  
 undef %f;  
 undef %c;  
 undef %rowlabel;  
 undef @os;  
   
 $maxrow = 0;  
 $sheettype = '';  
   
 # filename/reference of the sheet  
 $filename = '';  
   
 # user data  
 $uname = '';  
 $uhome = '';  
 $udom  = '';  
   
 # course data  
   
 $csec = '';  
 $chome= '';  
 $cnum = '';  
 $cdom = '';  
 $cid  = '';  
 $cfn  = '';  
   
 # symb  
   
 $usymb = '';  
   
 # error messages  
 $errormsg = '';  
   
 sub mask {  sub mask {
     my ($lower,$upper)=@_;      my ($lower,$upper)=@_;
       #
     $lower=~/([A-Za-z]|\*)(\d+|\*)/;      my ($la,$ld) = ($lower=~/([A-Za-z]|\*)(\d+|\*)/);
     my $la=$1;      my ($ua,$ud) = ($upper=~/([A-Za-z]|\*)(\d+|\*)/);
     my $ld=$2;      #
   
     $upper=~/([A-Za-z]|\*)(\d+|\*)/;  
     my $ua=$1;  
     my $ud=$2;  
     my $alpha='';      my $alpha='';
     my $num='';      my $num='';
       #
     if (($la eq '*') || ($ua eq '*')) {      if (($la eq '*') || ($ua eq '*')) {
        $alpha='[A-Za-z]';         $alpha='[A-Za-z]';
     } else {      } else {
           
        if (($la=~/[A-Z]/) && ($ua=~/[A-Z]/) ||         if (($la=~/[A-Z]/) && ($ua=~/[A-Z]/) ||
            ($la=~/[a-z]/) && ($ua=~/[a-z]/)) {             ($la=~/[a-z]/) && ($ua=~/[a-z]/)) {
           $alpha='['.$la.'-'.$ua.']';            $alpha='['.$la.'-'.$ua.']';
Line 199  sub mask { Line 140  sub mask {
           $alpha='['.$la.'-Za-'.$ua.']';            $alpha='['.$la.'-Za-'.$ua.']';
        }         }
     }         }   
   
     if (($ld eq '*') || ($ud eq '*')) {      if (($ld eq '*') || ($ud eq '*')) {
  $num='\d+';   $num='\d+';
     } else {      } else {
Line 219  sub mask { Line 159  sub mask {
        } else {         } else {
            my @lda=($ld=~m/\d/g);             my @lda=($ld=~m/\d/g);
            my @uda=($ud=~m/\d/g);             my @uda=($ud=~m/\d/g);
            my $i; $j=0; $notdone=1;             my $i; 
              my $j=0; 
              my $notdone=1;
            for ($i=0;($i<=$#lda)&&($notdone);$i++) {             for ($i=0;($i<=$#lda)&&($notdone);$i++) {
                if ($lda[$i]==$uda[$i]) {                 if ($lda[$i]==$uda[$i]) {
    $num.=$lda[$i];     $num.=$lda[$i];
Line 243  sub mask { Line 185  sub mask {
                }                 }
                $num.=')';                 $num.=')';
            } else {             } else {
                if ($lda[$#lda]!=$uda[$#uda]) {                 if ($lda[-1]!=$uda[-1]) {
                   $num.='['.$lda[$#lda].'-'.$uda[$#uda].']';                    $num.='['.$lda[-1].'-'.$uda[-1].']';
        }         }
            }             }
        }         }
Line 252  sub mask { Line 194  sub mask {
     return '^'.$alpha.$num."\$";      return '^'.$alpha.$num."\$";
 }  }
   
   
   
   sub initsheet {
       my $safeeval = new Safe(shift);
       my $safehole = new Safe::Hole;
       $safeeval->permit("entereval");
       $safeeval->permit(":base_math");
       $safeeval->permit("sort");
       $safeeval->deny(":base_io");
       $safehole->wrap(\&Apache::lonnet::EXT,$safeeval,'&EXT');
       $safehole->wrap(\&Apache::lonspreadsheet::mask,$safeeval,'&mask');
       $safeeval->share('$@');
       my $code=<<'ENDDEFS';
   # ---------------------------------------------------- Inside of the safe space
   
   #
   # f: formulas
   # t: intermediate format (variable references expanded)
   # v: output values
   # c: preloaded constants (A-column)
   # rl: row label
   # os: other spreadsheets (for student spreadsheet only)
   
   undef %sheet_values;   # Holds the (computed, final) values for the sheet
       # This is only written to by &calc, the spreadsheet computation routine.
       # It is read by many functions
   undef %t; # Holds the values of the spreadsheet temporarily. Set in &sett, 
       # which does the translation of strings like C5 into the value in C5.
       # Used in &calc - %t holds the values that are actually eval'd.
   undef %f;    # Holds the formulas for each cell.  This is the users
       # (spreadsheet authors) data for each cell.
       # set by &setformulas and returned by &getformulas
       # &setformulas is called by &readsheet, &tmpread, &updateclasssheet,
       # &updatestudentassesssheet, &loadstudent, &loadcourse
       # &getformulas is called by &writesheet, &tmpwrite, &updateclasssheet,
       # &updatestudentassesssheet, &loadstudent, &loadcourse, &loadassessment, 
   undef %c; # Holds the constants for a sheet.  In the assessment
       # sheets, this is the A column.  Used in &MINPARM, &MAXPARM, &expandnamed,
       # &sett, and &setconstants.  There is no &getconstants.
       # &setconstants is called by &loadstudent, &loadcourse, &load assessment,
   undef @os;  # Holds the names of other spreadsheets - this is used to specify
       # the spreadsheets that are available for the assessment sheet.
       # Set by &setothersheets.  &setothersheets is called by &handler.  A
       # related subroutine is &othersheets.
   
   $maxrow = 0;
   $sheettype = '';
   
   # filename/reference of the sheet
   $filename = '';
   
   # user data
   $uname = '';
   $uhome = '';
   $udom  = '';
   
   # course data
   
   $csec = '';
   $chome= '';
   $cnum = '';
   $cdom = '';
   $cid  = '';
   $coursefilename  = '';
   
   # symb
   
   $usymb = '';
   
   # error messages
   $errormsg = '';
   
   
 #-------------------------------------------------------  #-------------------------------------------------------
   
 =item UWCALC(hashname,modules,units,date)   =item UWCALC(hashname,modules,units,date) 
Line 863  sub sett { Line 878  sub sett {
     }      }
     # Deal with the normal cells      # Deal with the normal cells
     foreach (keys(%f)) {      foreach (keys(%f)) {
  if (($f{$_}) && ($_!~/template\_/)) {   if (exists($f{$_}) && ($_!~/template\_/)) {
             my $matches=($_=~/^$pattern(\d+)/);              my $matches=($_=~/^$pattern(\d+)/);
             if  (($matches) && ($1)) {              if  (($matches) && ($1)) {
         unless ($f{$_}=~/^\!/) {          unless ($f{$_}=~/^\!/) {
Line 924  sub calc { Line 939  sub calc {
     return '';      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 {  sub templaterow {
       my $sheet = shift;
     my @cols=();      my @cols=();
     $cols[0]='<b><font size=+1>Template</font></b>';      $cols[0]='<b><font size=+1>Template</font></b>';
     foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',      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',       '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',       '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') {       'n','o','p','q','r','s','t','u','v','w','x','y','z') {
         my $fm=$f{'template_'.$_};          my $fm=$sheet->{'f'}->{'template_'.$_};
         $fm=~s/[\'\"]/\&\#34;/g;          $fm=~s/[\'\"]/\&\#34;/g;
         push(@cols,"'template_$_','$fm'".'___eq___'.$fm);          push(@cols,"'template_$_','$fm'".'___eq___'.$fm);
     }      }
     return @cols;      return @cols;
 }  }
   
 #  
 # This is actually used for the student spreadsheet, not the assessment sheet  
 # Do not be fooled by the name!  
 #  
 sub outrowassess {  sub outrowassess {
     # $n is the current row number      # $n is the current row number
     my $n=shift;      my $sheet = shift;
       my $n=shift; 
       my $csv = $ENV{'form.showcsv'};
     my @cols=();      my @cols=();
     if ($n) {      if ($n) {
         my ($usy,$ufn)=split(/__&&&\__/,$f{'A'.$n});          my ($usy,$ufn)=split(/__&&&\__/,$sheet->{'f'}->{'A'.$n});
         if ($rowlabel{$usy}) {          if ($sheet->{'rowlabel'}->{$usy}) {
             $cols[0]=$rowlabel{$usy}.'<br>'.              $cols[0]=&format_rowlabel($sheet->{'rowlabel'}->{$usy});
               if (! $csv) {
                   $cols[0].='<br>'.
                 '<select name="sel_'.$n.'" onChange="changesheet('.$n.')">'.                  '<select name="sel_'.$n.'" onChange="changesheet('.$n.')">'.
                     '<option name="default">Default</option>';                      '<option name="default">Default</option>';
               }
         } else {           } else { 
             $cols[0]='';               $cols[0]=''; 
         }          }
         foreach (@os) {          if (! $csv) {
             $cols[0].='<option name="'.$_.'"';              foreach (@{$sheet->{'othersheets'}}) {
             if ($ufn eq $_) {                  $cols[0].='<option name="'.$_.'"';
                 $cols[0].=' selected';                  if ($ufn eq $_) {
                       $cols[0].=' selected';
                   }
                   $cols[0].='>'.$_.'</option>';
             }              }
             $cols[0].='>'.$_.'</option>';              $cols[0].='</select>';
         }          }
         $cols[0].='</select>';  
     } else {      } else {
         $cols[0]='<b><font size=+1>Export</font></b>';          $cols[0]='<b><font size=+1>Export</font></b>';
     }      }
Line 970  sub outrowassess { Line 1000  sub outrowassess {
      'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',       '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',       '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') {       '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;          $fm=~s/[\'\"]/\&\#34;/g;
         push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n});          push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n});
     }      }
     return @cols;      return @cols;
 }  }
   
 sub outrow {  sub outrow {
       my $sheet=shift;
     my $n=shift;      my $n=shift;
     my @cols=();      my @cols=();
     if ($n) {      if ($n) {
        $cols[0]=$rowlabel{$f{'A'.$n}};          $cols[0]=&format_rowlabel($sheet->{'rowlabel'}->{$sheet->{'f'}->{'A'.$n}});
     } else {      } else {
        $cols[0]='<b><font size=+1>Export</font></b>';         $cols[0]='<b><font size=+1>Export</font></b>';
     }      }
Line 989  sub outrow { Line 1020  sub outrow {
      'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',       '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',       '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') {       '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;          $fm=~s/[\'\"]/\&\#34;/g;
         push(@cols,"'$_$n','$fm'".'___eq___'.$sheet_values{$_.$n});          push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n});
     }      }
     return @cols;      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;  
 }  
   
 # ------------------------------------------- End of "Inside of the safe space"  
 ENDDEFS  
     $safeeval->reval($code);  
     return $safeeval;  
 }  
   
 # ------------------------------------------------ Add or change formula values  # ------------------------------------------------ Add or change formula values
   
 sub setformulas {  sub setformulas {
     my ($safeeval,%f)=@_;      my ($sheet)=shift;
     %{$safeeval->varglob('f')}=%f;      %{$sheet->{'safe'}->varglob('f')}=%{$sheet->{'f'}};
 }  }
   
 # ------------------------------------------------ Add or change formula values  # ------------------------------------------------ Add or change formula values
   
 sub setconstants {  sub setconstants {
     my ($safeeval,%c)=@_;      my ($sheet)=shift;
     %{$safeeval->varglob('c')}=%c;      my ($constants) = @_;
       if (! ref($constants)) {
           my %tmp = @_;
           $constants = \%tmp;
       }
       $sheet->{'constants'} = $constants;
       return %{$sheet->{'safe'}->varglob('c')}=%{$sheet->{'constants'}};
 }  }
   
 # --------------------------------------------- Set names of other spreadsheets  # --------------------------------------------- Set names of other spreadsheets
   
 sub setothersheets {  sub setothersheets {
     my ($safeeval,@os)=@_;      my $sheet = shift;
     @{$safeeval->varglob('os')}=@os;      my @othersheets = @_;
       $sheet->{'othersheets'} = \@othersheets;
       @{$sheet->{'safe'}->varglob('os')}=@othersheets;
       return;
 }  }
   
 # ------------------------------------------------ Add or change formula values  # ------------------------------------------------ Add or change formula values
   
 sub setrowlabels {  sub setrowlabels {
     my ($safeeval,%rowlabel)=@_;      my $sheet=shift;
     %{$safeeval->varglob('rowlabel')}=%rowlabel;      my ($rowlabel) = @_;
       if (! ref($rowlabel)) {
           my %tmp = @_;
           $rowlabel = \%tmp;
       }
       $sheet->{'rowlabel'}=$rowlabel;
 }  }
   
 # ------------------------------------------------------- Calculate spreadsheet  # ------------------------------------------------------- Calculate spreadsheet
   
 sub calcsheet {  sub calcsheet {
     my $safeeval=shift;      my $sheet=shift;
     return $safeeval->reval('&calc();');      my $result =  $sheet->{'safe'}->reval('&calc();');
 }      %{$sheet->{'values'}} = %{$sheet->{'safe'}->varglob('sheet_values')};
       return $result;
 # ------------------------------------------------------------------ Get values  
   
 sub getvalues {  
     my $safeeval=shift;  
     return $safeeval->reval('%sheet_values');  
 }  }
   
 # ---------------------------------------------------------------- Get formulas  # ---------------------------------------------------------------- Get formulas
   
 sub getformulas {  sub getformulas {
     my $safeeval=shift;      my $sheet = shift;
     return %{$safeeval->varglob('f')};      return %{$sheet->{'safe'}->varglob('f')};
 }  }
   
 # ----------------------------------------------------- Get value of $f{'A'.$n}  # ----------------------------------------------------- Get value of $f{'A'.$n}
   
 sub getfa {  sub getfa {
     my ($safeeval,$n)=@_;      my $sheet = shift;
     return $safeeval->reval('$f{"A'.$n.'"}');      my ($n)=@_;
 }      return $sheet->{'safe'}->reval('$f{"A'.$n.'"}');
   
 # -------------------------------------------------------------------- Get type  
   
 sub gettype {  
     my $safeeval=shift;  
     return $safeeval->reval('$sheettype');  
 }  
   
 # ------------------------------------------------------------------ Set maxrow  
   
 sub setmaxrow {  
     my ($safeeval,$row)=@_;  
     $safeeval->reval('$maxrow='.$row.';');  
 }  
   
 # ------------------------------------------------------------------ Get maxrow  
   
 sub getmaxrow {  
     my $safeeval=shift;  
     return $safeeval->reval('$maxrow');  
 }  
   
 # ---------------------------------------------------------------- Set filename  
   
 sub setfilename {  
     my ($safeeval,$fn)=@_;  
     $safeeval->reval('$filename="'.$fn.'";');  
 }  
   
 # ---------------------------------------------------------------- Get filename  
   
 sub getfilename {  
     my $safeeval=shift;  
     return $safeeval->reval('$filename');  
 }  
   
 # --------------------------------------------------------------- Get course ID  
   
 sub getcid {  
     my $safeeval=shift;  
     return $safeeval->reval('$cid');  
 }  
   
 # --------------------------------------------------------- Get course filename  
   
 sub getcfn {  
     my $safeeval=shift;  
     return $safeeval->reval('$cfn');  
 }  
   
 # ----------------------------------------------------------- Get course number  
   
 sub getcnum {  
     my $safeeval=shift;  
     return $safeeval->reval('$cnum');  
 }  
   
 # ------------------------------------------------------------- Get course home  
   
 sub getchome {  
     my $safeeval=shift;  
     return $safeeval->reval('$chome');  
 }  
   
 # ----------------------------------------------------------- Get course domain  
   
 sub getcdom {  
     my $safeeval=shift;  
     return $safeeval->reval('$cdom');  
 }  
   
 # ---------------------------------------------------------- Get course section  
   
 sub getcsec {  
     my $safeeval=shift;  
     return $safeeval->reval('$csec');  
 }  
   
 # --------------------------------------------------------------- Get user name  
   
 sub getuname {  
     my $safeeval=shift;  
     return $safeeval->reval('$uname');  
 }  
   
 # ------------------------------------------------------------- Get user domain  
   
 sub getudom {  
     my $safeeval=shift;  
     return $safeeval->reval('$udom');  
 }  
   
 # --------------------------------------------------------------- Get user home  
   
 sub getuhome {  
     my $safeeval=shift;  
     return $safeeval->reval('$uhome');  
 }  
   
 # -------------------------------------------------------------------- Get symb  
   
 sub getusymb {  
     my $safeeval=shift;  
     return $safeeval->reval('$usymb');  
 }  }
   
 # ------------------------------------------------------------- Export of A-row  # ------------------------------------------------------------- Export of A-row
   
 sub exportdata {  sub exportdata {
     my $safeeval=shift;      my $sheet=shift;
     return $safeeval->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  # ========================================================== End of Spreadsheet
 # =============================================================================  # =============================================================================
   
Line 1189  sub exportdata { Line 1106  sub exportdata {
 # --------------------------------------------- Produce output row n from sheet  # --------------------------------------------- Produce output row n from sheet
   
 sub rown {  sub rown {
     my ($safeeval,$n)=@_;      my ($sheet,$n)=@_;
     my $defaultbg;      my $defaultbg;
     my $rowdata='';      my $rowdata='';
     my $dataflag=0;      my $dataflag=0;
     unless ($n eq '-') {      unless ($n eq '-') {
        $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF';          $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF';
     } else {      } else {
        $defaultbg='#E0FF';          $defaultbg='#E0FF';
     }      }
     unless ($ENV{'form.showcsv'}) {      unless ($ENV{'form.showcsv'}) {
        $rowdata.="\n<tr><td><b><font size=+1>$n</font></b></td>";          $rowdata.="\n<tr><td><b><font size=+1>$n</font></b></td>";
     } else {      } else {
        $rowdata.="\n".'"'.$n.'"';          $rowdata.="\n".'"'.$n.'"';
     }      }
     my $showf=0;      my $showf=0;
     my $proc;      #
       # Determine how many pink (uneditable) cells there are in this sheet.
     my $maxred=1;      my $maxred=1;
     my $sheettype=&gettype($safeeval);      my $sheettype=$sheet->{'sheettype'};
     if ($sheettype eq 'studentcalc') {      if ($sheettype eq 'studentcalc') {
         $proc='&outrowassess';  
         $maxred=26;          $maxred=26;
     } else {      } elsif ($sheettype eq 'assesscalc') {
         $proc='&outrow';  
     }  
     if ($sheettype eq 'assesscalc') {  
         $maxred=1;          $maxred=1;
     } else {      } else {
         $maxred=26;          $maxred=26;
     }      }
     if (&getfa($safeeval,$n)=~/^[\~\-]/) { $maxred=1; }      $maxred=1 if (&getfa($sheet,$n)=~/^[\~\-]/);
       #
       # Get the proper row
       my @rowdata;
     if ($n eq '-') {       if ($n eq '-') { 
         $proc='&templaterow';           @rowdata = &templaterow($sheet);
         $n=-1;           $n=-1; 
         $dataflag=1;           $dataflag=1; 
       } elsif ($sheettype eq 'studentcalc') {
           @rowdata = &outrowassess($sheet,$n);
       } else {
           @rowdata = &outrow($sheet,$n);
     }      }
     foreach ($safeeval->reval($proc.'('.$n.')')) {      #
        my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');      foreach (@rowdata) {
        my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);          my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD');
        if ((($vl ne '') || ($vl eq '0')) &&          my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_);
            (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; }          if ((($vl ne '') || ($vl eq '0')) &&
        if ($showf==0) { $vl=$_; }              (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; }
       unless ($ENV{'form.showcsv'}) {          if ($showf==0) { $vl=$_; }
        if ($showf<=$maxred) { $bgcolor='#FFDDDD'; }          unless ($ENV{'form.showcsv'}) {
        if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; }               if ($showf<=$maxred) { $bgcolor='#FFDDDD'; }
        if (($showf>$maxred) || ((!$n) && ($showf>0))) {              if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; } 
    if ($vl eq '') {              if (($showf>$maxred) || ((!$n) && ($showf>0))) {
        $vl='<font size=+2 color='.$bgcolor.'>&#35;</font>';                  if ($vl eq '') {
            }                      $vl='<font size=+2 color='.$bgcolor.'>&#35;</font>';
            $rowdata.=                  }
        '<td bgcolor='.$bgcolor.'><a href="javascript:celledit('.$fm.');">'.$vl.                  $rowdata.='<td bgcolor='.$bgcolor.'>';
        '</a></td>';                  if ($ENV{'request.role'} =~ /^st\./) {
        } else {                      $rowdata.=$vl;
            $rowdata.='<td bgcolor='.$bgcolor.'>&nbsp;'.$vl.'&nbsp;</td>';                  } else {
        }                      $rowdata.='<a href="javascript:celledit('.$fm.');">'.
       } else {                          $vl.'</a>';
   $rowdata.=',"'.$vl.'"';                  }
       }                  $rowdata.='</td>';
        $showf++;              } else {
                   $rowdata.='<td bgcolor='.$bgcolor.'>&nbsp;'.$vl.'&nbsp;</td>';
               }
           } else {
               $rowdata.=',"'.$vl.'"';
           }
           $showf++;
     }  # End of foreach($safeval...)      }  # End of foreach($safeval...)
     if ($ENV{'form.showall'} || ($dataflag)) {      if ($ENV{'form.showall'} || ($dataflag)) {
        return $rowdata.($ENV{'form.showcsv'}?'':'</tr>');          return $rowdata.($ENV{'form.showcsv'}?'':'</tr>');
     } else {      } else {
        return '';          return '';
     }      }
 }  }
   
 # ------------------------------------------------------------- Print out sheet  # ------------------------------------------------------------- Print out sheet
   
 sub outsheet {  sub outsheet {
     my ($r,$safeeval)=@_;      my ($r,$sheet)=@_;
     my $maxred;      my $maxred = 26;    # The maximum number of cells to show as 
     my $realm;                          # red (uneditable) 
     if (&gettype($safeeval) eq 'assesscalc') {                          # To make student sheets uneditable could we 
                           # set $maxred = 52?
                           #
       my $realm='Course'; # 'assessment', 'user', or 'course' sheet
       if ($sheet->{'sheettype'} eq 'assesscalc') {
         $maxred=1;          $maxred=1;
         $realm='Assessment';          $realm='Assessment';
     } elsif (&gettype($safeeval) eq 'studentcalc') {      } elsif ($sheet->{'sheettype'} eq 'studentcalc') {
         $maxred=26;          $maxred=26;
         $realm='User';          $realm='User';
     } else {  
         $maxred=26;  
         $realm='Course';  
     }      }
     my $maxyellow=52-$maxred;      #
       # Column label
     my $tabledata;      my $tabledata;
     unless ($ENV{'form.showcsv'}) {      if ($ENV{'form.showcsv'}) {
        $tabledata=          $tabledata='<pre>';
         '<table border=2><tr><th colspan=2 rowspan=2><font size=+2>'.      } else { 
                   $realm.'</font></th>'.          $tabledata='<table border=2><tr><th colspan=2 rowspan=2>'.
               '<font size=+2>'.$realm.'</font></th>'.
                   '<td bgcolor=#FFDDDD colspan='.$maxred.                    '<td bgcolor=#FFDDDD colspan='.$maxred.
                   '><b><font size=+1>Import</font></b></td>'.                    '><b><font size=+1>Import</font></b></td>'.
                   '<td colspan='.$maxyellow.                    '<td colspan='.(52-$maxred).
   '><b><font size=+1>Calculations</font></b></td></tr><tr>';    '><b><font size=+1>Calculations</font></b></td></tr><tr>';
        my $showf=0;          my $showf=0;
        foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',          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',                   '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',                   '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') {                   'n','o','p','q','r','s','t','u','v','w','x','y','z') {
            $showf++;              $showf++;
            if ($showf<=$maxred) {               if ($showf<=$maxred) { 
                $tabledata.='<td bgcolor="#FFDDDD">';                   $tabledata.='<td bgcolor="#FFDDDD">'; 
            } else {              } else {
                $tabledata.='<td>';                  $tabledata.='<td>';
            }              }
            $tabledata.="<b><font size=+1>$_</font></b></td>";              $tabledata.="<b><font size=+1>$_</font></b></td>";
        }          }
        $tabledata.='</tr>'.&rown($safeeval,'-').&rown($safeeval,0);          $tabledata.='</tr>'.&rown($sheet,'-').
    } else { $tabledata='<pre>'; }              &rown($sheet,0);
       }
     $r->print($tabledata);      $r->print($tabledata);
       #
       # Prepare to output rows
     my $row;      my $row;
     my $maxrow=&getmaxrow($safeeval);      #
   
     my @sortby=();      my @sortby=();
     my @sortidx=();      my @sortidx=();
     for ($row=1;$row<=$maxrow;$row++) {      for ($row=1;$row<=$sheet->{'maxrow'};$row++) {
        $sortby[$row-1]=$safeeval->reval('$f{"A'.$row.'"}');          push (@sortby, $sheet->{'safe'}->reval('$f{"A'.$row.'"}'));
        $sortidx[$row-1]=$row-1;          push (@sortidx, $row-1);
     }      }
     @sortidx=sort { $sortby[$a] cmp $sortby[$b]; } @sortidx;      @sortidx=sort { lc($sortby[$a]) cmp lc($sortby[$b]); } @sortidx;
         my $what='Student';      #
         if (&gettype($safeeval) eq 'assesscalc') {      # Determine the type of child spreadsheets
     $what='Item';      my $what='Student';
  } elsif (&gettype($safeeval) eq 'studentcalc') {      if ($sheet->{'sheettype'} eq 'assesscalc') {
             $what='Assessment';          $what='Item';
         }      } elsif ($sheet->{'sheettype'} eq 'studentcalc') {
           $what='Assessment';
       }
       #
       # Loop through the rows and output them one at a time
     my $n=0;      my $n=0;
     for ($row=0;$row<$maxrow;$row++) {      for ($row=0;$row<$sheet->{'maxrow'};$row++) {
         my $thisrow=&rown($safeeval,$sortidx[$row]+1);          my $thisrow=&rown($sheet,$sortidx[$row]+1);
         if ($thisrow) {          if ($thisrow) {
             if (($n/25==int($n/25)) && (!$ENV{'form.showcsv'})) {              if (($n/25==int($n/25)) && (!$ENV{'form.showcsv'})) {
                 $r->print("</table>\n<br>\n");                  $r->print("</table>\n<br>\n");
                 $r->rflush();                  $r->rflush();
                 $r->print('<table border=2><tr><td>&nbsp;<td>'.$what.'</td>');                  $r->print('<table border=2><tr><td>&nbsp;<td>'.$what.'</td>');
                 $r->print('<td>'.join('</td><td>',                  $r->print('<td>'.
                                       (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.                            join('</td><td>',
                                             'abcdefghijklmnopqrstuvwxyz'))).                                 (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
                                         'abcdefghijklmnopqrstuvwxyz'))).
                           "</td></tr>\n");                            "</td></tr>\n");
             }              }
             $n++;              $n++;
Line 1340  sub outsheet { Line 1274  sub outsheet {
 # ----------------------------------------------- Read list of available sheets  # ----------------------------------------------- Read list of available sheets
 #   # 
 sub othersheets {  sub othersheets {
     my ($safeeval,$stype)=@_;      my ($sheet,$stype)=@_;
       $stype = $sheet->{'sheettype'} if (! defined($stype));
     #      #
     my $cnum  = &getcnum($safeeval);      my $cnum  = $sheet->{'cnum'};
     my $cdom  = &getcdom($safeeval);      my $cdom  = $sheet->{'cdom'};
     my $chome = &getchome($safeeval);      my $chome = $sheet->{'chome'};
     #      #
     my @alternatives=();      my @alternatives=();
     my %results=&Apache::lonnet::dump($stype.'_spreadsheets',$cdom,$cnum);      my %results=&Apache::lonnet::dump($stype.'_spreadsheets',$cdom,$cnum);
Line 1387  sub parse_sheet { Line 1322  sub parse_sheet {
 #  #
 # -------------------------------------- Read spreadsheet formulas for a course  # -------------------------------------- Read spreadsheet formulas for a course
 #  #
   
 sub readsheet {  sub readsheet {
     my ($safeeval,$fn)=@_;      my ($sheet,$fn)=@_;
     my $stype = &gettype($safeeval);      #
     my $cnum  = &getcnum($safeeval);      my $stype = $sheet->{'sheettype'};
     my $cdom  = &getcdom($safeeval);      my $cnum  = $sheet->{'cnum'};
     my $chome = &getchome($safeeval);      my $cdom  = $sheet->{'cdom'};
       my $chome = $sheet->{'chome'};
       #
     if (! defined($fn)) {      if (! defined($fn)) {
         # There is no filename. Look for defaults in course and global, cache          # There is no filename. Look for defaults in course and global, cache
         unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {          unless ($fn=$defaultsheets{$cnum.'_'.$cdom.'_'.$stype}) {
Line 1414  sub readsheet { Line 1349  sub readsheet {
         }          }
     }      }
     # $fn now has a value      # $fn now has a value
     &setfilename($safeeval,$fn);      $sheet->{'filename'} = $fn;
     # see if sheet is cached      # see if sheet is cached
     my $fstring='';      my $fstring='';
     if ($fstring=$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}) {      if ($fstring=$spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}) {
         &setformulas($safeeval,split(/\_\_\_\;\_\_\_/,$fstring));          my %tmp = split(/___;___/,$fstring);
           $sheet->{'f'} = \%tmp;
           &setformulas($sheet);
     } else {      } else {
         # Not cached, need to read          # Not cached, need to read
         my %f=();          my %f=();
Line 1453  sub readsheet { Line 1390  sub readsheet {
         }          }
         # Cache and set          # Cache and set
         $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);            $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);  
         &setformulas($safeeval,%f);          $sheet->{'f'}=\%f;
           &setformulas($sheet);
     }      }
 }  }
   
 # -------------------------------------------------------- Make new spreadsheet  # -------------------------------------------------------- Make new spreadsheet
   
 sub makenewsheet {  sub makenewsheet {
     my ($uname,$udom,$stype,$usymb)=@_;      my ($uname,$udom,$stype,$usymb)=@_;
     my $safeeval=initsheet($stype);      my $sheet={};
     $safeeval->reval(      $sheet->{'uname'} = $uname;
        '$uname="'.$uname.      $sheet->{'udom'}  = $udom;
       '";$udom="'.$udom.      $sheet->{'sheettype'} = $stype;
       '";$uhome="'.&Apache::lonnet::homeserver($uname,$udom).      $sheet->{'usymb'} = $usymb;
       '";$sheettype="'.$stype.      $sheet->{'cid'}   = $ENV{'request.course.id'};
       '";$usymb="'.$usymb.      $sheet->{'csec'}  = $Section{$uname.':'.$udom};
       '";$csec="'.&Apache::lonnet::usection($udom,$uname,      $sheet->{'coursefilename'}   = $ENV{'request.course.fn'};
                                             $ENV{'request.course.id'}).      $sheet->{'cnum'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.num'};
       '";$cid="'.$ENV{'request.course.id'}.      $sheet->{'cdom'}  = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'};
       '";$cfn="'.$ENV{'request.course.fn'}.      $sheet->{'chome'} = $ENV{'course.'.$ENV{'request.course.id'}.'.home'};
       '";$cnum="'.$ENV{'course.'.$ENV{'request.course.id'}.'.num'}.      $sheet->{'uhome'} = &Apache::lonnet::homeserver($uname,$udom);
       '";$cdom="'.$ENV{'course.'.$ENV{'request.course.id'}.'.domain'}.      #
       '";$chome="'.$ENV{'course.'.$ENV{'request.course.id'}.'.home'}.'";');      #
     return $safeeval;      $sheet->{'f'} = {};
       $sheet->{'constants'} = {};
       $sheet->{'othersheets'} = [];
       $sheet->{'rowlabel'} = {};
       #
       #
       $sheet->{'safe'}=&initsheet($sheet->{'sheettype'});
       #
       # Place all the %$sheet items into the safe space except the safe space
       # itself
       my $initstring = '';
       foreach (qw/uname udom sheettype usymb cid csec coursefilename
                cnum cdom chome uhome/) {
           $initstring.= qq{\$$_="$sheet->{$_}";};
       }
       $sheet->{'safe'}->reval($initstring);
       return $sheet;
 }  }
   
 # ------------------------------------------------------------ Save spreadsheet  # ------------------------------------------------------------ Save spreadsheet
   
 sub writesheet {  sub writesheet {
     my ($safeeval,$makedef)=@_;      my ($sheet,$makedef)=@_;
     my $cid=&getcid($safeeval);      my $cid=$sheet->{'cid'};
     if (&Apache::lonnet::allowed('opa',$cid)) {      if (&Apache::lonnet::allowed('opa',$cid)) {
         my %f=&getformulas($safeeval);          my %f=&getformulas($sheet);
         my $stype=&gettype($safeeval);          my $stype= $sheet->{'sheettype'};
         my $cnum=&getcnum($safeeval);          my $cnum = $sheet->{'cnum'};
         my $cdom=&getcdom($safeeval);          my $cdom = $sheet->{'cdom'};
         my $chome=&getchome($safeeval);          my $chome= $sheet->{'chome'};
         my $fn=&getfilename($safeeval);          my $fn   = $sheet->{'filename'};
         # Cache new sheet          # Cache new sheet
         $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);          $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f);
         # Write sheet          # Write sheet
Line 1531  sub writesheet { Line 1483  sub writesheet {
 # ----------------------------------------------- Make a temp copy of the sheet  # ----------------------------------------------- Make a temp copy of the sheet
 # "Modified workcopy" - interactive only  # "Modified workcopy" - interactive only
 #  #
   
 sub tmpwrite {  sub tmpwrite {
     my $safeeval=shift;      my ($sheet) = @_;
     my $fn=$ENV{'user.name'}.'_'.      my $fn=$ENV{'user.name'}.'_'.
         $ENV{'user.domain'}.'_spreadsheet_'.&getusymb($safeeval).'_'.          $ENV{'user.domain'}.'_spreadsheet_'.$sheet->{'usymb'}.'_'.
            &getfilename($safeeval);             $sheet->{'filename'};
     $fn=~s/\W/\_/g;      $fn=~s/\W/\_/g;
     $fn=$tmpdir.$fn.'.tmp';      $fn=$tmpdir.$fn.'.tmp';
     my $fh;      my $fh;
     if ($fh=Apache::File->new('>'.$fn)) {      if ($fh=Apache::File->new('>'.$fn)) {
  print $fh join("\n",&getformulas($safeeval));   print $fh join("\n",&getformulas($sheet));
     }      }
 }  }
   
 # ---------------------------------------------------------- Read the temp copy  # ---------------------------------------------------------- Read the temp copy
   
 sub tmpread {  sub tmpread {
     my ($safeeval,$nfield,$nform)=@_;      my ($sheet,$nfield,$nform)=@_;
     my $fn=$ENV{'user.name'}.'_'.      my $fn=$ENV{'user.name'}.'_'.
            $ENV{'user.domain'}.'_spreadsheet_'.&getusymb($safeeval).'_'.             $ENV{'user.domain'}.'_spreadsheet_'.$sheet->{'usymb'}.'_'.
            &getfilename($safeeval);             $sheet->{'filename'};
     $fn=~s/\W/\_/g;      $fn=~s/\W/\_/g;
     $fn=$tmpdir.$fn.'.tmp';      $fn=$tmpdir.$fn.'.tmp';
     my $fh;      my $fh;
Line 1587  sub tmpread { Line 1537  sub tmpread {
     } else {      } else {
        if ($nfield) { $fo{$nfield}=$nform; }         if ($nfield) { $fo{$nfield}=$nform; }
     }      }
     &setformulas($safeeval,%fo);      $sheet->{'f'}=\%fo;
       &setformulas($sheet);
 }  }
   
 ##################################################  ##################################################
Line 1599  sub tmpread { Line 1550  sub tmpread {
   
 Determine the value of a parameter.  Determine the value of a parameter.
   
 Inputs: $what, the parameter needed, $safeeval, the safe space  Inputs: $what, the parameter needed, $sheet, the safe space
   
 Returns: The value of a parameter, or '' if none.  Returns: The value of a parameter, or '' if none.
   
Line 1615  this user and course. Line 1566  this user and course.
 ##################################################  ##################################################
 ##################################################  ##################################################
 sub parmval {  sub parmval {
     my ($what,$safeeval)=@_;      my ($what,$sheet)=@_;
     my $symb  = &getusymb($safeeval);      my $symb  = $sheet->{'usymb'};
     unless ($symb) { return ''; }      unless ($symb) { return ''; }
     #      #
     my $cid   = &getcid($safeeval);      my $cid   = $sheet->{'cid'};
     my $csec  = &getcsec($safeeval);      my $csec  = $sheet->{'csec'};
     my $uname = &getuname($safeeval);      my $uname = $sheet->{'uname'};
     my $udom  = &getudom($safeeval);      my $udom  = $sheet->{'udom'};
     my $result='';      my $result='';
     #      #
     my ($mapname,$id,$fn)=split(/\_\_\_/,$symb);      my ($mapname,$id,$fn)=split(/\_\_\_/,$symb);
Line 1643  sub parmval { Line 1594  sub parmval {
     my $courselevelr = $usercourseprefix.'.'.$symbparm;      my $courselevelr = $usercourseprefix.'.'.$symbparm;
     my $courselevelm = $usercourseprefix.'.'.$mapparm;      my $courselevelm = $usercourseprefix.'.'.$mapparm;
     # fourth, check user      # fourth, check user
     if ($uname) {       if (defined($uname)) {
         return $useropt{$courselevelr} if ($useropt{$courselevelr});          return $useropt{$courselevelr} if (defined($useropt{$courselevelr}));
         return $useropt{$courselevelm} if ($useropt{$courselevelm});          return $useropt{$courselevelm} if (defined($useropt{$courselevelm}));
         return $useropt{$courselevel} if ($useropt{$courselevel});          return $useropt{$courselevel}  if (defined($useropt{$courselevel}));
     }      }
     # third, check course      # third, check course
     if ($csec) {      if (defined($csec)) {
         return $courseopt{$seclevelr} if ($courseopt{$seclevelr});          return $courseopt{$seclevelr} if (defined($courseopt{$seclevelr}));
         return $courseopt{$seclevelm} if ($courseopt{$seclevelm});          return $courseopt{$seclevelm} if (defined($courseopt{$seclevelm}));
         return $courseopt{$seclevel} if ($courseopt{$seclevel});          return $courseopt{$seclevel}  if (defined($courseopt{$seclevel}));
     }      }
     #      #
     return $courseopt{$courselevelr} if ($courseopt{$courselevelr});      return $courseopt{$courselevelr} if (defined($courseopt{$courselevelr}));
     return $courseopt{$courselevelm} if ($courseopt{$courselevelm});      return $courseopt{$courselevelm} if (defined($courseopt{$courselevelm}));
     return $courseopt{$courselevel} if ($courseopt{$courselevel});      return $courseopt{$courselevel}  if (defined($courseopt{$courselevel}));
     # second, check map parms      # second, check map parms
     my $thisparm = $parmhash{$symbparm};      my $thisparm = $parmhash{$symbparm};
     return $thisparm if ($thisparm);      return $thisparm if (defined($thisparm));
     # first, check default      # first, check default
     return &Apache::lonnet::metadata($fn,$rwhat.'.default');      return &Apache::lonnet::metadata($fn,$rwhat.'.default');
 }  }
   
   sub format_rowlabel {
       my $rowlabel = shift;
       my ($type,$labeldata) = split(':',$rowlabel,2);
       my $result = '';
       if ($type eq 'symb') {
           my ($symb,$uname,$udom,$title) = split(':',$labeldata);
           $symb = &Apache::lonnet::unescape($symb);
           if ($ENV{'form.showcsv'}) {
               $result = $title;
           } else {
               $result = '<a href="/adm/assesscalc?usymb='.$symb.
                   '&uname='.$uname.'&udom='.$udom.'">'.$title.'</a>';
           }
       } elsif ($type eq 'student') {
           my ($sname,$sdom,$fullname,$section,$id) = split(':',$labeldata);
           if ($ENV{'form.showcsv'}) {
               $result = '"'.
                   join('","',($sname,$sdom,$fullname,$section,$id).'"');
           } else {
               $result ='<a href="/adm/studentcalc?uname='.$sname.
                   '&udom='.$sdom.'">';
               $result.=$section.'&nbsp;'.$id."&nbsp;".$fullname.'</a>';
           }
       } elsif ($type eq 'parameter') {
           if ($ENV{'form.showcsv'}) {
               $labeldata =~ s/<br>/ /g;
           }
           $result = $labeldata;
       } else {
           &Apache::lonnet::logthis("lonspreadsheet:bogus rowlabel type: $type");
       }
       return $result;
   }
   
 # ---------------------------------------------- Update rows for course listing  # ---------------------------------------------- Update rows for course listing
 sub updateclasssheet {  sub updateclasssheet {
     my $safeeval=shift;      my ($sheet) = @_;
     my $cnum=&getcnum($safeeval);      my $cnum  =$sheet->{'cnum'};
     my $cdom=&getcdom($safeeval);      my $cdom  =$sheet->{'cdom'};
     my $cid=&getcid($safeeval);      my $cid   =$sheet->{'cid'};
     my $chome=&getchome($safeeval);      my $chome =$sheet->{'chome'};
       #
       %Section = ();
   
     #      #
     # Read class list and row labels      # Read class list and row labels
     my %classlist;      my $classlist = &Apache::loncoursedata::get_classlist();
     my @tmp = &Apache::lonnet::dump('classlist',$cdom,$cnum);      if (! defined($classlist)) {
     if ($tmp[0] !~ /^error/) {          return 'Could not access course classlist';
         %classlist = @tmp;      } 
     } else {  
         return 'Could not access course data';  
     }  
     undef @tmp;  
     #      #
     my %currentlist=();      my %currentlist=();
     my $now=time;      foreach my $student (keys(%$classlist)) {
     foreach my $student (keys(%classlist)) {          my ($studentDomain,$studentName,$end,$start,$id,$studentSection,
         my ($end,$start)=split(/\:/,$classlist{$student});              $fullname,$status)   =   @{$classlist->{$student}};
         my $active=1;          if ($ENV{'form.Status'} eq $status || $ENV{'form.Status'} eq 'Any') {
         $active = 0 if (($end) && ($now>$end));              $currentlist{$student}=join(':',('student',$studentName,
         $active = 1 if ($ENV{'form.Status'} eq 'Any');                                               $studentDomain,$fullname,
         $active = !$active if ($ENV{'form.Status'} eq 'Expired');                                               $studentSection,$id));
         if ($active) {          }
             my $rowlabel='';      }
             my ($studentName,$studentDomain)=split(/\:/,$student);  
             my $studentSection=&Apache::lonnet::usection($studentDomain,  
                                                          $studentName,$cid);  
             if ($studentSection==-1) {  
                 unless ($ENV{'form.showcsv'}) {  
                     $rowlabel='<font color=red>Data not available: '.  
                         $studentName.'</font>';  
                 } else {  
                     $rowlabel='ERROR","'.$studentName.  
                         '","Data not available","","","';  
                 }  
             } else {  
                 my %reply=&Apache::lonnet::idrget($studentDomain,$studentName);  
                 my %studentInformation=&Apache::lonnet::get  
                     ('environment',  
                      ['lastname','generation','firstname','middlename','id'],  
                      $studentDomain,$studentName);  
                 if (! $ENV{'form.showcsv'}) {  
                     $rowlabel='<a href="/adm/studentcalc?uname='.$studentName.  
                         '&udom='.$studentDomain.'">'.  
                             $studentSection.'&nbsp;';  
                     foreach ('id','firstname','middlename',  
                              'lastname','generation'){  
                         $rowlabel.=$studentInformation{$_}."&nbsp;";  
                     }  
                     $rowlabel.='</a>';  
                 } else {  
                     $rowlabel= '"'.join('","',  
                                         ($studentSection,  
                                          $studentInformation{'id'},  
                                          $studentInformation{'firstname'},  
                                          $studentInformation{'middlename'},  
                                          $studentInformation{'lastname'},  
                                          $studentInformation{'generation'})  
                                         ).'"';  
                 }  
             }  
             $currentlist{$student}=$rowlabel;  
         } # end of if ($active)  
     } # end of foreach my $student (keys(%classlist))  
     #      #
     # Find discrepancies between the course row table and this      # Find discrepancies between the course row table and this
     #      #
     my %f=&getformulas($safeeval);      my %f=&getformulas($sheet);
     my $changed=0;      my $changed=0;
     #      #
     my $maxrow=0;      $sheet->{'maxrow'}=0;
     my %existing=();      my %existing=();
     #      #
     # Now obsolete rows      # Now obsolete rows
     foreach (keys(%f)) {      foreach (keys(%f)) {
         if ($_=~/^A(\d+)/) {          if ($_=~/^A(\d+)/) {
             $maxrow=($1>$maxrow)?$1:$maxrow;              if ($1 > $sheet->{'maxrow'}) {
                   $sheet->{'maxrow'}= $1;
               }
             $existing{$f{$_}}=1;              $existing{$f{$_}}=1;
             unless ((defined($currentlist{$f{$_}})) || (!$1) ||              unless ((defined($currentlist{$f{$_}})) || (!$1) ||
                     ($f{$_}=~/^(\~\~\~|\-\-\-)/)) {                      ($f{$_}=~/^(~~~|---)/)) {
                 $f{$_}='!!! Obsolete';                  $f{$_}='!!! Obsolete';
                 $changed=1;                  $changed=1;
             }              }
Line 1759  sub updateclasssheet { Line 1705  sub updateclasssheet {
     foreach (sort keys(%currentlist)) {      foreach (sort keys(%currentlist)) {
         unless ($existing{$_}) {          unless ($existing{$_}) {
             $changed=1;              $changed=1;
             $maxrow++;              $sheet->{'maxrow'}++;
             $f{'A'.$maxrow}=$_;              $f{'A'.$sheet->{'maxrow'}}=$_;
         }          }
     }      }
     if ($changed) { &setformulas($safeeval,%f); }      if ($changed) { 
           $sheet->{'f'} = \%f;
           &setformulas($sheet,%f); 
       }
     #      #
     &setmaxrow($safeeval,$maxrow);      &setrowlabels($sheet,\%currentlist);
     &setrowlabels($safeeval,%currentlist);  
 }  }
   
 # ----------------------------------- Update rows for student and assess sheets  # ----------------------------------- Update rows for student and assess sheets
 sub updatestudentassesssheet {  sub updatestudentassesssheet {
     my $safeeval=shift;      my ($sheet) = @_;
     my %bighash;      my %bighash;
     my $stype=&gettype($safeeval);      my $stype=$sheet->{'sheettype'};
     my %current=();      my $uname=$sheet->{'uname'};
     if  ($updatedata{$ENV{'request.course.fn'}.'_'.$stype}) {      my $udom =$sheet->{'udom'};
         %current=split(/\_\_\_\;\_\_\_/,      $sheet->{'rowlabel'} = {};
        $updatedata{$ENV{'request.course.fn'}.'_'.$stype});      if  ($updatedata
            {$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}) {
           %{$sheet->{'rowlabel'}}=split(/___;___/,
                          $updatedata{$ENV{'request.course.fn'}.
                                          '_'.$stype.'_'.$uname.'_'.$udom});
     } else {      } else {
         # Tie hash          # Tie hash
         tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',          tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db',
Line 1786  sub updatestudentassesssheet { Line 1738  sub updatestudentassesssheet {
             return 'Could not access course data';              return 'Could not access course data';
         }          }
         # Get all assessments          # Get all assessments
           #
           # allkeys is used in the assessment sheets to provide labels
           # for the parameters.
         my %allkeys=('timestamp' =>           my %allkeys=('timestamp' => 
                      'Timestamp of Last Transaction<br>timestamp',                       'parameter:Timestamp of Last Transaction<br>timestamp',
                      'subnumber' =>                       'subnumber' =>
                      'Number of Submissions<br>subnumber',                       'parameter:Number of Submissions<br>subnumber',
                      'tutornumber' =>                       'tutornumber' =>
                      'Number of Tutor Responses<br>tutornumber',                       'parameter:Number of Tutor Responses<br>tutornumber',
                      'totalpoints' =>                       'totalpoints' =>
                      'Total Points Granted<br>totalpoints');                       'parameter:Total Points Granted<br>totalpoints');
         my $adduserstr='';          my $adduserstr='';
         if ((&getuname($safeeval) ne $ENV{'user.name'}) ||          if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})){
             (&getudom($safeeval) ne $ENV{'user.domain'})) {              $adduserstr='&uname='.$uname.'&udom='.$udom;
             $adduserstr='&uname='.&getuname($safeeval).          }
                 '&udom='.&getudom($safeeval);          #
         }          # allassess holds the descriptions of all assessments
         my %allassess =          my %allassess;
             ('_feedback' =>'<a href="/adm/assesscalc?usymb=_feedback'.          foreach ('Feedback','Evaluation','Tutoring','Discussion') {
              $adduserstr.'">Feedback</a>',              my $symb = '_'.lc($_);
              '_evaluation' =>'<a href="/adm/assesscalc?usymb=_evaluation'.              $allassess{$symb} = join(':',('symb',$symb,$uname,$udom,$_));
              $adduserstr.'">Evaluation</a>',          }
              '_tutoring' =>'<a href="/adm/assesscalc?usymb=_tutoring'.          while (($_,undef) = each(%bighash)) {
              $adduserstr.'">Tutoring</a>',  
              '_discussion' =>'<a href="/adm/assesscalc?usymb=_discussion'.  
              $adduserstr.'">Discussion</a>'  
              );  
         foreach (keys(%bighash)) {  
             next if ($_!~/^src\_(\d+)\.(\d+)$/);              next if ($_!~/^src\_(\d+)\.(\d+)$/);
             my $mapid=$1;              my $mapid=$1;
             my $resid=$2;              my $resid=$2;
Line 1820  sub updatestudentassesssheet { Line 1770  sub updatestudentassesssheet {
                 my $symb=                  my $symb=
                     &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}).                      &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}).
                         '___'.$resid.'___'.&Apache::lonnet::declutter($srcf);                          '___'.$resid.'___'.&Apache::lonnet::declutter($srcf);
                 $allassess{$symb}=                  $allassess{$symb}='symb:'.&Apache::lonnet::escape($symb).':'
                     '<a href="/adm/assesscalc?usymb='.$symb.$adduserstr.'">'.                      .$uname.':'.$udom.':'.$bighash{'title_'.$id};
                         $bighash{'title_'.$id}.'</a>';  
                 next if ($stype ne 'assesscalc');                  next if ($stype ne 'assesscalc');
                 foreach my $key (split(/\,/,                  foreach my $key (split(/\,/,
                                        &Apache::lonnet::metadata($srcf,'keys')                                         &Apache::lonnet::metadata($srcf,'keys')
Line 1835  sub updatestudentassesssheet { Line 1784  sub updatestudentassesssheet {
                             &Apache::lonnet::metadata($srcf,$key.'.name');                              &Apache::lonnet::metadata($srcf,$key.'.name');
                     }                      }
                     $display.='<br>'.$key;                      $display.='<br>'.$key;
                     $allkeys{$key}=$display;                      $allkeys{$key}='parameter:'.$display;
                 } # end of foreach                  } # end of foreach
             }              }
         } # end of foreach (keys(%bighash))          } # end of foreach (keys(%bighash))
Line 1845  sub updatestudentassesssheet { Line 1794  sub updatestudentassesssheet {
         # %allassess has a list of all resource displays by symb          # %allassess has a list of all resource displays by symb
         #          #
         if ($stype eq 'assesscalc') {          if ($stype eq 'assesscalc') {
             %current=%allkeys;              $sheet->{'rowlabel'} = \%allkeys;
         } elsif ($stype eq 'studentcalc') {          } elsif ($stype eq 'studentcalc') {
             %current=%allassess;              $sheet->{'rowlabel'} = \%allassess;
         }          }
         $updatedata{$ENV{'request.course.fn'}.'_'.$stype}=          $updatedata{$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}=
             join('___;___',%current);              join('___;___',%{$sheet->{'rowlabel'}});
         # Get current from cache          # Get current from cache
     }      }
     # Find discrepancies between the course row table and this      # Find discrepancies between the course row table and this
     #      #
     my %f=&getformulas($safeeval);      my %f=&getformulas($sheet);
     my $changed=0;      my $changed=0;
           
     my $maxrow=0;      $sheet->{'maxrow'} = 0;
     my %existing=();      my %existing=();
     # Now obsolete rows      # Now obsolete rows
     foreach (keys(%f)) {      foreach (keys(%f)) {
         next if ($_!~/^A(\d+)/);          next if ($_!~/^A(\d+)/);
         $maxrow=($1>$maxrow)?$1:$maxrow;          if ($1 > $sheet->{'maxrow'}) {
         my ($usy,$ufn)=split(/\_\_\&\&\&\_\_/,$f{$_});              $sheet->{'maxrow'} = $1;
           }
           my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
         $existing{$usy}=1;          $existing{$usy}=1;
         unless ((defined($current{$usy})) || (!$1) ||          unless ((exists($sheet->{'rowlabel'}->{$usy}) && 
                 ($f{$_}=~/^(\~\~\~|\-\-\-)/)){                   (defined($sheet->{'rowlabel'}->{$usy})) || (!$1) ||
                   ($f{$_}=~/^(~~~|---)/))){
             $f{$_}='!!! Obsolete';              $f{$_}='!!! Obsolete';
             $changed=1;              $changed=1;
         } elsif ($ufn) {          } elsif ($ufn) {
             $current{$usy}              $sheet->{'rowlabel'}->{$usy}
             =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;                  =~s/assesscalc\?usymb\=/assesscalc\?ufn\=$ufn\&usymb\=/;
         }          }
     }      }
     # New and unknown keys      # New and unknown keys
     foreach (keys(%current)) {      foreach (keys(%{$sheet->{'rowlabel'}})) {
         unless ($existing{$_}) {          unless ($existing{$_}) {
             $changed=1;              $changed=1;
             $maxrow++;              $sheet->{'maxrow'}++;
             $f{'A'.$maxrow}=$_;              $f{'A'.$sheet->{'maxrow'}}=$_;
         }          }
     }      }
     if ($changed) { &setformulas($safeeval,%f); }      if ($changed) { 
     &setmaxrow($safeeval,$maxrow);          $sheet->{'f'} = \%f;
     &setrowlabels($safeeval,%current);          &setformulas($sheet); 
       }
     #      #
     undef %current;  
     undef %existing;      undef %existing;
 }  }
   
 # ------------------------------------------------ Load data for one assessment  # ------------------------------------------------ Load data for one assessment
   
 sub loadstudent {  sub loadstudent {
     my $safeeval=shift;      my ($sheet)=@_;
     my %c=();      my %c=();
     my %f=&getformulas($safeeval);      my %f=&getformulas($sheet);
     $cachedassess=&getuname($safeeval).':'.&getudom($safeeval);      $cachedassess=$sheet->{'uname'}.':'.$sheet->{'udom'};
     # Get ALL the student preformance data      # Get ALL the student preformance data
     my @tmp = &Apache::lonnet::dump(&getcid($safeeval),      my @tmp = &Apache::lonnet::dump($sheet->{'cid'},
                                     &getudom($safeeval),                                      $sheet->{'udom'},
                                     &getuname($safeeval),                                      $sheet->{'uname'},
                                     undef);                                      undef);
     if ($tmp[0] !~ /^error:/) {      if ($tmp[0] !~ /^error:/) {
         %cachedstores = @tmp;          %cachedstores = @tmp;
Line 1914  sub loadstudent { Line 1866  sub loadstudent {
         my $row=$1;          my $row=$1;
         next if (($f{$_}=~/^[\!\~\-]/) || ($row==0));          next if (($f{$_}=~/^[\!\~\-]/) || ($row==0));
         my ($usy,$ufn)=split(/__&&&\__/,$f{$_});          my ($usy,$ufn)=split(/__&&&\__/,$f{$_});
         @assessdata=&exportsheet(&getuname($safeeval),          @assessdata=&exportsheet($sheet->{'uname'},
                                  &getudom($safeeval),                                   $sheet->{'udom'},
                                  'assesscalc',$usy,$ufn);                                   'assesscalc',$usy,$ufn);
         my $index=0;          my $index=0;
         foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',          foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
Line 1936  sub loadstudent { Line 1888  sub loadstudent {
     }      }
     $cachedassess='';      $cachedassess='';
     undef %cachedstores;      undef %cachedstores;
     &setformulas($safeeval,%f);      $sheet->{'f'} = \%f;
     &setconstants($safeeval,%c);      &setformulas($sheet);
       &setconstants($sheet,\%c);
 }  }
   
 # --------------------------------------------------- Load data for one student  # --------------------------------------------------- Load data for one student
   #
 sub loadcourse {  sub loadcourse {
     my ($safeeval,$r)=@_;      my ($sheet,$r)=@_;
     my %c=();      my %c=();
     my %f=&getformulas($safeeval);      my %f=&getformulas($sheet);
     my $total=0;      my $total=0;
     foreach (keys(%f)) {      foreach (keys(%f)) {
  if ($_=~/^A(\d+)/) {   if ($_=~/^A(\d+)/) {
Line 1996  ENDPOP Line 1949  ENDPOP
             }              }
         }          }
     }      }
     &setformulas($safeeval,%f);      $sheet->{'f'}=\%f;
     &setconstants($safeeval,%c);      &setformulas($sheet);
       &setconstants($sheet,\%c);
     $r->print('<script>popwin.close()</script>');      $r->print('<script>popwin.close()</script>');
     $r->rflush();       $r->rflush(); 
 }  }
   
 # ------------------------------------------------ Load data for one assessment  # ------------------------------------------------ Load data for one assessment
   #
 sub loadassessment {  sub loadassessment {
     my $safeeval=shift;      my ($sheet)=@_;
   
     my $uhome = &getuhome($safeeval);      my $uhome = $sheet->{'uhome'};
     my $uname = &getuname($safeeval);      my $uname = $sheet->{'uname'};
     my $udom  = &getudom($safeeval);      my $udom  = $sheet->{'udom'};
     my $symb  = &getusymb($safeeval);      my $symb  = $sheet->{'usymb'};
     my $cid   = &getcid($safeeval);      my $cid   = $sheet->{'cid'};
     my $cnum  = &getcnum($safeeval);      my $cnum  = $sheet->{'cnum'};
     my $cdom  = &getcdom($safeeval);      my $cdom  = $sheet->{'cdom'};
     my $chome = &getchome($safeeval);      my $chome = $sheet->{'chome'};
   
     my $namespace;      my $namespace;
     unless ($namespace=$cid) { return ''; }      unless ($namespace=$cid) { return ''; }
Line 2035  sub loadassessment { Line 1989  sub loadassessment {
         #          #
         # restore individual          # restore individual
         #          #
         my $answer=&Apache::lonnet::reply(          %returnhash = &Apache::lonnet::restore($symb,$namespace,$udom,$uname);
                                           "restore:$udom:$uname:".          for (my $version=1;$version<=$returnhash{'version'};$version++) {
                                           &Apache::lonnet::escape($namespace).":".  
                                           &Apache::lonnet::escape($symb),$uhome);  
         foreach (split(/\&/,$answer)) {  
             my ($name,$value)=split(/\=/,$_);  
             $returnhash{&Apache::lonnet::unescape($name)}=  
                 &Apache::lonnet::unescape($value);  
         }  
         my $version;  
         for ($version=1;$version<=$returnhash{'version'};$version++) {  
             foreach (split(/\:/,$returnhash{$version.':keys'})) {              foreach (split(/\:/,$returnhash{$version.':keys'})) {
                 $returnhash{$_}=$returnhash{$version.':'.$_};                  $returnhash{$_}=$returnhash{$version.':'.$_};
             }               } 
         }          }
     }      }
       #
     # returnhash now has all stores for this resource      # returnhash now has all stores for this resource
     # convert all "_" to "." to be able to use libraries, multiparts, etc      # convert all "_" to "." to be able to use libraries, multiparts, etc
       #
       # This is dumb.  It is also necessary :(
     my @oldkeys=keys %returnhash;      my @oldkeys=keys %returnhash;
       #
     foreach (@oldkeys) {      foreach my $name (@oldkeys) {
         my $name=$_;          my $value=$returnhash{$name};
         my $value=$returnhash{$_};          delete $returnhash{$name};
         delete $returnhash{$_};  
         $name=~s/\_/\./g;          $name=~s/\_/\./g;
         $returnhash{$name}=$value;          $returnhash{$name}=$value;
     }      }
Line 2067  sub loadassessment { Line 2014  sub loadassessment {
     undef %useropt;      undef %useropt;
   
     my $userprefix=$uname.'_'.$udom.'_';      my $userprefix=$uname.'_'.$udom.'_';
       
     unless ($uhome eq 'no_host') {       unless ($uhome eq 'no_host') { 
         # Get coursedata          # Get coursedata
         unless          unless ((time-$courserdatas{$cid.'.last_cache'})<240) {
             ((time-$courserdatas{$cid.'.last_cache'})<240) {              my %Tmp = &Apache::lonnet::dump('resourcedata',$cdom,$cnum);
                 my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.              $courserdatas{$cid}=\%Tmp;
                                                  ':resourcedata',$chome);              $courserdatas{$cid.'.last_cache'}=time;
                 if ($reply!~/^error\:/) {          }
                     $courserdatas{$cid}=$reply;          while (my ($name,$value) = each(%{$courserdatas{$cid}})) {
                     $courserdatas{$cid.'.last_cache'}=time;              $courseopt{$userprefix.$name}=$value;
                 }  
             }  
         foreach (split(/\&/,$courserdatas{$cid})) {  
             my ($name,$value)=split(/\=/,$_);  
             $courseopt{$userprefix.&Apache::lonnet::unescape($name)}=  
                 &Apache::lonnet::unescape($value);    
         }          }
         # Get userdata (if present)          # Get userdata (if present)
         unless          unless ((time-$userrdatas{$uname.'@'.$udom.'.last_cache'})<240) {
             ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {              my %Tmp = &Apache::lonnet::dump('resourcedata',$udom,$uname);
                 my $reply=              $userrdatas{$cid} = \%Tmp;
                     &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);              # Most of the time the user does not have a 'resourcedata.db' 
                 if ($reply!~/^error\:/) {              # file.  We need to cache that we got nothing instead of bothering
                     $userrdatas{$uname.'___'.$udom}=$reply;              # with requesting it every time.
                     $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;              $userrdatas{$uname.'@'.$udom.'.last_cache'}=time;
                 }          }
             }          while (my ($name,$value) = each(%{$userrdatas{$cid}})) {
         foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) {              $useropt{$userprefix.$name}=$value;
             my ($name,$value)=split(/\=/,$_);  
             $useropt{$userprefix.&Apache::lonnet::unescape($name)}=  
                 &Apache::lonnet::unescape($value);  
         }          }
     }      }
     # now courseopt, useropt initialized for this user and course      # now courseopt, useropt initialized for this user and course
Line 2115  sub loadassessment { Line 2053  sub loadassessment {
     #      #
     my %c=();      my %c=();
     if (tie(%parmhash,'GDBM_File',      if (tie(%parmhash,'GDBM_File',
             &getcfn($safeeval).'_parms.db',&GDBM_READER(),0640)) {              $sheet->{'coursefilename'}.'_parms.db',&GDBM_READER(),0640)) {
         my %f=&getformulas($safeeval);          my %f=&getformulas($sheet);
         foreach (keys(%f))  {          foreach my $cell (keys(%f))  {
             next if ($_!~/^A/);              next if ($cell !~ /^A/);
             next if  ($f{$_}=~/^[\!\~\-]/);              next if  ($f{$cell} =~/^[\!\~\-]/);
             if ($f{$_}=~/^parameter/) {              if ($f{$cell}=~/^parameter/) {
                 if ($thisassess{$f{$_}}) {                  if (defined($thisassess{$f{$cell}})) {
                     my $val=&parmval($f{$_},$safeeval);                      my $val       = &parmval($f{$cell},$sheet);
                     $c{$_}=$val;                      $c{$cell}     = $val;
                     $c{$f{$_}}=$val;                      $c{$f{$cell}} = $val;
                 }                  }
             } else {              } else {
                 my $key=$f{$_};                  my $key=$f{$cell};
                 my $ckey=$key;                  my $ckey=$key;
                 $key=~s/^stores\_/resource\./;                  $key=~s/^stores\_/resource\./;
                 $key=~s/\_/\./g;                  $key=~s/\_/\./g;
                 $c{$_}=$returnhash{$key};                  $c{$cell}=$returnhash{$key};
                 $c{$ckey}=$returnhash{$key};                  $c{$ckey}=$returnhash{$key};
             }              }
         }          }
         untie(%parmhash);          untie(%parmhash);
     }      }
     &setconstants($safeeval,%c);      &setconstants($sheet,\%c);
 }  }
   
 # --------------------------------------------------------- Various form fields  # --------------------------------------------------------- Various form fields
Line 2170  sub selectbox { Line 2108  sub selectbox {
 #  #
   
 sub updatesheet {  sub updatesheet {
     my $safeeval=shift;      my ($sheet)=@_;
     my $stype=&gettype($safeeval);      my $stype=$sheet->{'sheettype'};
     if ($stype eq 'classcalc') {      if ($stype eq 'classcalc') {
  return &updateclasssheet($safeeval);   return &updateclasssheet($sheet);
     } else {      } else {
         return &updatestudentassesssheet($safeeval);          return &updatestudentassesssheet($sheet);
     }      }
 }  }
   
Line 2185  sub updatesheet { Line 2123  sub updatesheet {
 #  #
   
 sub loadrows {  sub loadrows {
     my ($safeeval,$r)=@_;      my ($sheet,$r)=@_;
     my $stype=&gettype($safeeval);      my $stype=$sheet->{'sheettype'};
     if ($stype eq 'classcalc') {      if ($stype eq 'classcalc') {
  &loadcourse($safeeval,$r);   &loadcourse($sheet,$r);
     } elsif ($stype eq 'studentcalc') {      } elsif ($stype eq 'studentcalc') {
         &loadstudent($safeeval);          &loadstudent($sheet);
     } else {      } else {
         &loadassessment($safeeval);          &loadassessment($sheet);
     }      }
 }  }
   
Line 2210  sub forcedrecalc { Line 2148  sub forcedrecalc {
     if ($ENV{'form.forcerecalc'}) { return 1; }      if ($ENV{'form.forcerecalc'}) { return 1; }
     unless ($time) { return 1; }      unless ($time) { return 1; }
     if ($stype eq 'assesscalc') {      if ($stype eq 'assesscalc') {
         my $map=(split(/\_\_\_/,$usymb))[0];          my $map=(split(/___/,$usymb))[0];
         if (&checkthis('::assesscalc:',$time) ||          if (&checkthis('::assesscalc:',$time) ||
             &checkthis('::assesscalc:'.$map,$time) ||              &checkthis('::assesscalc:'.$map,$time) ||
             &checkthis('::assesscalc:'.$usymb,$time) ||              &checkthis('::assesscalc:'.$usymb,$time) ||
Line 2229  sub forcedrecalc { Line 2167  sub forcedrecalc {
 }  }
   
 # ============================================================== Export handler  # ============================================================== Export handler
 #  
 # Non-interactive call from with program  
 #  
   
 sub exportsheet {  sub exportsheet {
     my ($uname,$udom,$stype,$usymb,$fn)=@_;      my ($uname,$udom,$stype,$usymb,$fn)=@_;
     my @exportarr=();      my @exportarr=();
     if (($usymb=~/^\_(\w+)/) && (!$fn)) {      if (defined($usymb) && ($usymb=~/^\_(\w+)/) && (!$fn)) {
         $fn='default_'.$1;          $fn='default_'.$1;
     }      }
     #      #
Line 2245  sub exportsheet { Line 2179  sub exportsheet {
     my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;      my $key=$uname.':'.$udom.':'.$stype.':'.$usymb;
     my $found='';      my $found='';
     if ($oldsheets{$key}) {      if ($oldsheets{$key}) {
         foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {          foreach (split(/___&\___/,$oldsheets{$key})) {
             my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);              my ($name,$value)=split(/___=___/,$_);
             if ($name eq $fn) {              if ($name eq $fn) {
                 $found=$value;                  $found=$value;
             }              }
Line 2255  sub exportsheet { Line 2189  sub exportsheet {
     unless ($found) {      unless ($found) {
         &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom));          &cachedssheets($uname,$udom,&Apache::lonnet::homeserver($uname,$udom));
         if ($oldsheets{$key}) {          if ($oldsheets{$key}) {
             foreach (split(/\_\_\_\&\_\_\_/,$oldsheets{$key})) {              foreach (split(/___&\___/,$oldsheets{$key})) {
                 my ($name,$value)=split(/\_\_\_\=\_\_\_/,$_);                  my ($name,$value)=split(/___=___/,$_);
                 if ($name eq $fn) {                  if ($name eq $fn) {
                     $found=$value;                      $found=$value;
                 }                  }
Line 2275  sub exportsheet { Line 2209  sub exportsheet {
         #          #
         # Return what was cached          # Return what was cached
         #          #
         @exportarr=split(/\_\_\_\;\_\_\_/,$found);          @exportarr=split(/___;___/,$found);
     } else {          return @exportarr;
         #      }
         # Not cached      #
         #              # Not cached
         my $thissheet=&makenewsheet($uname,$udom,$stype,$usymb);      #        
         &readsheet($thissheet,$fn);      my ($sheet)=&makenewsheet($uname,$udom,$stype,$usymb);
         &updatesheet($thissheet);      &readsheet($sheet,$fn);
         &loadrows($thissheet);      &updatesheet($sheet);
         &calcsheet($thissheet);       &loadrows($sheet);
         @exportarr=&exportdata($thissheet);      &calcsheet($sheet); 
         #      @exportarr=&exportdata($sheet);
         # Store now      #
         #      # Store now
         my $cid=$ENV{'request.course.id'};       #
         my $current='';      my $cid=$ENV{'request.course.id'}; 
         if ($stype eq 'studentcalc') {      my $current='';
             $current=&Apache::lonnet::reply('get:'.      if ($stype eq 'studentcalc') {
                                             $ENV{'course.'.$cid.'.domain'}.':'.          $current=&Apache::lonnet::reply('get:'.
                                             $ENV{'course.'.$cid.'.num'}.                                          $ENV{'course.'.$cid.'.domain'}.':'.
                                             ':nohist_calculatedsheets:'.                                          $ENV{'course.'.$cid.'.num'}.
                                             &Apache::lonnet::escape($key),                                          ':nohist_calculatedsheets:'.
                                             $ENV{'course.'.$cid.'.home'});                                          &Apache::lonnet::escape($key),
         } else {                                          $ENV{'course.'.$cid.'.home'});
             $current=&Apache::lonnet::reply('get:'.      } else {
                                             &getudom($thissheet).':'.          $current=&Apache::lonnet::reply('get:'.$sheet->{'udom'}.':'.
                                             &getuname($thissheet).                                          $sheet->{'uname'}.
                                             ':nohist_calculatedsheets_'.                                          ':nohist_calculatedsheets_'.
                                             $ENV{'request.course.id'}.':'.                                          $ENV{'request.course.id'}.':'.
                                             &Apache::lonnet::escape($key),                                          &Apache::lonnet::escape($key),
                                             &getuhome($thissheet));                                          $sheet->{'uhome'});
         }      }
         my %currentlystored=();      my %currentlystored=();
         unless ($current=~/^error\:/) {      unless ($current=~/^error\:/) {
             foreach (split(/___&\___/,&Apache::lonnet::unescape($current))) {          foreach (split(/___&\___/,&Apache::lonnet::unescape($current))) {
                 my ($name,$value)=split(/___=___/,$_);              my ($name,$value)=split(/___=___/,$_);
                 $currentlystored{$name}=$value;              $currentlystored{$name}=$value;
             }          }
         }      }
         $currentlystored{$fn}=join('___;___',@exportarr);      $currentlystored{$fn}=join('___;___',@exportarr);
         #      #
         my $newstore='';      my $newstore='';
         foreach (keys(%currentlystored)) {      foreach (keys(%currentlystored)) {
             if ($newstore) { $newstore.='___&___'; }          if ($newstore) { $newstore.='___&___'; }
             $newstore.=$_.'___=___'.$currentlystored{$_};          $newstore.=$_.'___=___'.$currentlystored{$_};
         }      }
         my $now=time;      my $now=time;
         if ($stype eq 'studentcalc') {      if ($stype eq 'studentcalc') {
             &Apache::lonnet::reply('put:'.          &Apache::lonnet::put('nohist_calculatedsheets',
                                    $ENV{'course.'.$cid.'.domain'}.':'.                               { $key => $newstore,
                                    $ENV{'course.'.$cid.'.num'}.                                 $key.time => $now },
                                    ':nohist_calculatedsheets:'.                               $ENV{'course.'.$cid.'.domain'},
                                    &Apache::lonnet::escape($key).'='.                               $ENV{'course.'.$cid.'.num'})
                                    &Apache::lonnet::escape($newstore).'&'.      } else {
                                    &Apache::lonnet::escape($key).'.time='.$now,          &Apache::lonnet::put('nohist_calculatedsheets_'.$sheet->{'cid'},
                                    $ENV{'course.'.$cid.'.home'});                               { $key => $newstore,
         } else {                                 $key.time => $now },
             &Apache::lonnet::reply('put:'.                               $sheet->{'udom'},
                                    &getudom($thissheet).':'.                               $sheet->{'uname'})
                                    &getuname($thissheet).  
                                    ':nohist_calculatedsheets_'.  
                                    $ENV{'request.course.id'}.':'.  
                                    &Apache::lonnet::escape($key).'='.  
                                    &Apache::lonnet::escape($newstore).'&'.  
                                    &Apache::lonnet::escape($key).'.time='.$now,  
                                    &getuhome($thissheet));  
         }  
     }      }
     return @exportarr;      return @exportarr;
 }  }
Line 2422  sub cachedssheets { Line 2348  sub cachedssheets {
 # Interactive call to screen  # Interactive call to screen
 #  #
 #  #
   
   
 sub handler {  sub handler {
     my $r=shift;      my $r=shift;
   
       if (! exists($ENV{'form.Status'})) {
           $ENV{'form.Status'} = 'Active';
       }
       # Check this server
       my $loaderror=&Apache::lonnet::overloaderror($r);
       if ($loaderror) { return $loaderror; }
       # Check the course homeserver
       $loaderror= &Apache::lonnet::overloaderror($r,
                         $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
       if ($loaderror) { return $loaderror; } 
       
     if ($r->header_only) {      if ($r->header_only) {
         $r->content_type('text/html');          $r->content_type('text/html');
         $r->send_http_header;          $r->send_http_header;
         return OK;          return OK;
     }      }
     # Global directory configs      # Global directory configs
     $includedir=$r->dir_config('lonIncludes');      $includedir = $r->dir_config('lonIncludes');
     $tmpdir=$r->dir_config('lonDaemons').'/tmp/';      $tmpdir = $r->dir_config('lonDaemons').'/tmp/';
     # Needs to be in a course      # Needs to be in a course
     if ($ENV{'request.course.fn'}) {       if (! $ENV{'request.course.fn'}) { 
         # Get query string for limited number of parameters          # Not in a course, or not allowed to modify parms
         &Apache::loncommon::get_unprocessed_cgi          $ENV{'user.error.msg'}=
             ($ENV{'QUERY_STRING'},['uname','udom','usymb','ufn']);              $r->uri.":opa:0:0:Cannot modify spreadsheet";
         if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {          return HTTP_NOT_ACCEPTABLE; 
             $ENV{'form.ufn'}='default_'.$1;      }
         }      # Get query string for limited number of parameters
         # Interactive loading of specific sheet?      &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
         if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {                                              ['uname','udom','usymb','ufn']);
             $ENV{'form.ufn'}=$ENV{'form.loadthissheet'};      if ($ENV{'request.role'} =~ /^st\./) {
         }          delete $ENV{'form.unewfield'}   if (exists($ENV{'form.unewfield'}));
         # Nothing there? Must be login user          delete $ENV{'form.unewformula'} if (exists($ENV{'form.unewformula'}));
         my $aname;      }
         my $adom;      if (($ENV{'form.usymb'}=~/^\_(\w+)/) && (!$ENV{'form.ufn'})) {
           $ENV{'form.ufn'}='default_'.$1;
         unless ($ENV{'form.uname'}) {      }
             $aname=$ENV{'user.name'};      # Interactive loading of specific sheet?
             $adom=$ENV{'user.domain'};      if (($ENV{'form.load'}) && ($ENV{'form.loadthissheet'} ne 'Default')) {
         } else {          $ENV{'form.ufn'}=$ENV{'form.loadthissheet'};
             $aname=$ENV{'form.uname'};      }
             $adom=$ENV{'form.udom'};      #
         }      # Determine the user name and domain for the sheet.
         # Open page      my $aname;
         $r->content_type('text/html');      my $adom;
         $r->header_out('Cache-control','no-cache');      unless ($ENV{'form.uname'}) {
         $r->header_out('Pragma','no-cache');          $aname=$ENV{'user.name'};
         $r->send_http_header;          $adom=$ENV{'user.domain'};
         # Screen output      } else {
         $r->print('<html><head><title>LON-CAPA Spreadsheet</title>');          $aname=$ENV{'form.uname'};
           $adom=$ENV{'form.udom'};
       }
       #
       # Open page
       $r->content_type('text/html');
       $r->header_out('Cache-control','no-cache');
       $r->header_out('Pragma','no-cache');
       $r->send_http_header;
       # Screen output
       $r->print('<html><head><title>LON-CAPA Spreadsheet</title>');
       if ($ENV{'request.role'} !~ /^st\./) {
         $r->print(<<ENDSCRIPT);          $r->print(<<ENDSCRIPT);
 <script language="JavaScript">  <script language="JavaScript">
   
Line 2490  sub handler { Line 2437  sub handler {
   
 </script>  </script>
 ENDSCRIPT  ENDSCRIPT
         $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').      }
                   '<form action="'.$r->uri.'" name=sheet method=post>'.      $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').
                   &hiddenfield('uname',$ENV{'form.uname'}).                '<form action="'.$r->uri.'" name=sheet method=post>');
                   &hiddenfield('udom',$ENV{'form.udom'}).      $r->print(&hiddenfield('uname',$ENV{'form.uname'}).
                   &hiddenfield('usymb',$ENV{'form.usymb'}).                &hiddenfield('udom',$ENV{'form.udom'}).
                   &hiddenfield('unewfield','').                &hiddenfield('usymb',$ENV{'form.usymb'}).
                   &hiddenfield('unewformula',''));                &hiddenfield('unewfield','').
         # Send this out right away                &hiddenfield('unewformula',''));
         $r->rflush();      $r->rflush();
         # Full recalc?      #
         if ($ENV{'form.forcerecalc'}) {      # Full recalc?
             $r->print('<h4>Completely Recalculating Sheet ...</h4>');      if ($ENV{'form.forcerecalc'}) {
             undef %spreadsheets;          $r->print('<h4>Completely Recalculating Sheet ...</h4>');
             undef %courserdatas;          undef %spreadsheets;
             undef %userrdatas;          undef %courserdatas;
             undef %defaultsheets;          undef %userrdatas;
             undef %updatedata;          undef %defaultsheets;
         }          undef %updatedata;
         # Read new sheet or modified worksheet      }
         $r->uri=~/\/(\w+)$/;      # Read new sheet or modified worksheet
         my $asheet=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});      $r->uri=~/\/(\w+)$/;
         # If a new formula had been entered, go from work copy      my ($sheet)=&makenewsheet($aname,$adom,$1,$ENV{'form.usymb'});
         if ($ENV{'form.unewfield'}) {      #
             $r->print('<h2>Modified Workcopy</h2>');      # If a new formula had been entered, go from work copy
             $ENV{'form.unewformula'}=~s/\'/\"/g;      if ($ENV{'form.unewfield'}) {
             $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.          $r->print('<h2>Modified Workcopy</h2>');
                       $ENV{'form.unewformula'}.'<p>');          $ENV{'form.unewformula'}=~s/\'/\"/g;
             &setfilename($asheet,$ENV{'form.ufn'});          $r->print('<p>New formula: '.$ENV{'form.unewfield'}.'='.
             &tmpread($asheet,                    $ENV{'form.unewformula'}.'<p>');
                      $ENV{'form.unewfield'},$ENV{'form.unewformula'});          $sheet->{'filename'} = $ENV{'form.ufn'};
                       &tmpread($sheet,$ENV{'form.unewfield'},$ENV{'form.unewformula'});
         } elsif ($ENV{'form.saveas'}) {      } elsif ($ENV{'form.saveas'}) {
             &setfilename($asheet,$ENV{'form.ufn'});          $sheet->{'filename'} = $ENV{'form.ufn'};
             &tmpread($asheet);          &tmpread($sheet);
         } else {      } else {
             &readsheet($asheet,$ENV{'form.ufn'});          &readsheet($sheet,$ENV{'form.ufn'});
         }      }
         # Print out user information      # Print out user information
         unless (&gettype($asheet) eq 'classcalc') {      if ($sheet->{'sheettype'} ne 'classcalc') {
             $r->print('<p><b>User:</b> '.&getuname($asheet).          $r->print('<p><b>User:</b> '.$sheet->{'uname'}.
                       '<br><b>Domain:</b> '.&getudom($asheet));                    '<br><b>Domain:</b> '.$sheet->{'udom'});
             if (&getcsec($asheet) eq '-1') {          $r->print('<br><b>Section/Group:</b> '.$sheet->{'csec'});
                 $r->print('<h3><font color=red>'.          if ($ENV{'form.usymb'}) {
                           'Not a student in this course</font></h3>');              $r->print('<br><b>Assessment:</b> <tt>'.
             } else {                        $ENV{'form.usymb'}.'</tt>');
                 $r->print('<br><b>Section/Group:</b> '.&getcsec($asheet));          }
       }
       #
       # Check user permissions
       if (($sheet->{'sheettype'} eq 'classcalc'       ) || 
           ($sheet->{'uname'}     ne $ENV{'user.name'} ) ||
           ($sheet->{'udom'}      ne $ENV{'user.domain'})) {
           unless (&Apache::lonnet::allowed('vgr',$sheet->{'cid'})) {
               $r->print('<h1>Access Permission Denied</h1>'.
                         '</form></body></html>');
               return OK;
           }
       }
       # Additional options
       $r->print('<br />'.
                 '<input type="submit" name="forcerecalc" '.
                 'value="Completely Recalculate Sheet"><p>');
       if ($sheet->{'sheettype'} eq 'assesscalc') {
           $r->print('<p><font size=+2>'.
                     '<a href="/adm/studentcalc?'.
                     'uname='.$sheet->{'uname'}.
                     '&udom='.$sheet->{'udom'}.'">'.
                     'Level up: Student Sheet</a></font><p>');
       }
       if (($sheet->{'sheettype'} eq 'studentcalc') && 
           (&Apache::lonnet::allowed('vgr',$sheet->{'cid'}))) {
           $r->print ('<p><font size=+2><a href="/adm/classcalc">'.
                      'Level up: Course Sheet</a></font><p>');
       }
       # Save dialog
       if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
           my $fname=$ENV{'form.ufn'};
           $fname=~s/\_[^\_]+$//;
           if ($fname eq 'default') { $fname='course_default'; }
           $r->print('<input type=submit name=saveas value="Save as ...">'.
                     '<input type=text size=20 name=newfn value="'.$fname.'">'.
                     'make default: <input type=checkbox name="makedefufn"><p>');
       }
       $r->print(&hiddenfield('ufn',$sheet->{'filename'}));
       # Load dialog
       if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
           $r->print('<p><input type=submit name=load value="Load ...">'.
                     '<select name="loadthissheet">'.
                     '<option name="default">Default</option>');
           foreach (&othersheets($sheet)) {
               $r->print('<option name="'.$_.'"');
               if ($ENV{'form.ufn'} eq $_) {
                   $r->print(' selected');
             }              }
             if ($ENV{'form.usymb'}) {              $r->print('>'.$_.'</option>');
                 $r->print('<br><b>Assessment:</b> <tt>'.          } 
                           $ENV{'form.usymb'}.'</tt>');          $r->print('</select><p>');
             }          if ($sheet->{'sheettype'} eq 'studentcalc') {
         }              &setothersheets($sheet,
         # See if user can see this                              &othersheets($sheet,'assesscalc'));
         if ((&gettype($asheet) eq 'classcalc') ||   
             (&getuname($asheet) ne $ENV{'user.name'}) ||  
             (&getudom($asheet) ne $ENV{'user.domain'})) {  
             unless (&Apache::lonnet::allowed('vgr',&getcid($asheet))) {  
                 $r->print('<h1>Access Permission Denied</h1>'.  
                           '</form></body></html>');  
                 return OK;  
             }  
         }  
         # Additional options  
         $r->print(  
  '<input type=submit name=forcerecalc value="Completely Recalculate Sheet"><p>'  
                   );  
         if (&gettype($asheet) eq 'assesscalc') {  
             $r->print ('<p><font size=+2><a href="/adm/studentcalc?uname='.  
                        &getuname($asheet).'&udom='.&getudom($asheet).'">'.  
                        'Level up: Student Sheet</a></font><p>');  
         }  
         if ((&gettype($asheet) eq 'studentcalc') &&   
             (&Apache::lonnet::allowed('vgr',&getcid($asheet)))) {  
             $r->print (  
                        '<p><font size=+2><a href="/adm/classcalc">'.  
                        'Level up: Course Sheet</a></font><p>');  
         }  
         # Save dialog  
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {  
             my $fname=$ENV{'form.ufn'};  
             $fname=~s/\_[^\_]+$//;  
             if ($fname eq 'default') { $fname='course_default'; }  
             $r->print  
                 ('<input type=submit name=saveas value="Save as ...">'.  
                  '<input type=text size=20 name=newfn value="'.$fname.'">'.  
                  '(make default: <input type=checkbox name="makedefufn">)<p>');  
         }  
         $r->print(&hiddenfield('ufn',&getfilename($asheet)));  
         # Load dialog  
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {  
             $r->print('<p><input type=submit name=load value="Load ...">'.  
                       '<select name="loadthissheet">'.  
                       '<option name="default">Default</option>');  
             foreach (&othersheets($asheet,&gettype($asheet))) {  
                 $r->print('<option name="'.$_.'"');  
                 if ($ENV{'form.ufn'} eq $_) {  
                     $r->print(' selected');  
                 }  
                 $r->print('>'.$_.'</option>');  
             }   
             $r->print('</select><p>');  
             if (&gettype($asheet) eq 'studentcalc') {  
                 &setothersheets($asheet,&othersheets($asheet,'assesscalc'));  
             }  
         }  
         # Cached sheets  
         &expirationdates();  
         undef %oldsheets;  
         undef %loadedcaches;  
         if (&gettype($asheet) eq 'classcalc') {  
             $r->print  
                 ("Loading previously calculated student sheets ...<br>\n");  
             $r->rflush();  
             &cachedcsheets();  
         } elsif (&gettype($asheet) eq 'studentcalc') {  
             $r->print  
                 ("Loading previously calculated assessment sheets ...<br>\n");  
             $r->rflush();  
             &cachedssheets(&getuname($asheet),&getudom($asheet),  
                            &getuhome($asheet));  
         }          }
         # Update sheet, load rows      }
         $r->print("Loaded sheet(s), updating rows ...<br>\n");      # Cached sheets
       &expirationdates();
       undef %oldsheets;
       undef %loadedcaches;
       if ($sheet->{'sheettype'} eq 'classcalc') {
           $r->print("Loading previously calculated student sheets ...\n");
         $r->rflush();          $r->rflush();
         #          &cachedcsheets();
         &updatesheet($asheet);      } elsif ($sheet->{'sheettype'} eq 'studentcalc') {
         $r->print("Updated rows, loading row data ...<br>\n");          $r->print("Loading previously calculated assessment sheets ...\n");
         $r->rflush();          $r->rflush();
         #          &cachedssheets($sheet->{'uname'},$sheet->{'udom'},$sheet->{'uhome'});
         &loadrows($asheet,$r);      }
         $r->print("Loaded row data, calculating sheet ...<br>\n");      # Update sheet, load rows
         $r->rflush();      $r->print("Loaded sheet(s), updating rows ...<br>\n");
         #      $r->rflush();
         my $calcoutput=&calcsheet($asheet);      #
         $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>');      &updatesheet($sheet);
         # See if something to save      $r->print("Updated rows, loading row data ...\n");
         if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {      $r->rflush();
             my $fname='';      #
             if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {      &loadrows($sheet,$r);
                 $fname=~s/\W/\_/g;      $r->print("Loaded row data, calculating sheet ...<br>\n");
                 if ($fname eq 'default') { $fname='course_default'; }      $r->rflush();
                 $fname.='_'.&gettype($asheet);      #
                 &setfilename($asheet,$fname);      my $calcoutput=&calcsheet($sheet);
                 $ENV{'form.ufn'}=$fname;      $r->print('<h3><font color=red>'.$calcoutput.'</h3></font>');
                 $r->print('<p>Saving spreadsheet: '.      # See if something to save
                           &writesheet($asheet,$ENV{'form.makedefufn'}).'<p>');      if (&Apache::lonnet::allowed('opa',$ENV{'request.course.id'})) {
             }          my $fname='';
           if ($ENV{'form.saveas'} && ($fname=$ENV{'form.newfn'})) {
               $fname=~s/\W/\_/g;
               if ($fname eq 'default') { $fname='course_default'; }
               $fname.='_'.$sheet->{'sheettype'};
               $sheet->{'filename'} = $fname;
               $ENV{'form.ufn'}=$fname;
               $r->print('<p>Saving spreadsheet: '.
                         &writesheet($sheet,$ENV{'form.makedefufn'}).
                         '<p>');
         }          }
         #Write the modified worksheet      }
       #
    $r->print('<b>Current sheet:</b> '.&getfilename($asheet).'<p>');      # Write the modified worksheet
       $r->print('<b>Current sheet:</b> '.$sheet->{'filename'}.'<p>');
    &tmpwrite($asheet);      &tmpwrite($sheet);
       if ($sheet->{'sheettype'} eq 'studentcalc') {
     if (&gettype($asheet) eq 'studentcalc') {          $r->print('<br>Show rows with empty A column: ');
  $r->print('<br>Show rows with empty A column: ');  
     } else {      } else {
         $r->print('<br>Show empty rows: ');          $r->print('<br>Show empty rows: ');
     }       }
       #
     $r->print(&hiddenfield('userselhidden','true').      $r->print(&hiddenfield('userselhidden','true').
              '<input type=checkbox name=showall onClick="submit()"');                '<input type="checkbox" name="showall" onClick="submit()"');
       #
     if ($ENV{'form.showall'}) {       if ($ENV{'form.showall'}) { 
        $r->print(' checked');           $r->print(' checked'); 
     } else {      } else {
  unless ($ENV{'form.userselhidden'}) {          unless ($ENV{'form.userselhidden'}) {
            unless               unless 
  ($ENV{'course.'.$ENV{'request.course.id'}.'.hideemptyrows'} eq 'yes') {                  ($ENV{'course.'.$ENV{'request.course.id'}.'.hideemptyrows'} eq 'yes') {
           $r->print(' checked');                      $r->print(' checked');
           $ENV{'form.showall'}=1;                      $ENV{'form.showall'}=1;
            }                  }
        }          }
     }      }
     $r->print('>');      $r->print('>');
       #
     if (&gettype($asheet) eq 'classcalc') {      # CSV format checkbox (classcalc sheets only)
        $r->print(      $r->print(' Output CSV format: <input type="checkbox" '.
    ' Output CSV format: <input type=checkbox name=showcsv onClick="submit()"');                'name="showcsv" onClick="submit()"');
        if ($ENV{'form.showcsv'}) { $r->print(' checked'); }      $r->print(' checked') if ($ENV{'form.showcsv'});
        $r->print('>');      $r->print('>');
       if ($sheet->{'sheettype'} eq 'classcalc') {
           $r->print('&nbsp;Student Status: '.
                     &Apache::lonhtmlcommon::StatusOptions
                     ($ENV{'form.Status'},'sheet'));
     }      }
       #
 # ------------------------------------------------------------------ Insertrows      # Buttons to insert rows
     $r->print('&nbsp;Student Status: '.      $r->print(<<ENDINSERTBUTTONS);
               &Apache::lonhtmlcommon::StatusOptions  
               ($ENV{'form.Status'},'sheet'));  
   
    $r->print(<<ENDINSERTBUTTONS);  
 <br>  <br>
 <input type='button' onClick='insertrow("top");'   <input type='button' onClick='insertrow("top");' 
 value='Insert Row Top'>  value='Insert Row Top'>
 <input type='button' onClick='insertrow("bottom");'   <input type='button' onClick='insertrow("bottom");' 
 value='Insert Row Bottom'><br>  value='Insert Row Bottom'><br>
 ENDINSERTBUTTONS  ENDINSERTBUTTONS
       # Print out sheet
 # ------------------------------------------------------------- Print out sheet      &outsheet($r,$sheet);
   
     &outsheet($r,$asheet);  
     $r->print('</form></body></html>');      $r->print('</form></body></html>');
       #  Done
 # ------------------------------------------------------------------------ Done  
   } else {  
 # ----------------------------- Not in a course, or not allowed to modify parms  
       $ENV{'user.error.msg'}=  
         $r->uri.":opa:0:0:Cannot modify spreadsheet";  
       return HTTP_NOT_ACCEPTABLE;   
   }  
     return OK;      return OK;
   
 }  }
   
 1;  1;
 __END__  __END__
   
   
   
   

Removed from v.1.104  
changed lines
  Added in v.1.127


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