--- loncom/homework/grades.pm	2010/04/27 00:06:34	1.632
+++ loncom/homework/grades.pm	2010/12/20 21:23:38	1.641
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # The LON-CAPA Grading handler
 #
-# $Id: grades.pm,v 1.632 2010/04/27 00:06:34 www Exp $
+# $Id: grades.pm,v 1.641 2010/12/20 21:23:38 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -44,6 +44,7 @@ use Apache::Constants qw(:common);
 use Apache::lonlocal;
 use Apache::lonenc;
 use Apache::lonstathelpers;
+use Apache::lonquickgrades;
 use String::Similarity;
 use LONCAPA;
 
@@ -212,8 +213,13 @@ sub reset_caches {
     }
 
     sub get_analyze {
-	my ($symb,$uname,$udom,$no_increment,$add_to_hash)=@_;
+	my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed)=@_;
 	my $key = "$symb\0$uname\0$udom";
+        if ($type eq 'randomizetry') {
+            if ($trial ne '') {
+                $key .= "\0".$trial;
+            }
+        }
 	if (exists($analyze_cache{$key})) {
             my $getupdate = 0;
             if (ref($add_to_hash) eq 'HASH') {
@@ -241,9 +247,15 @@ sub reset_caches {
                     'grade_courseid'    =>  $env{'request.course.id'},
                     'grade_username'    => $uname,
                     'grade_noincrement' => $no_increment);
+        if ($type eq 'randomizetry') {
+            $form{'grade_questiontype'} = $type;
+            if ($rndseed ne '') {
+                $form{'grade_rndseed'} = $rndseed;
+            }
+        }
         if (ref($add_to_hash)) {
             %form = (%form,%{$add_to_hash});
-        } 
+        }
 	my $subresult=&ssi_with_retries($url, $ssi_retries,%form);
 	(undef,$subresult)=split(/_HASH_REF__/,$subresult,2);
 	my %analyze=&Apache::lonnet::str2hash($subresult);
@@ -256,15 +268,15 @@ sub reset_caches {
     }
 
     sub get_order {
-	my ($partid,$respid,$symb,$uname,$udom,$no_increment)=@_;
-	my $analyze = &get_analyze($symb,$uname,$udom,$no_increment);
+	my ($partid,$respid,$symb,$uname,$udom,$no_increment,$type,$trial,$rndseed)=@_;
+	my $analyze = &get_analyze($symb,$uname,$udom,$no_increment,undef,$type,$trial,$rndseed);
 	return $analyze->{"$partid.$respid.shown"};
     }
 
     sub get_radiobutton_correct_foil {
-	my ($partid,$respid,$symb,$uname,$udom)=@_;
-	my $analyze = &get_analyze($symb,$uname,$udom);
-        my $foils = &get_order($partid,$respid,$symb,$uname,$udom);
+	my ($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed)=@_;
+	my $analyze = &get_analyze($symb,$uname,$udom,undef,undef,$type,$trial,$rndseed);
+        my $foils = &get_order($partid,$respid,$symb,$uname,$udom,undef,$type,$trial,$rndseed);
         if (ref($foils) eq 'ARRAY') {
 	    foreach my $foil (@{$foils}) {
 	        if ($analyze->{"$partid.$respid.foil.value.$foil"} eq 'true') {
@@ -306,7 +318,7 @@ sub reset_caches {
 #        response types only.
 sub cleanRecord {
     my ($answer,$response,$symb,$partid,$respid,$record,$order,$version,
-	$uname,$udom) = @_;
+	$uname,$udom,$type,$trial,$rndseed) = @_;
     my $grayFont = '<span class="LC_internal_info">';
     if ($response =~ /^(option|rank)$/) {
 	my %answer=&Apache::lonnet::str2hash($answer);
@@ -350,7 +362,7 @@ sub cleanRecord {
 	my %answer=&Apache::lonnet::str2hash($answer);
 	my ($toprow,$bottomrow);
 	my $correct = 
-	    &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom);
+	    &get_radiobutton_correct_foil($partid,$respid,$symb,$uname,$udom,$type,$trial,$rndseed);
 	foreach my $foil (@$order) {
 	    if (exists($answer{$foil})) {
 		if ($foil eq $correct) {
@@ -1267,12 +1279,6 @@ sub sub_page_js {
 	    }
 	    
 	}
-	if (val == "Grade Student") {
-	    if (formname.Status.value == "") {
-		formname.Status.value = "Active";
-	    }
-	    formname.studentNo.value = total;
-	}
 	formname.submit();
     }
 
@@ -2138,6 +2144,12 @@ KEYWORDS
 		    my ($ressub,$hide,$subval) = split(/:/,$submission,3);
 		    # Similarity check
 		    my $similar='';
+                    my ($type,$trial,$rndseed);
+                    if ($hide eq 'rand') {
+                        $type = 'randomizetry';
+                        $trial = $record{"resource.$partid.tries"};
+                        $rndseed = $record{"resource.$partid.rndseed"};
+                    }
 		    if($env{'form.checkPlag'}){
 			my ($oname,$odom,$ocrsid,$oessay,$osim)=
 			    &most_similar($uname,$udom,$subval,\%old_essays);
@@ -2147,7 +2159,7 @@ KEYWORDS
 				&Apache::lonnet::coursedescription($ocrsid,
 								   {'one_time' => 1});
 
-                            if ($hide) {
+                            if ($hide eq 'anon') {
                                 $similar='<hr /><span class="LC_warning">'.&mt("Essay was found to be similar to another essay submitted for this assignment.").'<br />'.
                                          &mt('As the current submission is for an anonymous survey, no other details are available.').'</span><hr />';
                             } else {
@@ -2164,7 +2176,8 @@ KEYWORDS
                             }
 			}
 		    }
-		    my $order=&get_order($partid,$respid,$symb,$uname,$udom);
+		    my $order=&get_order($partid,$respid,$symb,$uname,$udom,
+                                         undef,$type,$trial,$rndseed);
 		    if ($env{'form.lastSub'} eq 'lastonly' || 
 			($env{'form.lastSub'} eq 'hdgrade' && 
 			 $$handgrade{$$part[0].'_'.$$part[1]} eq 'yes')) {
@@ -2176,7 +2189,7 @@ KEYWORDS
                             '</span>&nbsp; &nbsp;';
 			my $files=&get_submitted_files($udom,$uname,$partid,$respid,\%record);
 			if (@$files) {
-                            if ($hide) {
+                            if ($hide eq 'anon') {
                                 $lastsubonly.='<br />'.&mt('[quant,_1,file] uploaded to this anonymous survey',scalar(@{$files}));
                             } else {
                                 $lastsubonly.='<br /><span class="LC_warning">'.&mt('Like all files provided by users, this file may contain viruses').'</span><br />';
@@ -2187,12 +2200,12 @@ KEYWORDS
                             }
 			    $lastsubonly.='<br />';
 			}
-                        if ($hide) {
+                        if ($hide eq 'anon') {
                             $lastsubonly.='<b>'.&mt('Anonymous Survey').'</b>'; 
                         } else {
 			    $lastsubonly.='<b>'.&mt('Submitted Answer:').' </b>'.
 			        &cleanRecord($subval,$responsetype,$symb,$partid,
-					     $respid,\%record,$order,undef,$uname,$udom);
+					     $respid,\%record,$order,undef,$uname,$udom,$type,$trial,$rndseed);
                         }
 			if ($similar) {$lastsubonly.="<br /><br />$similar\n";}
 			$lastsubonly.='</div>';
@@ -2214,13 +2227,8 @@ KEYWORDS
     $request->print('<input type="hidden" name="unamedom'.$counter.'" value="'.$uname.':'
 	.$udom.'" />'."\n");
     # return if view submission with no grading option
-# FIXME: the logic seems off here. Why show the grade button if you cannot grade?
     if (!&canmodify($usec)) {
-	my $toGrade.='<input type="button" value="Grade Student" '.
-	    'onclick="javascript:checksubmit(this.form,\'Grade Student\',\''
-	    .$counter.'\');" target="_self" /> &nbsp;'."\n" if (&canmodify($usec));
-	$toGrade.='</div>'."\n";
-	$request->print($toGrade);
+	$request->print('<p><span class="LC_warning">'.&mt('No grading privileges').'</span></p></div>');
 	return;
     } else {
 	$request->print('</div>'."\n");
@@ -2396,35 +2404,51 @@ sub get_last_submission {
 		    &Apache::lonlocal::locallocaltime($$returnhash{$version.':timestamp'});
 	    }
 	}
-        my %typeparts;
+        my (%typeparts,%randombytry);
         my $showsurv = 
             &Apache::lonnet::allowed('vas',$env{'request.course.id'});
         foreach my $key (sort(keys(%lasthash))) {
             if ($key =~ /\.type$/) {
                 if (($lasthash{$key} eq 'anonsurvey') || 
-                    ($lasthash{$key} eq 'anonsurveycred')) {
+                    ($lasthash{$key} eq 'anonsurveycred') ||
+                    ($lasthash{$key} eq 'randomizetry')) {
                     my ($ign,@parts) = split(/\./,$key);
                     pop(@parts);
-                    unless ($showsurv) {
-                        my $id = join(',',@parts);
-                        $typeparts{$ign.'.'.$id} = $lasthash{$key};
+                    my $id = join('.',@parts);
+                    if ($lasthash{$key} eq 'randomizetry') {
+                        $randombytry{$ign.'.'.$id} = $lasthash{$key};
+                    } else {
+                        unless ($showsurv) {
+                            $typeparts{$ign.'.'.$id} = $lasthash{$key};
+                        }
                     }
                     delete($lasthash{$key});
                 }
             }
         }
         my @hidden = keys(%typeparts);
+        my @randomize = keys(%randombytry);
 	foreach my $key (keys(%lasthash)) {
 	    next if ($key !~ /\.submission$/);
             my $hide;
             if (@hidden) {
                 foreach my $id (@hidden) {
                     if ($key =~ /^\Q$id\E/) {
-                        $hide = 1;
+                        $hide = 'anon';
                         last;
                     }
                 }
             }
+            unless ($hide) {
+                if (@randomize) {
+                    foreach my $id (@hidden) {
+                        if ($key =~ /^\Q$id\E/) {
+                            $hide = 'rand';
+                            last;
+                        }
+                    }
+                }
+            }
 	    my ($partid,$foo) = split(/submission$/,$key);
 	    my $draft  = $lasthash{$partid.'awarddetail'} eq 'DRAFT' ?
 		'<span class="LC_warning">Draft Copy</span> ' : '';
@@ -2593,16 +2617,6 @@ sub processHandGrade {
 	return '';
     }
 
-# Go directly to grade student - from submission or link from chart page
-# FIXME: looks like reading off the button label!
-    if ($button eq 'Grade Student') {
-	my $processUser = $env{'form.unamedom'.$env{'form.studentNo'}};
-	($env{'form.student'},$env{'form.userdom'}) = split(/:/,$processUser);
-	$env{'form.fullname'} = $$fullname{$processUser};
-	&submission($request,0,0,$symb);
-	return '';
-    }
-
     # Get the next/previous one or group of students
     my $firststu = $env{'form.unamedom0'};
     my $laststu = $env{'form.unamedom'.($ngrade-1)};
@@ -4078,6 +4092,9 @@ sub csvuploadassign {
                     my $pcr=$entries{$fields{$dest}} / $wgt;
                     my $award=($pcr == 0) ? 'incorrect_by_override'
                                           : 'correct_by_override';
+                    if ($pcr>1) {
+                       push(@skipped,&mt("[_1]: point value larger than weight","$username:$domain"));
+                    }
                     $grades{"resource.$part.awarded"}=$pcr;
                     $grades{"resource.$part.solved"}=$award;
                     $points{$part}=1;
@@ -4383,8 +4400,8 @@ sub displayPage {
 		&Apache::loncommon::start_data_table_row().
 		'<td align="center" valign="top" >'.$prob.
 		(scalar(@{$parts}) == 1 ? '' 
-		                        : '<br />('.&mt('[_1]&nbsp;parts)',
-							scalar(@{$parts}))
+		                        : '<br />('.&mt('[_1]parts)',
+							scalar(@{$parts}).'&nbsp;')
 		 ).
 		 '</td>';
 	    $studentTable.='<td valign="top">';
@@ -4478,6 +4495,7 @@ sub displaySubByDates {
 
     my $interaction;
     my $no_increment = 1;
+    my %lastrndseed;
     for ($version=1;$version<=$$record{'version'};$version++) {
 	my $timestamp = 
 	    &Apache::lonlocal::locallocaltime($$record{$version.':timestamp'});
@@ -4495,9 +4513,9 @@ sub displaySubByDates {
 	my @versionKeys = split(/\:/,$$record{$version.':keys'});
 	my @displaySub = ();
 	foreach my $partid (@{$parts}) {
-            my $hidden;
-            if (($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurvey') ||
-                ($$record{$version.':resource.'.$partid.'.type'} eq 'anonsurveycred')) {
+            my ($hidden,$type);
+            $type = $$record{$version.':resource.'.$partid.'.type'};
+            if (($type eq 'anonsurvey') || ($type eq 'anonsurveycred')) {
                 $hidden = 1;
             }
 	    my @matchKey = ($isTask ? sort(grep /^resource\.\d+\.\Q$partid\E\.award$/,@versionKeys)
@@ -4520,23 +4538,34 @@ sub displaySubByDates {
                     if ($hidden) {
                         $displaySub[0].= &mt('Anonymous Survey').'</b>';
                     } else {
+                        my ($trial,$rndseed,$newvariation);
+                        if ($type eq 'randomizetry') {
+                            $trial = $$record{"$where.$partid.tries"};
+                            $rndseed = $$record{"$where.$partid.rndseed"};
+                        }
 		        if ($$record{"$where.$partid.tries"} eq '') {
 			    $displaySub[0].=&mt('Trial not counted');
 		        } else {
 			    $displaySub[0].=&mt('Trial: [_1]',
 					    $$record{"$where.$partid.tries"});
+                            if ($rndseed || $lastrndseed{$partid}) {
+                                if ($rndseed ne $lastrndseed{$partid}) {
+                                    $newvariation = '&nbsp;('.&mt('New variation this try').')';
+                                }
+                            }
+                            $lastrndseed{$partid} = $rndseed;
 		        }
 		        my $responseType=($isTask ? 'Task'
                                               : $responseType->{$partid}->{$responseId});
 		        if (!exists($orders{$partid})) { $orders{$partid}={}; }
-		        if (!exists($orders{$partid}->{$responseId})) {
+		        if ((!exists($orders{$partid}->{$responseId})) || ($trial)) {
 			    $orders{$partid}->{$responseId}=
 			        &get_order($partid,$responseId,$symb,$uname,$udom,
-                                           $no_increment);
+                                           $no_increment,$type,$trial,$rndseed);
 		        }
-		        $displaySub[0].='</b></span>'; # /nobreak
+		        $displaySub[0].='</b>'.$newvariation.'</span>'; # /nobreak
 		        $displaySub[0].='&nbsp; '.
-			    &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom).'<br />';
+			    &cleanRecord($$record{$version.':'.$matchKey},$responseType,$symb,$partid,$responseId,$record,$orders{$partid}->{$responseId},"$version:",$uname,$udom,$type,$trial,$rndseed).'<br />';
                     }
 		}
 	    }
@@ -4635,7 +4664,7 @@ sub updateGradeByPage {
 		&Apache::loncommon::start_data_table_row().
 		'<td align="center" valign="top" >'.$prob.
 		(scalar(@{$parts}) == 1 ? '' 
-                                        : '<br />('.&mt('[quant,_1,&nbsp;part]',scalar(@{$parts}))
+                                        : '<br />('.&mt('[quant,_1,part]',scalar(@{$parts}))
 		.')').'</td>';
 	    $studentTable.='<td valign="top">&nbsp;<b>'.$title.'</b>&nbsp;</td>';
 
@@ -8401,32 +8430,32 @@ sub grading_menu {
                         {	linktext => 'Select individual students to grade',
                     		url => $url1a,
                     		permission => 'F',
-                    		icon => 'edit-find-replace.png',
+                    		icon => 'grade_students.png',
                     		linktitle => 'Grade current resource for a selection of students.'
                         }, 
                         {       linktext => 'Grade ungraded submissions.',
                                 url => $url1b,
                                 permission => 'F',
-                                icon => 'edit-find-replace.png',
+                                icon => 'ungrade_sub.png',
                                 linktitle => 'Grade all submissions that have not been graded yet.'
                         },
 
                         {       linktext => 'Grading table',
                                 url => $url1c,
                                 permission => 'F',
-                                icon => 'edit-find-replace.png',
+                                icon => 'grading_table.png',
                                 linktitle => 'Grade current resource for all students.'
                         },
                         {       linktext => 'Grade page/folder for one student',
                                 url => $url1d,
                                 permission => 'F',
-                                icon => 'edit-find-replace.png',
+                                icon => 'grade_PageFolder.png',
                                 linktitle => 'Grade all resources in current page/sequence/folder for one student.'
                         },
                         {       linktext => 'Download submissions',
                                 url => $url1e,
                                 permission => 'F',
-                                icon => 'edit-find-replace.png',
+                                icon => 'download_sub.png',
                                 linktitle => 'Download all students submissions.'
                         }]},
                          { categorytitle=>'Automated Grading',
@@ -8447,13 +8476,13 @@ sub grading_menu {
                 	    {	linktext => 'Grade/Manage/Review Bubblesheets',
                     		url => $url4,
                     		permission => 'F',
-                    		icon => 'stat.png',
+                    		icon => 'bubblesheet.png',
                     		linktitle => 'Grade scantron exams, upload/download scantron data files, and review previously graded scantron exams.'
                 	    },
                             {   linktext => 'Verify Receipt Number',
                                 url => $url5,
                                 permission => 'F',
-                                icon => 'edit-find-replace.png',
+                                icon => 'receipt_number.png',
                                 linktitle => 'Verify a system-generated receipt number for correct problem solution.'
                             }
 
@@ -8558,6 +8587,14 @@ sub submit_options {
 
 sub selectfield {
    my ($full)=@_;
+   my %options = 
+          (&Apache::lonlocal::texthash(
+             'yes'       => 'with submissions',
+             'queued'    => 'in grading queue',
+             'graded'    => 'with ungraded submissions',
+             'incorrect' => 'with incorrect submissions',
+             'all'       => 'with any status'),
+             'select_form_order' => ['yes','queued','graded','incorrect','all']);
    my $result='<div class="LC_columnSection">
   
     <fieldset>
@@ -8586,14 +8623,7 @@ sub selectfield {
       <legend>
         '.&mt('Submission Status').'
       </legend>'.
-       &Apache::loncommon::select_form('all','submitonly',
-          (&Apache::lonlocal::texthash(
-             'yes'       => 'with submissions',
-             'queued'    => 'in grading queue',
-             'graded'    => 'with ungraded submissions',
-             'incorrect' => 'with incorrect submissions',
-             'all'       => 'with any status'),
-             'select_form_order' => ['yes','queued','graded','incorrect','all'])).
+       &Apache::loncommon::select_form('all','submitonly',\%options).
    '</fieldset>';
     }
     $result.='</div><br />';
@@ -8718,8 +8748,8 @@ sub process_clicker {
     my $pcorrect=&mt("Percentage points for correct solution");
     my $pincorrect=&mt("Percentage points for incorrect solution");
     my $selectform=&Apache::loncommon::select_form($env{'form.upfiletype'},'upfiletype',
-						   ('iclicker' => 'i>clicker',
-                                                    'interwrite' => 'interwrite PRS'));
+						   {'iclicker' => 'i>clicker',
+                                                    'interwrite' => 'interwrite PRS'});
     $symb = &Apache::lonenc::check_encrypt($symb);
     $result.= &Apache::lonhtmlcommon::scripttag(<<ENDUPFORM);
 function sanitycheck() {
@@ -9157,7 +9187,7 @@ sub startpage {
     unshift(@$crumbs,{href=>&href_symb_cmd($symb,'gradingmenu'),text=>"Grading"});
     $r->print(&Apache::loncommon::start_page('Grading',undef,
                                           {'bread_crumbs' => $crumbs}));
-    $r->print('<h3>'.$$crumbs[-1]{'text'}.'</h3>');
+    &Apache::lonquickgrades::startGradeScreen($r,'grading');
     unless ($nodisplayflag) {
        $r->print(&Apache::lonhtmlcommon::resource_info_box($symb,$onlyfolderflag));
     }
@@ -9202,9 +9232,9 @@ sub handler {
     &Apache::lonenc::check_decrypt(\$symb);                             
 
     $ssi_error = 0;
-    if ($symb eq '' || $command eq '') {
+    if (($symb eq '' || $command eq '') && ($env{'request.course.id'})) {
 #
-# Not called from a resource
+# Not called from a resource, but inside a course
 #    
         &startpage($request,undef,[],1,1);
         &select_problem($request);
@@ -9350,6 +9380,7 @@ sub handler {
     if ($ssi_error) {
 	&ssi_print_error($request);
     }
+    &Apache::lonquickgrades::endGradeScreen($request);
     $request->print(&Apache::loncommon::end_page());
     &reset_caches();
     return '';