--- loncom/interface/Attic/lonspreadsheet.pm 2002/10/22 19:47:13 1.124 +++ loncom/interface/Attic/lonspreadsheet.pm 2002/11/06 20:00:13 1.134 @@ -1,5 +1,5 @@ # -# $Id: lonspreadsheet.pm,v 1.124 2002/10/22 19:47:13 matthew Exp $ +# $Id: lonspreadsheet.pm,v 1.134 2002/11/06 20:00:13 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -62,6 +62,8 @@ use GDBM_File; use HTML::TokeParser; use Apache::lonhtmlcommon; use Apache::loncoursedata; +use Apache::File(); +use Spreadsheet::WriteExcel; # # Caches for coursewide information # @@ -122,19 +124,16 @@ my $tmpdir; ## sub mask { my ($lower,$upper)=@_; - - $lower=~/([A-Za-z]|\*)(\d+|\*)/; - my $la=$1; - my $ld=$2; - - $upper=~/([A-Za-z]|\*)(\d+|\*)/; - my $ua=$1; - my $ud=$2; + $upper = $lower if (! defined($upper)); + # + my ($la,$ld) = ($lower=~/([A-Za-z]|\*)(\d+|\*)/); + my ($ua,$ud) = ($upper=~/([A-Za-z]|\*)(\d+|\*)/); + # my $alpha=''; my $num=''; - + # if (($la eq '*') || ($ua eq '*')) { - $alpha='[A-Za-z]'; + $alpha='[A-Za-z]'; } else { if (($la=~/[A-Z]/) && ($ua=~/[A-Z]/) || ($la=~/[a-z]/) && ($ua=~/[a-z]/)) { @@ -188,8 +187,8 @@ sub mask { } $num.=')'; } else { - if ($lda[$#lda]!=$uda[$#uda]) { - $num.='['.$lda[$#lda].'-'.$uda[$#uda].']'; + if ($lda[-1]!=$uda[-1]) { + $num.='['.$lda[-1].'-'.$uda[-1].']'; } } } @@ -197,8 +196,6 @@ sub mask { return '^'.$alpha.$num."\$"; } - - sub initsheet { my $safeeval = new Safe(shift); my $safehole = new Safe::Hole; @@ -237,12 +234,11 @@ undef %c; # Holds the constants for a sh # 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 %rowlabel; # Holds the 'prefix' for each row. Set by &setrowlabels. - # &setrowlabels is called by &updateclasssheet, &updatestudentassesssheet, 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. +#$errorlog = ''; $maxrow = 0; $sheettype = ''; @@ -596,7 +592,8 @@ compute the average of the items in the #------------------------------------------------------- sub MEAN { my $mask=mask(@_); - my $sum=0; my $num=0; + my $sum=0; + my $num=0; foreach (grep /$mask/,keys(%sheet_values)) { $sum+=$sheet_values{$_}; $num++; @@ -833,9 +830,11 @@ sub expandnamed { foreach $parameter (keys(%c)) { push @matches,$parameter if ($parameter =~ /$expression/); } - if ($#matches == 0) { + if (scalar(@matches) == 0) { + $returnvalue = 'unmatched parameter: '.$parameter; + } elsif (scalar(@matches) == 1) { $returnvalue = '$c{\''.$matches[0].'\'}'; - } elsif ($#matches > 0) { + } elsif (scalar(@matches) > 0) { # more than one match. Look for a concise one $returnvalue = "'non-unique parameter name : $expression'"; foreach (@matches) { @@ -844,7 +843,9 @@ sub expandnamed { } } } else { - $returnvalue = "'bad parameter name : $expression'"; + # There was a negative number of matches, which indicates + # something is wrong with reality. Better warn the user. + $returnvalue = 'bizzare parameter: '.$parameter; } return $returnvalue; } @@ -927,6 +928,7 @@ sub calc { while ($notfinished) { $notfinished=0; foreach (keys(%t)) { + #$errorlog .= "$_:".$t{$_}; my $old=$sheet_values{$_}; $sheet_values{$_}=eval $t{$_}; if ($@) { @@ -934,6 +936,7 @@ sub calc { return $_.': '.$@; } if ($sheet_values{$_} ne $old) { $notfinished=1; $lastcalc=$_; } + #$errorlog .= ":".$sheet_values{$_}."\n"; } $depth++; if ($depth>100) { @@ -951,55 +954,39 @@ ENDDEFS } # -# This is actually used for the student spreadsheet, not the assessment sheet -# Do not be fooled by the name! +# # sub templaterow { my $sheet = shift; my @cols=(); - $cols[0]='Template'; + my $rowlabel = 'Template'; foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z') { my $fm=$sheet->{'f'}->{'template_'.$_}; $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'template_$_','$fm'".'___eq___'.$fm); + push(@cols,{ name => 'template_'.$_, + formula => $fm, + value => $fm }); } - return @cols; + return ($rowlabel,@cols); } - sub outrowassess { # $n is the current row number - my $sheet = shift; - my $n=shift; - my $csv = $ENV{'form.showcsv'}; + my ($sheet,$n) = @_; my @cols=(); + my $rowlabel=''; if ($n) { my ($usy,$ufn)=split(/__&&&\__/,$sheet->{'f'}->{'A'.$n}); - if ($sheet->{'rowlabel'}->{$usy}) { - $cols[0]=$sheet->{'rowlabel'}->{$usy}; - if (! $csv) { - $cols[0].='
'. - ''; + $rowlabel = ''; } } else { - $cols[0]='Export'; + $rowlabel = 'Export'; } 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', @@ -1007,19 +994,25 @@ sub outrowassess { 'n','o','p','q','r','s','t','u','v','w','x','y','z') { my $fm=$sheet->{'f'}->{$_.$n}; $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n}); + push(@cols,{ name => $_.$n, + formula => $fm, + value => $sheet->{'values'}->{$_.$n}}); } - return @cols; + return ($rowlabel,@cols); } sub outrow { - my $sheet=shift; - my $n=shift; + my ($sheet,$n)=@_; my @cols=(); + my $rowlabel; if ($n) { - $cols[0]=$sheet->{'rowlabel'}->{$sheet->{'f'}->{'A'.$n}}; + $rowlabel = $sheet->{'rowlabel'}->{$sheet->{'f'}->{'A'.$n}}; } else { - $cols[0]='Export'; + if ($sheet->{'sheettype'} eq 'classcalc') { + $rowlabel = 'Summary'; + } else { + $rowlabel = 'Export'; + } } 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', @@ -1027,9 +1020,11 @@ sub outrow { 'n','o','p','q','r','s','t','u','v','w','x','y','z') { my $fm=$sheet->{'f'}->{$_.$n}; $fm=~s/[\'\"]/\&\#34;/g; - push(@cols,"'$_$n','$fm'".'___eq___'.$sheet->{'values'}->{$_.$n}); + push(@cols,{ name => $_.$n, + formula => $fm, + value => $sheet->{'values'}->{$_.$n}}); } - return @cols; + return ($rowlabel,@cols); } # ------------------------------------------------ Add or change formula values @@ -1062,7 +1057,12 @@ sub setothersheets { # ------------------------------------------------ Add or change formula values sub setrowlabels { my $sheet=shift; - %{$sheet->{'safe'}->varglob('rowlabel')}=%{$sheet->{'rowlabel'}}; + my ($rowlabel) = @_; + if (! ref($rowlabel)) { + my %tmp = @_; + $rowlabel = \%tmp; + } + $sheet->{'rowlabel'}=$rowlabel; } # ------------------------------------------------------- Calculate spreadsheet @@ -1074,11 +1074,17 @@ sub calcsheet { } # ---------------------------------------------------------------- Get formulas +# Return a copy of the formulas sub getformulas { my $sheet = shift; return %{$sheet->{'safe'}->varglob('f')}; } +sub geterrorlog { + my $sheet = shift; + return ${$sheet->{'safe'}->varglob('errorlog')}; +} + # ----------------------------------------------------- Get value of $f{'A'.$n} sub getfa { my $sheet = shift; @@ -1092,7 +1098,11 @@ sub exportdata { 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'}); + if (exists($sheet->{'values'}->{$_.'0'})) { + push(@exportarray,$sheet->{'values'}->{$_.'0'}); + } else { + push(@exportarray,''); + } } return @exportarray; } @@ -1105,174 +1115,367 @@ sub exportdata { # # --------------------------------------------- Produce output row n from sheet -sub rown { - my ($sheet,$n)=@_; - my $defaultbg; - my $rowdata=''; - my $dataflag=0; - unless ($n eq '-') { - $defaultbg=((($n-1)/5)==int(($n-1)/5))?'#E0E0':'#FFFF'; - } else { - $defaultbg='#E0FF'; - } - unless ($ENV{'form.showcsv'}) { - $rowdata.="\n$n"; +sub get_row { + my ($sheet,$n) = @_; + my ($rowlabel,@rowdata); + if ($n eq '-') { + ($rowlabel,@rowdata) = &templaterow($sheet); + } elsif ($sheet->{'sheettype'} eq 'studentcalc') { + ($rowlabel,@rowdata) = &outrowassess($sheet,$n); } else { - $rowdata.="\n".'"'.$n.'"'; + ($rowlabel,@rowdata) = &outrow($sheet,$n); } - my $showf=0; + return ($rowlabel,@rowdata); +} + +######################################################################## +######################################################################## +sub sort_indicies { + my $sheet = shift; # - # Determine how many pink (uneditable) cells there are in this sheet. - my $maxred=1; - my $sheettype=$sheet->{'sheettype'}; - if ($sheettype eq 'studentcalc') { - $maxred=26; - } elsif ($sheettype eq 'assesscalc') { - $maxred=1; - } else { - $maxred=26; - } - $maxred=1 if (&getfa($sheet,$n)=~/^[\~\-]/); + # Sort the rows in some manner # - # Get the proper row - my @rowdata; - if ($n eq '-') { - @rowdata = &templaterow($sheet); - $n=-1; - $dataflag=1; - } elsif ($sheettype eq 'studentcalc') { - @rowdata = &outrowassess($sheet,$n); - } else { - @rowdata = &outrow($sheet,$n); - } - # - foreach (@rowdata) { - my $bgcolor=$defaultbg.((($showf-1)/5==int(($showf-1)/5))?'99':'DD'); - my ($fm,$vl)=split(/\_\_\_eq\_\_\_/,$_); - if ((($vl ne '') || ($vl eq '0')) && - (($showf==1) || ($sheettype ne 'studentcalc'))) { $dataflag=1; } - if ($showf==0) { $vl=$_; } - unless ($ENV{'form.showcsv'}) { - if ($showf<=$maxred) { $bgcolor='#FFDDDD'; } - if (($n==0) && ($showf<=26)) { $bgcolor='#CCCCFF'; } - if (($showf>$maxred) || ((!$n) && ($showf>0))) { - if ($vl eq '') { - $vl='#'; - } - $rowdata.=''; - if ($ENV{'request.role'} =~ /^st\./) { - $rowdata.=$vl; - } else { - $rowdata.=''. - $vl.''; - } - $rowdata.=''; - } else { - $rowdata.=' '.$vl.' '; - } - } else { - $rowdata.=',"'.$vl.'"'; + my @sortby=(); + my @sortidx=(); + for (my $row=1;$row<=$sheet->{'maxrow'};$row++) { + push (@sortby, $sheet->{'safe'}->reval('$f{"A'.$row.'"}')); + push (@sortidx, $row); + } + @sortidx=sort { lc($sortby[$a]) cmp lc($sortby[$b]); } @sortidx; + return @sortidx; +} + +######################################################################## +######################################################################## + +sub html_editable_cell { + my ($cell,$bgcolor) = @_; + my $result; + my ($name,$formula,$value); + if (defined($cell)) { + $name = $cell->{'name'}; + $formula = $cell->{'formula'}; + $value = $cell->{'value'}; + } + $name = '' if (! defined($name)); + $formula = '' if (! defined($formula)); + if (! defined($value)) { + $value = '#'; + if ($formula ne '') { + $value = 'undefined value'; } - $showf++; - } # End of foreach($safeval...) - if ($ENV{'form.showall'} || ($dataflag)) { - return $rowdata.($ENV{'form.showcsv'}?'':''); - } else { - return ''; } + if ($value =~ /^\s*$/ ) { + $value = '#'; + } + $result .= ''.$value.''; + return $result; } -# ------------------------------------------------------------- Print out sheet +sub html_uneditable_cell { + my ($cell,$bgcolor) = @_; + my $value = (defined($cell) ? $cell->{'value'} : ''); + return ' '.$value.' '; +} -sub outsheet { - my ($r,$sheet)=@_; - my $maxred = 26; # The maximum number of cells to show as - # red (uneditable) - # To make student sheets uneditable could we - # set $maxred = 52? - # - my $realm='Course'; # 'assessment', 'user', or 'course' sheet +######################################################################## +######################################################################## + +sub outsheet_html { + my ($sheet,$r) = @_; + my ($num_uneditable,$realm,$row_type); if ($sheet->{'sheettype'} eq 'assesscalc') { - $maxred=1; - $realm='Assessment'; + $num_uneditable = 1; + $realm = 'Assessment'; + $row_type = 'Item'; } elsif ($sheet->{'sheettype'} eq 'studentcalc') { - $maxred=26; - $realm='User'; - } - # - # Column label - my $tabledata; - if ($ENV{'form.showcsv'}) { - $tabledata='
';
-    } else { 
-        $tabledata=''.
-                  ''.
-                  '';
-        my $showf=0;
-        foreach ('A','B','C','D','E','F','G','H','I','J','K','L','M',
-                 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
-                 'a','b','c','d','e','f','g','h','i','j','k','l','m',
-                 'n','o','p','q','r','s','t','u','v','w','x','y','z') {
-            $showf++;
-            if ($showf<=$maxred) { 
-                $tabledata.='";
+        $num_uneditable = 26;
+        $realm = 'User';
+        $row_type = 'Assessment';
+    } elsif ($sheet->{'sheettype'} eq 'classcalc') {
+        $num_uneditable = 26;
+        $realm = 'Course';
+        $row_type = 'Student';
+    } else {
+        return;  # error
+    }
+    ####################################
+    # Print out header table
+    ####################################
+    my $num_left = 52-$num_uneditable;
+    my $tabledata =<<"END";
+
'. - ''.$realm.'ImportCalculations
'; - } else { - $tabledata.=''; - } - $tabledata.="$_
+ + + + + +END + my $label_num = 0; + foreach (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz')){ + if ($label_num<$num_uneditable) { + $tabledata.=''.&rown($sheet,'-'). - &rown($sheet,0); + $tabledata.="$_"; + $label_num++; } + $tabledata.="\n"; $r->print($tabledata); - # - # Prepare to output rows - my $row; - # - my @sortby=(); - my @sortidx=(); - for ($row=1;$row<=$sheet->{'maxrow'};$row++) { - push (@sortby, $sheet->{'safe'}->reval('$f{"A'.$row.'"}')); - push (@sortidx, $row-1); + #################################### + # Print out template row + #################################### + my ($rowlabel,@rowdata) = &get_row($sheet,'-'); + my $row_html = ''; + my $num_cols_output = 0; + foreach my $cell (@rowdata) { + if ($num_cols_output++ < $num_uneditable) { + $row_html .= ''; } - @sortidx=sort { lc($sortby[$a]) cmp lc($sortby[$b]); } @sortidx; - # - # Determine the type of child spreadsheets - my $what='Student'; - if ($sheet->{'sheettype'} eq 'assesscalc') { - $what='Item'; - } elsif ($sheet->{'sheettype'} eq 'studentcalc') { - $what='Assessment'; + $row_html.= "\n"; + $r->print($row_html); + #################################### + # Print out summary/export row + #################################### + my ($rowlabel,@rowdata) = &get_row($sheet,'0'); + my $rowcount = 0; + $row_html = ''; + $num_cols_output = 0; + foreach my $cell (@rowdata) { + if ($num_cols_output++ < 26) { + $row_html .= ''; } + $row_html.= "\n"; + $r->print($row_html); + $r->print('
$realm + Import + Calculations
'; + } else { + $tabledata.=''; } - $tabledata.='
'.&format_html_rowlabel($rowlabel).''; + $row_html .= &html_uneditable_cell($cell,'#FFDDDD'); + } else { + $row_html .= ''; + $row_html .= &html_editable_cell($cell,'#E0FFDD'); + } + $row_html .= '
'.&format_html_rowlabel($rowlabel).''; + $row_html .= &html_editable_cell($cell,'#CCCCFF'); + } else { + $row_html .= ''; + $row_html .= &html_uneditable_cell(undef,'#CCCCFF'); + } + $row_html .= '
'); + #################################### + # Prepare to output rows + #################################### + my @Rows = &sort_indicies($sheet); # # Loop through the rows and output them one at a time - my $n=0; - for ($row=0;$row<$sheet->{'maxrow'};$row++) { - my $thisrow=&rown($sheet,$sortidx[$row]+1); - if ($thisrow) { - if (($n/25==int($n/25)) && (!$ENV{'form.showcsv'})) { + my $rows_output=0; + foreach my $rownum (@Rows) { + my ($rowlabel,@rowdata) = &get_row($sheet,$rownum); + # + my $defaultbg='#E0FF'; + # + my $row_html ="\n".''.$rownum. + ''; + # + if ($sheet->{'sheettype'} eq 'classcalc') { + $row_html.=''.&format_html_rowlabel($rowlabel).''; + # Output links for each student? + # Nope, that is already done for us in format_html_rowlabel (for now) + } elsif ($sheet->{'sheettype'} eq 'studentcalc') { + $row_html.=''.&format_html_rowlabel($rowlabel); + $row_html.= '
'. + ''; + } elsif ($sheet->{'sheettype'} eq 'assesscalc') { + $row_html.=''.&format_html_rowlabel($rowlabel).''; + } + # + my $shown_cells = 0; + foreach my $cell (@rowdata) { + my $value = $cell->{'value'}; + my $formula = $cell->{'formula'}; + my $cellname = $cell->{'name'}; + # + my $bgcolor; + if ($shown_cells && ($shown_cells/5 == int($shown_cells/5))) { + $bgcolor = $defaultbg.'99'; + } else { + $bgcolor = $defaultbg.'DD'; + } + $bgcolor='#FFDDDD' if ($shown_cells < $num_uneditable); + # + $row_html.=''; + if ($shown_cells < $num_uneditable) { + $row_html .= &html_uneditable_cell($cell,$bgcolor); + } else { + $row_html .= &html_editable_cell($cell,$bgcolor); + } + $row_html.=''; + $shown_cells++; + } + if ($row_html) { + if ($rows_output % 25 == 0) { $r->print("\n
\n"); $r->rflush(); - $r->print(''); - $r->print('
 '.$what.''. + $r->print(''. + ''. + '\n"); } - $n++; - $r->print($thisrow); + $rows_output++; + $r->print($row_html); } } - $r->print($ENV{'form.showcsv'}?'':'
 '.$row_type.''. join('', (split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. 'abcdefghijklmnopqrstuvwxyz'))). "
'); + # + $r->print('
'); + # + # Debugging code (be sure to uncomment errorlog code in safe space): + # + # $r->print("\n
");
+    # $r->print(&geterrorlog($sheet));
+    # $r->print("\n
"); + return 1; } -# -# ----------------------------------------------- Read list of available sheets -# +sub outsheet_csv { + my ($sheet,$r) = @_; + my $csvdata = ''; + my @Values; + #################################### + # Prepare to output rows + #################################### + my @Rows = &sort_indicies($sheet); + # + # Loop through the rows and output them one at a time + my $rows_output=0; + foreach my $rownum (@Rows) { + my ($rowlabel,@rowdata) = &get_row($sheet,$rownum); + push (@Values,&format_csv_rowlabel($rowlabel)); + foreach my $cell (@rowdata) { + push (@Values,'"'.$cell->{'value'}.'"'); + } + $csvdata.= join(',',@Values)."\n"; + @Values = (); + } + # + # Write the CSV data to a file and serve up a link + # + my $filename = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.csv'; + my $file; + unless ($file = Apache::File->new('>'.'/home/httpd'.$filename)) { + $r->log_error("Couldn't open $filename for output $!"); + $r->print("Problems occured in writing the csv file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator."); + $r->print("
\n".$csvdata."
\n"); + return 0; + } + print $file $csvdata; + close($file); + $r->print('

'. + 'Your CSV spreadsheet.'."\n"); + # + return 1; +} + +sub outsheet_excel { + my ($sheet,$r) = @_; + my $filename = '/prtspool/'. + $ENV{'user.name'}.'_'.$ENV{'user.domain'}.'_'. + time.'_'.rand(1000000000).'.xls'; + &Apache::lonnet::logthis("spreadsheet:filename = ".$filename); + my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); + if (! defined($workbook)) { + $r->log_error("Error creating excel spreadsheet $filename: $!"); + $r->print("Problems creating new Excel file. ". + "This error has been logged. ". + "Please alert your LON-CAPA administrator"); + return 0; + } + # + # The spreadsheet stores temporary data in files, then put them + # together. If needed we should be able to disable this (memory only). + # The temporary directory must be specified before calling 'addworksheet'. + # File::Temp is used to determine the temporary directory. + $workbook->set_tempdir('/home/httpd/perl/tmp'); + # + # Determine the name to give the worksheet + my $sheetname; + if ($sheet->{'sheettype'} eq 'classcalc') { + $sheetname = 'Main'; + } elsif ($sheet->{'sheettype'} eq 'studentcalc') { + $sheetname = $sheet->{'uname'}.'@'.$sheet->{'udom'}; + } elsif ($sheet->{'sheettype'} eq 'assesscalc') { + $sheetname = $sheet->{'uname'}.'@'.$sheet->{'udom'}.' assessment'; + } + my $worksheet = $workbook->addworksheet($sheetname); + #################################### + # Prepare to output rows + #################################### + my @Rows = &sort_indicies($sheet); + # + # Loop through the rows and output them one at a time + my $rows_output=0; + foreach my $rownum (@Rows) { + my ($rowlabel,@rowdata) = &get_row($sheet,$rownum); + my $cols_output = 0; + my $label = &format_excel_rowlabel($rowlabel); + $worksheet->write($rows_output,$cols_output++,$label); + if (ref($label)) { + $cols_output = (scalar(@$label)); + } + foreach my $cell (@rowdata) { + $worksheet->write($rows_output,$cols_output++, + $cell->{'value'}); + } + $rows_output++; + } + # + $workbook->close(); + # Okay, the spreadsheet is taken care of, so give the user a link. + $r->print('

'. + 'Your Excel spreadsheet.'."\n"); + return 1; +} + +sub outsheet_xml { + my ($sheet,$r) = @_; +} + +sub outsheet { + my ($r,$sheet)=@_; + if (! exists($ENV{'form.output'})) { + $ENV{'form.output'} = 'HTML'; + } + if (lc($ENV{'form.output'}) eq 'csv') { + &outsheet_csv($sheet,$r); + } elsif (lc($ENV{'form.output'}) eq 'excel') { + &outsheet_excel($sheet,$r); +# } elsif (lc($ENV{'form.output'}) eq 'xml' ) { +# &outsheet_xml($sheet,$r); + } else { + &outsheet_html($sheet,$r); + } +} + +######################################################################## +######################################################################## sub othersheets { my ($sheet,$stype)=@_; $stype = $sheet->{'sheettype'} if (! defined($stype)); @@ -1290,7 +1493,6 @@ sub othersheets { return @alternatives; } - # # -------------------------------------- Parse a spreadsheet # @@ -1409,6 +1611,8 @@ sub makenewsheet { $sheet->{'cnum'} = $ENV{'course.'.$ENV{'request.course.id'}.'.num'}; $sheet->{'cdom'} = $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}; $sheet->{'chome'} = $ENV{'course.'.$ENV{'request.course.id'}.'.home'}; + $sheet->{'coursedesc'} = $ENV{'course.'.$ENV{'request.course.id'}. + 'description'}; $sheet->{'uhome'} = &Apache::lonnet::homeserver($uname,$udom); # # @@ -1445,31 +1649,19 @@ sub writesheet { # Cache new sheet $spreadsheets{$cnum.'_'.$cdom.'_'.$stype.'_'.$fn}=join('___;___',%f); # Write sheet - my $sheetdata=''; foreach (keys(%f)) { - unless ($f{$_} eq 'import') { - $sheetdata.=&Apache::lonnet::escape($_).'='. - &Apache::lonnet::escape($f{$_}).'&'; - } + delete($f{$_}) if ($f{$_} eq 'import'); } - $sheetdata=~s/\&$//; - my $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'.$fn.':'. - $sheetdata,$chome); + my $reply = &Apache::lonnet::put($fn,\%f,$cdom,$cnum); if ($reply eq 'ok') { - $reply=&Apache::lonnet::reply('put:'.$cdom.':'.$cnum.':'. - $stype.'_spreadsheets:'. - &Apache::lonnet::escape($fn). - '='.$ENV{'user.name'}.'@'. - $ENV{'user.domain'}, - $chome); + $reply = &Apache::lonnet::put($stype.'_spreadsheets', + {$fn => $ENV{'user.name'}.'@'.$ENV{'user.domain'}}, + $cdom,$cnum); if ($reply eq 'ok') { if ($makedef) { - return &Apache::lonnet::reply('put:'.$cdom.':'.$cnum. - ':environment:'. - 'spreadsheet_default_'. - $stype.'='. - &Apache::lonnet::escape($fn), - $chome); + return &Apache::lonnet::put('environment', + {'spreadsheet_default_'.$stype => $fn }, + $cdom,$cnum); } return $reply; } @@ -1522,7 +1714,7 @@ sub tmpread { } } if ($nform eq 'changesheet') { - $fo{'A'.$nfield}=(split(/\_\_\&\&\&\_\_/,$fo{'A'.$nfield}))[0]; + $fo{'A'.$nfield}=(split(/__&&&\__/,$fo{'A'.$nfield}))[0]; unless ($ENV{'form.sel_'.$nfield} eq 'Default') { $fo{'A'.$nfield}.='__&&&__'.$ENV{'form.sel_'.$nfield}; } @@ -1616,6 +1808,78 @@ sub parmval { return &Apache::lonnet::metadata($fn,$rwhat.'.default'); } + +################################################################## +## Row label formatting routines ## +################################################################## +sub format_html_rowlabel { + my $rowlabel = shift; + return '' if ($rowlabel eq ''); + my ($type,$labeldata) = split(':',$rowlabel,2); + my $result = ''; + if ($type eq 'symb') { + my ($symb,$uname,$udom,$title) = split(':',$labeldata); + $symb = &Apache::lonnet::unescape($symb); + $result = ''.$title.''; + } elsif ($type eq 'student') { + my ($sname,$sdom,$fullname,$section,$id) = split(':',$labeldata); + $result =''; + $result.=$section.' '.$id." ".$fullname.''; + } elsif ($type eq 'parameter') { + $result = $labeldata; + } else { + $result = ''.$rowlabel.''; + } + return $result; +} + +sub format_csv_rowlabel { + my $rowlabel = shift; + return '' if ($rowlabel eq ''); + my ($type,$labeldata) = split(':',$rowlabel,2); + my $result = ''; + if ($type eq 'symb') { + my ($symb,$uname,$udom,$title) = split(':',$labeldata); + $symb = &Apache::lonnet::unescape($symb); + $result = $title; + } elsif ($type eq 'student') { + my ($sname,$sdom,$fullname,$section,$id) = split(':',$labeldata); + $result = join('","',($sname,$sdom,$fullname,$section,$id)); + } elsif ($type eq 'parameter') { + $labeldata =~ s/
/ /g; + $result = $labeldata; + } else { + $result = $rowlabel; + } + return '"'.$result.'"'; +} + +sub format_excel_rowlabel { + my $rowlabel = shift; + return '' if ($rowlabel eq ''); + my ($type,$labeldata) = split(':',$rowlabel,2); + my $result = ''; + if ($type eq 'symb') { + my ($symb,$uname,$udom,$title) = split(':',$labeldata); + $symb = &Apache::lonnet::unescape($symb); + $result = $title; + } elsif ($type eq 'student') { + my ($sname,$sdom,$fullname,$section,$id) = split(':',$labeldata); + $section = '' if (! defined($section)); + $id = '' if (! defined($id)); + my @Data = ($sname,$sdom,$fullname,$section,$id); + $result = \@Data; + } elsif ($type eq 'parameter') { + $labeldata =~ s/
/ /g; + $result = $labeldata; + } else { + $result = $rowlabel; + } + return $result; +} + # ---------------------------------------------- Update rows for course listing sub updateclasssheet { my ($sheet) = @_; @@ -1638,17 +1902,9 @@ sub updateclasssheet { my ($studentDomain,$studentName,$end,$start,$id,$studentSection, $fullname,$status) = @{$classlist->{$student}}; if ($ENV{'form.Status'} eq $status || $ENV{'form.Status'} eq 'Any') { - my $rowlabel=''; - if ($ENV{'form.showcsv'}) { - $rowlabel= '"'.join('","',($studentName,$studentDomain, - $fullname,$studentSection,$id).'"'); - } else { - $rowlabel=''; - $rowlabel.=$studentSection.' '.$id." ".$fullname; - $rowlabel.=''; - } - $currentlist{$student}=$rowlabel; + $currentlist{$student}=join(':',('student',$studentName, + $studentDomain,$fullname, + $studentSection,$id)); } } # @@ -1676,11 +1932,11 @@ sub updateclasssheet { } # # New and unknown keys - foreach (sort keys(%currentlist)) { - unless ($existing{$_}) { + foreach my $student (sort keys(%currentlist)) { + unless ($existing{$student}) { $changed=1; $sheet->{'maxrow'}++; - $f{'A'.$sheet->{'maxrow'}}=$_; + $f{'A'.$sheet->{'maxrow'}}=$student; } } if ($changed) { @@ -1688,62 +1944,48 @@ sub updateclasssheet { &setformulas($sheet,%f); } # - $sheet->{'rowlabel'} = \%currentlist; - &setrowlabels($sheet); + &setrowlabels($sheet,\%currentlist); } # ----------------------------------- Update rows for student and assess sheets sub updatestudentassesssheet { my ($sheet) = @_; + # my %bighash; - my $stype=$sheet->{'sheettype'}; - my $uname=$sheet->{'uname'}; - my $udom =$sheet->{'udom'}; + # + my $stype = $sheet->{'sheettype'}; + my $uname = $sheet->{'uname'}; + my $udom = $sheet->{'udom'}; $sheet->{'rowlabel'} = {}; - if ($updatedata - {$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}) { - %{$sheet->{'rowlabel'}}=split(/___;___/, - $updatedata{$ENV{'request.course.fn'}. - '_'.$stype.'_'.$uname.'_'.$udom}); + my $identifier =$sheet->{'coursefilename'}.'_'.$stype.'_'.$uname.'_'.$udom; + if ($updatedata{$identifier}) { + %{$sheet->{'rowlabel'}}=split(/___;___/,$updatedata{$identifier}); } else { # Tie hash - tie(%bighash,'GDBM_File',$ENV{'request.course.fn'}.'.db', + tie(%bighash,'GDBM_File',$sheet->{'coursefilename'}.'.db', &GDBM_READER(),0640); if (! tied(%bighash)) { return 'Could not access course data'; } # Get all assessments - my %allkeys=('timestamp' => - 'Timestamp of Last Transaction
timestamp', - 'subnumber' => - 'Number of Submissions
subnumber', - 'tutornumber' => - 'Number of Tutor Responses
tutornumber', - 'totalpoints' => - 'Total Points Granted
totalpoints'); - my $adduserstr=''; - if (($uname ne $ENV{'user.name'}) || ($udom ne $ENV{'user.domain'})){ - $adduserstr='&uname='.$uname.'&udom='.$udom; - } - my %allassess; - if (! $ENV{'form.showcsv'}) { - %allassess = - ('_feedback' =>'Feedback', - '_evaluation' =>'Evaluation', - '_tutoring' =>'Tutoring', - '_discussion' =>'Discussion' - ); - } else { - %allassess = - ('_feedback' => "Feedback", - '_evaluation' => "Evaluation", - '_tutoring' => "Tutoring", - '_discussion' => "Discussion", - ); + # + # parameter_labels is used in the assessment sheets to provide labels + # for the parameters. + my %parameter_labels= + ('timestamp' => + 'parameter:Timestamp of Last Transaction
timestamp', + 'subnumber' => + 'parameter:Number of Submissions
subnumber', + 'tutornumber' => + 'parameter:Number of Tutor Responses
tutornumber', + 'totalpoints' => + 'parameter:Total Points Granted
totalpoints'); + # + # assesslist holds the descriptions of all assessments + my %assesslist; + foreach ('Feedback','Evaluation','Tutoring','Discussion') { + my $symb = '_'.lc($_); + $assesslist{$symb} = join(':',('symb',$symb,$uname,$udom,$_)); } while (($_,undef) = each(%bighash)) { next if ($_!~/^src\_(\d+)\.(\d+)$/); @@ -1755,13 +1997,8 @@ sub updatestudentassesssheet { my $symb= &Apache::lonnet::declutter($bighash{'map_id_'.$mapid}). '___'.$resid.'___'.&Apache::lonnet::declutter($srcf); - if (! $ENV{'form.showcsv'}) { - $allassess{$symb}= - ''. - $bighash{'title_'.$id}.''; - } else { - $allassess{$symb}=$bighash{'title_'.$id}; - } + $assesslist{$symb}='symb:'.&Apache::lonnet::escape($symb).':' + .$uname.':'.$udom.':'.$bighash{'title_'.$id}; next if ($stype ne 'assesscalc'); foreach my $key (split(/\,/, &Apache::lonnet::metadata($srcf,'keys') @@ -1774,22 +2011,24 @@ sub updatestudentassesssheet { &Apache::lonnet::metadata($srcf,$key.'.name'); } $display.='
'.$key; - $allkeys{$key}=$display; + $parameter_labels{$key}='parameter:'.$display; } # end of foreach } } # end of foreach (keys(%bighash)) untie(%bighash); # - # %allkeys has a list of storage and parameter displays by unikey - # %allassess has a list of all resource displays by symb + # %parameter_labels has a list of storage and parameter displays by + # unikey + # %assesslist has a list of all resource, by symb # if ($stype eq 'assesscalc') { - $sheet->{'rowlabel'} = \%allkeys; + $sheet->{'rowlabel'} = \%parameter_labels; } elsif ($stype eq 'studentcalc') { - $sheet->{'rowlabel'} = \%allassess; + $sheet->{'rowlabel'} = \%assesslist; } - $updatedata{$ENV{'request.course.fn'}.'_'.$stype.'_'.$uname.'_'.$udom}= - join('___;___',%{$sheet->{'rowlabel'}}); + $updatedata{$sheet->{'coursefilename'}.'_'.$stype.'_' + .$uname.'_'.$udom}= + join('___;___',%{$sheet->{'rowlabel'}}); # Get current from cache } # Find discrepancies between the course row table and this @@ -1829,7 +2068,6 @@ sub updatestudentassesssheet { $sheet->{'f'} = \%f; &setformulas($sheet); } - &setrowlabels($sheet); # undef %existing; } @@ -1857,7 +2095,7 @@ sub loadstudent { my $row=$1; next if (($f{$_}=~/^[\!\~\-]/) || ($row==0)); my ($usy,$ufn)=split(/__&&&\__/,$f{$_}); - @assessdata=&exportsheet($sheet->{'uname'}, + @assessdata=&exportsheet($sheet,$sheet->{'uname'}, $sheet->{'udom'}, 'assesscalc',$usy,$ufn); my $index=0; @@ -1914,8 +2152,8 @@ ENDPOP next if ($_!~/^A(\d+)/); my $row=$1; next if (($f{$_}=~/^[\!\~\-]/) || ($row==0)); - my @studentdata=&exportsheet(split(/\:/,$f{$_}), - 'studentcalc'); + my ($sname,$sdom) = split(':',$f{$_}); + my @studentdata=&exportsheet($sheet,$sname,$sdom,'studentcalc'); undef %userrdatas; $now++; $r->print('