--- loncom/homework/grades.pm 2011/10/09 23:24:27 1.596.2.4 +++ loncom/homework/grades.pm 2012/05/02 14:23:34 1.596.2.12.2.2 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # The LON-CAPA Grading handler # -# $Id: grades.pm,v 1.596.2.4 2011/10/09 23:24:27 raeburn Exp $ +# $Id: grades.pm,v 1.596.2.12.2.2 2012/05/02 14:23:34 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -272,7 +272,7 @@ sub reset_caches { } sub get_analyze { - my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed)=@_; + my ($symb,$uname,$udom,$no_increment,$add_to_hash,$type,$trial,$rndseed,$bubbles_per_row)=@_; my $key = "$symb\0$uname\0$udom"; if ($type eq 'randomizetry') { if ($trial ne '') { @@ -306,6 +306,9 @@ sub reset_caches { 'grade_courseid' => $env{'request.course.id'}, 'grade_username' => $uname, 'grade_noincrement' => $no_increment); + if ($bubbles_per_row ne '') { + $form{'bubbles_per_row'} = $bubbles_per_row; + } if ($type eq 'randomizetry') { $form{'grade_questiontype'} = $type; if ($rndseed ne '') { @@ -346,7 +349,7 @@ sub reset_caches { } sub scantron_partids_tograde { - my ($resource,$cid,$uname,$udom,$check_for_randomlist) = @_; + my ($resource,$cid,$uname,$udom,$check_for_randomlist,$bubbles_per_row) = @_; my (%analysis,@parts); if (ref($resource)) { my $symb = $resource->symb(); @@ -354,7 +357,9 @@ sub reset_caches { if ($check_for_randomlist) { $add_to_form = { 'check_parts_withrandomlist' => 1,}; } - my $analyze = &get_analyze($symb,$uname,$udom,undef,$add_to_form); + my $analyze = + &get_analyze($symb,$uname,$udom,undef,$add_to_form, + undef,undef,undef,$bubbles_per_row); if (ref($analyze) eq 'HASH') { %analysis = %{$analyze}; } @@ -416,7 +421,7 @@ sub cleanRecord { '
'.&mt("You have not selected a file that contains the student's response data.").'
'); } if ( $env{'form.scantron_format'} eq '') { - $r->print(''.&mt(:You have not selected the format of the student's response data.").'
'); + $r->print(''.&mt("You have not selected the format of the student's response data.").'
'); } } else { my $warning=&scantron_warning_screen('Grading: Validate Records'); @@ -6477,7 +6493,7 @@ SCANTRONFORM =item scantron_validate_file - Dispatch routine for doing validation of a bubble sheet data file. + Dispatch routine for doing validation of a bubblesheet data file. Also processes any necessary information resets that need to occur before validation begins (ignore previous corrections, @@ -6515,7 +6531,8 @@ sub scantron_validate_file { #get the student pick code ready $r->print(&Apache::loncommon::studentbrowser_javascript()); my $nav_error; - my $max_bubble=&scantron_get_maxbubble(\$nav_error); + my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); + my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config); if ($nav_error) { $r->print(&navmap_errormsg()); return ''; @@ -6588,7 +6605,7 @@ sub scantron_validate_file { =item scantron_remove_file - Removes the requested bubble sheet data file, makes sure that + Removes the requested bubblesheet data file, makes sure that scantron_original_".&mt("An error was detected ($error)". - " for PaperID [_1]", - $$scan_record{'scantron.PaperID'})."
\n"); + $r->print( + '' + .&mt('An error was detected ([_1]) for PaperID [_2]', + "$error", + ''.$$scan_record{'scantron.PaperID'}.'') + ."
\n"); } else { - $r->print("".&mt("An error was detected ($error)". - " in scanline [_1]
[_2]", - $i,$line)." \n"); - } - my $message="
".&mt("The ID on the form is [_1]
".
- "The name on the paper is [_2],[_3]",
- $$scan_record{'scantron.ID'},
- $$scan_record{'scantron.LastName'},
- $$scan_record{'scantron.FirstName'})."
' + .&mt('An error was detected ([_1]) in scanline [_2] [_3]', + "$error", $i, "
$line") + ." \n"); + } + my $message = + '
'
+ .&mt('The ID on the form is [_1]',
+ "$$scan_record{'scantron.ID'}")
+ .'
'
+ .&mt('The name on the paper is [_1], [_2]',
+ $$scan_record{'scantron.LastName'},
+ $$scan_record{'scantron.FirstName'})
+ .'
".&mt("The encoded ID is not in the classlist"). + $r->print('
'.&mt("The encoded ID is not in the classlist"). "
\n"); } elsif ($error eq 'duplicateID') { - $r->print("".&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n"); + $r->print(''.&mt("The encoded ID has also been used by a previous paper [_1]",$arg)."
\n"); } $r->print($message); $r->print("".&mt("How should I handle this?")."
\n");
@@ -7074,14 +7100,15 @@ sub scantron_get_correction {
$r->print('');
} elsif ($error =~ /CODE$/) {
if ($error eq 'incorrectCODE') {
- $r->print("
".&mt("The encoded CODE is not in the list of possible CODEs.")."
\n"); + $r->print(''.&mt("The encoded CODE is not in the list of possible CODEs.")."
\n"); } elsif ($error eq 'duplicateCODE') { - $r->print("".&mt("The encoded CODE has also been used by a previous paper [_1], and CODEs are supposed to be unique.",join(', ',@{$arg}))."
\n"); + $r->print(''.&mt("The encoded CODE has also been used by a previous paper [_1], and CODEs are supposed to be unique.",join(', ',@{$arg}))."
\n"); } - $r->print("".&mt("The CODE on the form is '[_1]'",
- $$scan_record{'scantron.CODE'})."
\n");
+ $r->print("
".&mt('The CODE on the form is [_1]', + "'$$scan_record{'scantron.CODE'}'") + ."
\n"); $r->print($message); - $r->print("".&mt("How should I handle this?")."
\n");
+ $r->print("
".&mt("How should I handle this?")."
\n"); $r->print("\n".&mt("There have been multiple bubbles scanned for some question(s)")."
\n"); + $r->print(''.&mt("There have been multiple bubbles scanned for some question(s)")."
\n"); # The form field scantron_questions is acutally a list of line numbers. # represented by this form so: @@ -7166,7 +7193,7 @@ ENDSCRIPT } $r->print(&verify_bubbles_checked(@lines_to_correct)); } elsif ($error eq 'missingbubble') { - $r->print("".&mt("There have been no bubbles scanned for some question(s)")."
\n"); + $r->print(''.&mt("There have been [_1]no[_2] bubbles scanned for some question(s)",'','')."
\n"); $r->print($message); $r->print("".&mt("Please indicate which bubble should be used for grading.")."
"); $r->print(&mt("Some questions have no scanned bubbles.")."\n"); @@ -7371,7 +7398,19 @@ sub scantron_bubble_selector { my $max=$$scan_config{'Qlength'}; my $scmode=$$scan_config{'Qon'}; - if ($scmode eq 'number' || $scmode eq 'letter') { $max=10; } + if ($scmode eq 'number' || $scmode eq 'letter') { + if (($$scan_config{'BubblesPerRow'} =~ /^\d+$/) && + ($$scan_config{'BubblesPerRow'} > 0)) { + $max=$$scan_config{'BubblesPerRow'}; + if (($scmode eq 'number') && ($max > 10)) { + $max = 10; + } elsif (($scmode eq 'letter') && $max > 26) { + $max = 26; + } + } else { + $max = 10; + } + } my @alphabet=('A'..'Z'); $r->print(&Apache::loncommon::start_data_table(). @@ -7526,7 +7565,7 @@ sub scantron_validate_CODE { my %allcodes=&get_codes(); my $nav_error; - &scantron_get_maxbubble(\$nav_error); # parse needs the lines per response array. + &scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the lines per response array. if ($nav_error) { $r->print(&navmap_errormsg()); return(1,$currentphase); @@ -7585,7 +7624,7 @@ sub scantron_validate_doublebubble { my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); my $nav_error; - &scantron_get_maxbubble(\$nav_error); # parse needs the bubble line array. + &scantron_get_maxbubble(\$nav_error,\%scantron_config); # parse needs the bubble line array. if ($nav_error) { $r->print(&navmap_errormsg()); return(1,$currentphase); @@ -7607,7 +7646,7 @@ sub scantron_validate_doublebubble { sub scantron_get_maxbubble { - my ($nav_error) = @_; + my ($nav_error,$scantron_config) = @_; if (defined($env{'form.scantron_maxbubble'}) && $env{'form.scantron_maxbubble'}) { &restore_bubble_lines(); @@ -7626,6 +7665,7 @@ sub scantron_get_maxbubble { } my $map=$navmap->getResourceByUrl($sequence); my @resources=$navmap->retrieveResources($map,\&scantron_filter,1,0); + my $bubbles_per_row = &bubblesheet_bubbles_per_row($scantron_config); &Apache::lonxml::clear_problem_counter(); @@ -7641,7 +7681,8 @@ sub scantron_get_maxbubble { my $response_number = 0; my $bubble_line = 0; foreach my $resource (@resources) { - my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname,$udom); + my ($analysis,$parts) = &scantron_partids_tograde($resource,$cid,$uname, + $udom,$bubbles_per_row); if ((ref($analysis) eq 'HASH') && (ref($parts) eq 'ARRAY')) { foreach my $part_id (@{$parts}) { my $lines; @@ -7670,9 +7711,10 @@ sub scantron_get_maxbubble { if (ref($analysis->{$part_id.'.shown'}) eq 'ARRAY') { $numshown = scalar(@{$analysis->{$part_id.'.shown'}}); } - my $bubbles_per_line = 10; - my $inner_bubble_lines = int($numbub/$bubbles_per_line); - if (($numbub % $bubbles_per_line) != 0) { + my $bubbles_per_row = + &bubblesheet_bubbles_per_row($scantron_config); + my $inner_bubble_lines = int($numbub/$bubbles_per_row); + if (($numbub % $bubbles_per_row) != 0) { $inner_bubble_lines++; } for (my $i=0; $i<$numshown; $i++) { @@ -7683,7 +7725,7 @@ sub scantron_get_maxbubble { $lines = $numshown * $inner_bubble_lines; } else { $lines = $analysis->{"$part_id.bubble_lines"}; - } + } $first_bubble_line{$response_number} = $bubble_line; $bubble_lines_per_response{$response_number} = $lines; @@ -7704,6 +7746,18 @@ sub scantron_get_maxbubble { return $env{'form.scantron_maxbubble'}; } +sub bubblesheet_bubbles_per_row { + my ($scantron_config) = @_; + my $bubbles_per_row; + if (ref($scantron_config) eq 'HASH') { + $bubbles_per_row = $scantron_config->{'BubblesPerRow'}; + } + if ((!$bubbles_per_row) || ($bubbles_per_row < 1)) { + $bubbles_per_row = 10; + } + return $bubbles_per_row; +} + sub scantron_validate_missingbubbles { my ($r,$currentphase) = @_; #get student info @@ -7714,7 +7768,7 @@ sub scantron_validate_missingbubbles { my %scantron_config=&get_scantron_config($env{'form.scantron_format'}); my ($scanlines,$scan_data)=&scantron_getfile(); my $nav_error; - my $max_bubble=&scantron_get_maxbubble(\$nav_error); + my $max_bubble=&scantron_get_maxbubble(\$nav_error,\%scantron_config); if ($nav_error) { return(1,$currentphase); } @@ -7797,7 +7851,8 @@ sub scantron_process_students { } my ($analysis,$parts) = &scantron_partids_tograde($resource,$env{'request.course.id'}, - $env{'user.name'},$env{'user.domain'},1); + $env{'user.name'},$env{'user.domain'}, + 1,$bubbles_per_row); $grader_partids_by_symb{$ressymb} = $parts; if (ref($analysis) eq 'HASH') { if (ref($analysis->{'parts_withrandomlist'}) eq 'ARRAY') { @@ -7835,7 +7890,7 @@ SCANTRONFORM my $started; my $nav_error; - &scantron_get_maxbubble(\$nav_error); # Need the bubble lines array to parse. + &scantron_get_maxbubble(\$nav_error,\%scantron_config); # Need the bubble lines array to parse. if ($nav_error) { $r->print(&navmap_errormsg()); return ''; @@ -7892,7 +7947,8 @@ SCANTRONFORM if ((exists($grader_randomlists_by_symb{$ressymb})) || (ref($grader_partids_by_symb{$ressymb}) ne 'ARRAY')) { my ($analysis,$parts) = - &scantron_partids_tograde($resource,$env{'request.course.id'},$uname,$udom); + &scantron_partids_tograde($resource,$env{'request.course.id'}, + $uname,$udom,undef,$bubbles_per_row); $partids_by_symb{$ressymb} = $parts; } else { $partids_by_symb{$ressymb} = $grader_partids_by_symb{$ressymb}; @@ -7921,7 +7977,8 @@ SCANTRONFORM } if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode, - \@resources,\%partids_by_symb) eq 'ssi_error') { + \@resources,\%partids_by_symb, + $bubbles_per_row) eq 'ssi_error') { $ssi_error = 0; # So end of handler error message does not trigger. $r->print(""); &ssi_print_error($r); @@ -7949,7 +8006,8 @@ SCANTRONFORM if ($studentrecord ne $studentdata) { &Apache::lonxml::clear_problem_counter(); if (&grade_student_bubbles($r,$uname,$udom,$scan_record,$scancode, - \@resources,\%partids_by_symb) eq 'ssi_error') { + \@resources,\%partids_by_symb, + $bubbles_per_row) eq 'ssi_error') { $ssi_error = 0; # So end of handler error message does not trigger. $r->print(""); &ssi_print_error($r); @@ -7969,12 +8027,12 @@ SCANTRONFORM $studentrecord .= $recording; } if ($studentrecord ne $studentdata) { - $r->print('');
+ $r->print(' ');
if ($scancode eq '') {
- $r->print(&mt('Mismatch grading bubble sheet for user: [_1] with ID: [_2].',
+ $r->print(&mt('Mismatch grading bubblesheet for user: [_1] with ID: [_2].',
$uname.':'.$udom,$scan_record->{'scantron.ID'}));
} else {
- $r->print(&mt('Mismatch grading bubble sheet for user: [_1] with ID: [_2] and CODE: [_3].',
+ $r->print(&mt('Mismatch grading bubblesheet for user: [_1] with ID: [_2] and CODE: [_3].',
$uname.':'.$udom,$scan_record->{'scantron.ID'},$scancode));
}
$r->print('
'.&Apache::loncommon::start_data_table()."\n".
@@ -7982,11 +8040,11 @@ SCANTRONFORM
'
'.
- &mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([_4] bubblesheet lines/student).',
+ &mt('Comparison of bubblesheet data (including corrections) with corresponding submission records (most recent submission) for [_1][quant,_2,student][_3] ([quant,_4,bubblesheet line] per student).',
'',
$numstudents,
'',
@@ -9372,9 +9436,10 @@ sub assign_clicker_grades {
# FIXME: This should probably look for the first handgradeable part
my $part=$$partlist[0];
# Start screen output
- my ($result) = &showResourceInfo($symb,$env{'form.probTitle'}).'
';
+ my ($result) = &showResourceInfo($symb,$env{'form.probTitle'});
- $result .= &Apache::loncommon::start_data_table().
+ $result .= '
'.
+ &Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row().
'