File:  [LON-CAPA] / loncom / interface / statistics / lonstudentassessment.pm
Revision 1.28: download - view: text, annotated - select for diffs
Fri Feb 21 18:41:56 2003 UTC (21 years, 4 months ago) by matthew
Branches: MAIN
CVS tags: HEAD
POD updates.

    1: # The LearningOnline Network with CAPA
    2: # (Publication Handler
    3: #
    4: # $Id: lonstudentassessment.pm,v 1.28 2003/02/21 18:41:56 matthew Exp $
    5: #
    6: # Copyright Michigan State University Board of Trustees
    7: #
    8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    9: # LON-CAPA is free software; you can redistribute it and/or modify
   10: # it under the terms of the GNU General Public License as published by
   11: # the Free Software Foundation; either version 2 of the License, or
   12: # (at your option) any later version.
   13: #
   14: # LON-CAPA is distributed in the hope that it will be useful,
   15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17: # GNU General Public License for more details.
   18: #
   19: # You should have received a copy of the GNU General Public License
   20: # along with LON-CAPA; if not, write to the Free Software
   21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22: #
   23: # /home/httpd/html/adm/gpl.txt
   24: #
   25: # http://www.lon-capa.org/
   26: #
   27: # (Navigate problems for statistical reports
   28: #
   29: #######################################################
   30: #######################################################
   31: 
   32: =pod
   33: 
   34: =head1 NAME
   35: 
   36: lonstudentassessment
   37: 
   38: =head1 SYNOPSIS
   39: 
   40: Presents assessment data about a student or a group of students.
   41: 
   42: =head1 Subroutines
   43: 
   44: =over 4 
   45: 
   46: =cut
   47: 
   48: #######################################################
   49: #######################################################
   50: 
   51: package Apache::lonstudentassessment;
   52: 
   53: use strict;
   54: use Apache::lonstatistics;
   55: use Apache::lonhtmlcommon;
   56: use Apache::loncoursedata;
   57: use Apache::lonnet; # for logging porpoises
   58: use GDBM_File;
   59: 
   60: #######################################################
   61: #######################################################
   62: 
   63: =pod
   64: 
   65: =item &BuildStudentAssessmentPage()
   66: 
   67: Inputs: 
   68: 
   69: =over 4
   70: 
   71: =item $cacheDB The name of the cache file used to store student data
   72: 
   73: =item $students Array ref containing the name(s) of the students 
   74: selected for display
   75: 
   76: =item $courseID The ID of the course
   77: 
   78: =item $formName The name of the html form - 'Statistics'
   79: 
   80: =item $headings Array ref of headings to show
   81: 
   82: =item $spacing A string of spaces
   83: 
   84: =item $studentInformation Array ref of possible headings for student info
   85: ('fullname','section',...)
   86: 
   87: =item $r Apache Request
   88: 
   89: =item $c Apache Connection 
   90: 
   91: =back
   92: 
   93: =cut
   94: 
   95: #######################################################
   96: #######################################################
   97: sub BuildStudentAssessmentPage {
   98:     my ($cacheDB,$students,$courseID,$formName,$headings,$spacing,
   99:         $studentInformation,$r,$c)=@_;
  100:     my %cache;
  101:     unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
  102:         $r->print('<html><body>Unable to tie database.</body></html>');
  103:         return;
  104:     }
  105: 
  106:     # Remove students who don't have the proper section.
  107:     my @sectionsSelected = split(':',$cache{'sectionsSelected'});
  108:     for(my $studentIndex=((scalar @$students)-1); $studentIndex>=0;
  109:         $studentIndex--) {
  110:         my $value = $cache{$students->[$studentIndex].':section'};
  111:         my $found = 0;
  112:         foreach (@sectionsSelected) {
  113:             if($_ eq 'none') {
  114:                 if($value eq '' || !defined($value) || $value eq ' ') {
  115:                     $found = 1;
  116:                     last;
  117:                 }
  118:             } else {
  119:                 if($value eq $_) {
  120:                     $found = 1;
  121:                     last;
  122:                 }
  123:             }
  124:         }
  125:         if($found == 0) {
  126:             splice(@$students, $studentIndex, 1);
  127:         }
  128:     }
  129:     my ($infoHeadings, $infoKeys, $sequenceHeadings, $sequenceKeys,
  130:         $doNotShow) =
  131:         &ShouldShowColumns(\%cache, $headings, $studentInformation);
  132: 
  133:     my $selectedName = &FindSelectedStudent(\%cache,
  134:                                             $cache{'StudentAssessmentStudent'},
  135:                                             $students);
  136:     $r->print(&CreateInterface(\%cache, $selectedName, $students, $formName,
  137:                                $doNotShow));
  138:     $r->rflush();
  139: 
  140:     my $Str = '';
  141:     if($selectedName eq 'No Student Selected') {
  142: 	$Str .= '<h3><font color=blue>WARNING: ';
  143:         $Str .= 'Please select a student</font></h3>';
  144:         $r->print($Str);
  145:         return;
  146:     }
  147: 
  148:     $r->print(&CreateTableHeadings(\%cache, $spacing, $infoKeys, $infoHeadings,
  149:                                    $sequenceKeys, $sequenceHeadings));
  150:     untie(%cache);
  151:     if($c->aborted()) {  return $Str; }
  152: 
  153:     my $selected=0;
  154:     my $Count = 0;
  155:     $r->print('<pre>'."\n");
  156:     foreach (@$students) {
  157:         if($c->aborted()) { return $Str; }
  158:         next if ($_ ne $selectedName &&
  159:                  $selectedName ne 'All Students');
  160:         $selected = 1;
  161: 
  162:         my @who = ($_);
  163:         next if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'true',
  164:                                                              $cacheDB, 'true',
  165:                                                              'false', $courseID,
  166:                                                              $r, $c) ne 'OK');
  167:         next if($c->aborted());
  168: 
  169:         if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
  170:             my @before=();
  171:             my @after=();
  172:             my @updateColumn=();
  173:             my $foundUpdate = 0;
  174:             foreach(@$infoKeys) {
  175:                 if(/updateTime/) {
  176:                     $foundUpdate=1;
  177:                     push(@updateColumn, $_);
  178:                     next;
  179:                 }
  180:                 if($foundUpdate) {
  181:                     push(@after, $_);
  182:                 } else {
  183:                     push(@before, $_);
  184:                 }
  185:             }
  186:             $Count++;
  187: 	    my $out = '';
  188: 	    $out .= sprintf("%3d) ", $Count);
  189:             if($Count % 2) {
  190:                 $out .= '<bgcolor="#FFFFFF">';
  191:             } else {
  192:                 $out .= '<bgcolor="#505050">';
  193:             }
  194: 	    my $displayString = $out.'DISPLAYDATA'.$spacing;
  195: 	    $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
  196:                                                          \%cache, $_,
  197:                                                          \@before,
  198:                                                          $displayString,
  199:                                                          'preformatted'));
  200: 
  201:             if($foundUpdate) {
  202:                 $displayString = '';
  203:                 $displayString .= '<a href="/adm/statistics?reportSelected=';
  204:                 $displayString .= &Apache::lonnet::escape('Student Assessment');
  205:                 $displayString .= '&download='.$_.'">';
  206:                 $displayString .= 'DISPLAYDATA</a>'.$spacing;
  207:                 $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
  208:                                                                    \%cache, $_,
  209:                                                                    \@updateColumn,
  210:                                                                    $displayString,
  211:                                                                    'preformatted'));
  212:             }
  213: 
  214:             $displayString = 'DISPLAYDATA'.$spacing;
  215:             $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
  216:                                                          \%cache, $_,
  217:                                                          \@after,
  218:                                                          $displayString,
  219:                                                          'preformatted'));
  220:             $r->print(&StudentReport(\%cache, $_, $spacing, $sequenceKeys));
  221:             $r->print("\n");
  222:             $r->rflush();
  223:             untie(%cache);
  224:         }
  225:     }
  226:     $r->print('</pre>'."\n"); 
  227:     if($selected == 0) {
  228: 	$Str .= '<h3><font color=blue>WARNING: ';
  229:         $Str .= 'No Students enrolled OR Please select a student</font></h3>';
  230:         $r->print($Str);
  231:     } else {
  232: 	if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
  233: 	    $r->print(&StudentAverageTotal(\%cache, $students, $sequenceKeys));
  234: 	    untie(%cache);
  235: 	}
  236:     }
  237:     return;
  238: }
  239: #######################################################
  240: #######################################################
  241: 
  242: =pod
  243: 
  244: =item &CreateInterface()
  245: 
  246: Called by &BuildStudentAssessmentPage to create the top part of the
  247: page which displays the chart.
  248: 
  249: Inputs:
  250: 
  251: =over 4
  252: 
  253: =item $cache The ubiquitous cache
  254: 
  255: =item $selectedName The name of the currently selected student, or
  256: 'All Students' or 'No Student Selected'.
  257: 
  258: =item $students Array ref containing the name(s) of the students selected
  259: for display.
  260: 
  261: =item $formName The name of the HTML form to use, 'Statistics'
  262: 
  263: =item $doNotShow Array ref containing the names of columns to not show
  264: 
  265: =back
  266: 
  267: Returns:  A string containing the HTML for the headers and top table for 
  268: the chart page.
  269: 
  270: =cut
  271: 
  272: #######################################################
  273: #######################################################
  274: sub CreateInterface {
  275:     my($cache,$selectedName,$students,$formName,$doNotShow)=@_;
  276: 
  277:     my $Str = '';
  278:     $Str .= &CreateLegend();
  279:     $Str .= '<table><tr><td>'."\n";
  280:     $Str .= '<input type="submit" name="PreviousStudent" ';
  281:     $Str .= 'value="Previous Student" />'."\n";
  282:     $Str .= '&nbsp&nbsp&nbsp'."\n";
  283:     $Str .= &Apache::lonhtmlcommon::StudentOptions($cache, $students,
  284:                                                    $selectedName,
  285:                                                    'StudentAssessment',
  286:                                                    $formName);
  287:     $Str .= "\n".'&nbsp&nbsp&nbsp'."\n";
  288:     $Str .= '<input type="submit" name="NextStudent" ';
  289:     $Str .= 'value="Next Student" />'."\n";
  290:     $Str .= '</td></tr></table>'."\n";
  291:     $Str .= '<table cellspacing="5"><tr>'."\n";
  292:     $Str .= '<td align="center"><b>Select Sections</b>'."\n";
  293:     $Str .= '</td>'."\n";
  294:     $Str .= '<td align="center"><b>Select column to view:</b></td>'."\n";
  295:     $Str .= '<td></td></tr>'."\n";
  296: 
  297:     $Str .= '<tr><td align="center">'."\n";
  298:     my @sections = split(':',$cache->{'sectionList'});
  299:     my @selectedSections = split(':',$cache->{'sectionsSelected'});
  300:     $Str .= &Apache::lonhtmlcommon::MultipleSectionSelect(\@sections,
  301:                                                           \@selectedSections,
  302:                                                           'Statistics');
  303:     $Str .= '</td><td align="center">';
  304:     $Str .= &CreateColumnSelectionBox($doNotShow);
  305:     $Str .= '</td><td>'."\n";
  306:     $Str .= '<input type="submit" name="DefaultColumns" ';
  307:     $Str .= 'value="Default Column Display" />'."\n";
  308:     $Str .= '</td><td>'."\n";
  309:     $Str .= '<input type="submit" name="displaymode" ';
  310:     if (! exists($ENV{'form.displaymode'}) ||
  311:         lc($ENV{'form.displaymode'}) eq 'display with links') {
  312:         $Str .= 'value="Display without links" />';
  313:         # Set the current value, in case it is undefined
  314:         $ENV{'form.displaymode'} = 'Display with links';
  315:     } else {
  316:         $Str .= 'value="Display with links" />';
  317:     }
  318:     $Str .= "\n";
  319:     $Str .= '</td></tr></table>'."\n";
  320: 
  321:     return $Str;
  322: }
  323: #######################################################
  324: #######################################################
  325: 
  326: =pod
  327: 
  328: =item &CreateTableHeadings()
  329: 
  330: Create HTML for the columns of student data to show.
  331: Called by &BuildStudentAssessmentPage().  Calls
  332: &Apache::lonhtmlcommon::CreateHeadings().
  333: 
  334: Inputs:
  335: 
  336: =over 4
  337: 
  338: =item $cache The ubiquitous cache
  339: 
  340: =item $spacing A string of spaces
  341: 
  342: =item $infoKeys Array ref to names of keys to display from the cache 
  343: which describe students
  344: 
  345: =item $infoHeadings Array ref to headings of columns for student info
  346: 
  347: =item $sequenceKeys Array ref of names of keys to use to retrieve sequence
  348: data from the cache
  349: 
  350: =item $sequenceHeadings Array ref of names of sequences used for output.
  351: 
  352: =back
  353: 
  354: Returns: A string containing the HTML of the table headings.
  355: 
  356: =cut
  357: 
  358: #######################################################
  359: #######################################################
  360: sub CreateTableHeadings {
  361:     my($cache,$spacing,$infoKeys,$infoHeadings,$sequenceKeys,
  362:        $sequenceHeadings)=@_;
  363: 
  364: #    my $Str = '&nbsp&nbsp&nbsp&nbsp&nbsp';
  365:     my $Str = '';
  366:     $Str .= '<table border="0" cellpadding="0" cellspacing="0">'."\n";
  367:     $Str .= '<tr>'."\n";
  368:     $Str .= '<td><pre>     </pre></td>'."\n";
  369:     $Str .= &CreateColumnSelectors($infoHeadings, $sequenceHeadings,
  370:                                    $sequenceKeys);
  371:     $Str .= '<td></td></tr>'."\n";
  372: 
  373:     $Str .= '<tr>'."\n";
  374:     my $displayString = '';
  375:     $displayString .= '<td><pre>     </pre></td>'."\n";
  376:     $displayString .= '<td align="left"><pre><a href="/adm/statistics?';
  377:     $displayString .= 'sort=LINKDATA">DISPLAYDATA</a>FORMATTING';
  378:     $displayString .= $spacing.'</pre></td>'."\n";
  379:     $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
  380:                                                    $infoKeys,
  381:                                                    $infoHeadings,
  382:                                                    $displayString,
  383:                                                    'preformatted');
  384: 
  385:     $displayString  = '<td align="left"><pre>DISPLAYDATAFORMATTING'.$spacing;
  386:     $displayString .= '</pre></td>'."\n";
  387:     $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
  388:                                                    $sequenceKeys,
  389:                                                    $sequenceHeadings,
  390:                                                    $displayString,
  391:                                                    'preformatted');
  392: 
  393:     $Str .= '<td><pre>Total Solved/Total Problems</pre></td>';
  394:     $Str .= '</tr></table>'."\n";
  395: 
  396:     return $Str;
  397: }
  398: 
  399: #######################################################
  400: #######################################################
  401: 
  402: =pod
  403: 
  404: =item &StudentReport()
  405: 
  406: This is the workhorse subroutine - it handles formatting and display of a
  407: students performance data.  It processes one row of the chart.
  408: 
  409: Input: 
  410: 
  411: =over 4
  412: 
  413: =item $cache The ubiquitous cache
  414: 
  415: =item $name The name and domain of the current student in name:domain format
  416: 
  417: =item $spacing A string containing spaces.
  418: 
  419: =item $showSequences Array ref containing the sequences to display
  420: 
  421: =back
  422: 
  423: Output: $Str
  424: 
  425: $Str: Formatted string that is an entire row of the chart.  It is a
  426: concatenation of student information and student course information.
  427: 
  428: =cut
  429: 
  430: #######################################################
  431: #######################################################
  432: sub StudentReport {
  433:     my ($cache,$name,$spacing,$showSequences)=@_;
  434:     my ($username,$domain)=split(':',$name);
  435: 
  436:     my $Str = '';
  437:     if(defined($cache->{$name.':error'})) {
  438:         return $Str;
  439:     }
  440:     if($cache->{$name.':error'} =~ /course/) {
  441:         $Str .= '<b><font color="blue">No course data for student </font>';
  442:         $Str .= '<font color="red">'.$username.'.</font></b><br>';
  443:         return $Str;
  444:     }
  445: 
  446:     my $hasVersion = 'false';
  447:     my $hasFinalData = 'false';
  448:     foreach my $sequence (@$showSequences) {
  449:         my $hasData = 'false';
  450:         my $characterCount=0;
  451:         foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
  452:             my $problem = $cache->{$problemID.':problem'};
  453:             # All grades (except for versionless parts) are displayed as links
  454:             # to their submission record.  Loop through all the parts for the
  455:             # current problem in the correct order and prepare the output links
  456:             foreach(split(/\:/,$cache->{$sequence.':'.$problemID.
  457:                                         ':parts'})) {
  458:                 if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
  459:                    $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
  460:                    $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
  461:                     $Str .= ' ';
  462:                     $characterCount++;
  463:                     next;
  464:                 }
  465:                 $hasVersion = 'true';
  466:                 $hasData = 'true';
  467:                 if (lc($ENV{'form.displaymode'}) ne 'display without links') {
  468:                     $Str .= '<a href="/adm/grades?symb=';
  469:                     $Str .= &Apache::lonnet::escape($problem);
  470:                     $Str .= '&student='.$username.'&domain='.$domain;
  471:                     $Str .= '&command=submission">';
  472:                 }
  473:                 my $code = $cache->{$name.':'.$problemID.':'.$_.':code'};
  474:                 my $tries = $cache->{$name.':'.$problemID.':'.$_.':tries'};
  475:                 if($code eq '*' && $tries < 10 && $tries ne '') {
  476:                     $code = $tries;
  477:                 }
  478:                 $Str .= $code;
  479:                 if (lc($ENV{'form.displaymode'}) ne 'display without links') {
  480:                     $Str .= '</a>';
  481:                 }
  482:                 $characterCount++;
  483:             }
  484:         }
  485: 
  486:         # Output the number of correct answers for the current sequence.
  487:         # This part takes up 6 character slots, but is formated right
  488:         # justified.
  489:         my $spacesNeeded=$cache->{$sequence.':columnWidth'}-$characterCount;
  490:         $spacesNeeded -= 3;
  491:         $Str .= (' 'x$spacesNeeded);
  492: 
  493: #        my $outputProblemsCorrect = sprintf("%3d", $cache->{$name.':'.$sequence.
  494: #							    ':problemsCorrect'});
  495: 
  496: 	my $outputProblemsCorrect = sprintf("%2d/%2d", $cache->{$name.':'.$sequence.
  497:                                             ':problemsCorrect'},
  498:                                             $characterCount);
  499:         if($hasData eq 'true') {
  500:             $Str .= '<font color="#007700">'.$outputProblemsCorrect.'</font>';
  501:             $hasFinalData = 'true';
  502:         } else {
  503:             $Str .= '<font color="#007700">     </font>';
  504:         }
  505:         $Str .= $spacing;
  506:     }
  507: 
  508:     # Output the total correct problems over the total number of problems.
  509:     # I don't like this type of formatting, but it is a solution.  Need
  510:     # a way to dynamically determine the space requirements.
  511:     my $outputProblemsSolved = sprintf("%4d", $cache->{$name.':problemsSolved'});
  512:     my $outputTotalProblems  = sprintf("%4d", $cache->{$name.':totalProblems'});
  513:     if($hasFinalData eq 'true') {
  514:         $Str .= '<font color="#000088">'.$outputProblemsSolved.
  515: 	    ' / '.$outputTotalProblems.'</font>';
  516:     } else {
  517:         $Str .= '<font color="#000088">           </font>';
  518:     }
  519: 
  520:     if($hasVersion eq 'false') {
  521:         $Str = '<b><font color="blue">No course data.</font></b>';
  522:     }
  523: 
  524:     return $Str;
  525: }
  526: 
  527: #######################################################
  528: #######################################################
  529: 
  530: #######################################################
  531: #######################################################
  532: sub StudentAverageTotal {
  533:     my ($cache, $students, $sequenceKeys)=@_;
  534:     my $Str = "\n<b>Summary Tables:</b>\n";
  535:     my %Correct = ();
  536:     my $ProblemsSolved = 0;
  537:     my $TotalProblems = 0;
  538:     my $StudentCount = 0;
  539: 
  540:     foreach my $name (@$students) {
  541:         $StudentCount++;
  542:         foreach my $sequence (@$sequenceKeys) {
  543:             $Correct{$sequence} +=
  544: 	       $cache->{$name.':'.$sequence.':problemsCorrect'};
  545:         }
  546: 	$ProblemsSolved += $cache->{$name.':problemsSolved'};
  547:         $TotalProblems += $cache->{$name.':totalProblems'};
  548:     }
  549:     if ($StudentCount) { 
  550:         $ProblemsSolved = sprintf( "%.2f", 
  551:                              $ProblemsSolved/$StudentCount);
  552:         $TotalProblems /= $StudentCount;
  553:     } else {
  554:         $ProblemsSolved = 0;
  555:         $TotalProblems  = 0;
  556:     }
  557: 
  558:     $Str .= '<table border=2 cellspacing="1">'."\n";
  559:     $Str .= '<tr><td><b>Students Count</b></td><td><b>'.
  560:             $StudentCount.'</b></td></tr>'."\n";
  561:     $Str .= '<tr><td><b>Total Problems</b></td><td><b>'.
  562:             $TotalProblems.'</b></td></tr>'."\n";
  563:     $Str .= '<tr><td><b>Average Correct</b></td><td><b>'.
  564:             $ProblemsSolved.'</b></td></tr>'."\n";
  565:     $Str .= '</table>'."\n";
  566: 
  567:     $Str .= '<table border=2 cellspacing="1">'."\n";
  568:     $Str .= '<tr><th>Title</th><th>Total Problems</th>'.
  569:             '<th>Average Correct</th></tr>'."\n";
  570:     foreach my $S(@$sequenceKeys) {
  571:         my $title=$cache->{$S.':title'};
  572: 	#$Str .= $cache->{$S.':problems'};
  573: 	#my @problems=split(':', $cache->{$S.':problems'});
  574: 	#my $pCount=scalar @problems;
  575: 	my $pCount=MaxSeqPr($cache,@$students[0],$S);
  576:         my $crr;
  577: 	if ($StudentCount) {
  578:             $crr=sprintf( "%.2f", $Correct{$S}/$StudentCount );
  579:         } else {
  580:             $crr="0.00";
  581:         }
  582:         $Str .= '<tr><td>'.$title.
  583:                 '</td><td align=center>'.$pCount.
  584:                 '</td><td align=center>'.$crr.
  585:                 '</td></tr>'."\n";
  586:     }
  587: 
  588:     $Str .= '</table>'."\n";
  589: 
  590:     return $Str;
  591: }
  592: 
  593: #######################################################
  594: #######################################################
  595: 
  596: #######################################################
  597: #######################################################
  598: sub MaxSeqPr {
  599:     my ($cache, $name, $sequence)=@_;
  600:     my $prCount=0;
  601:     foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
  602:         my $problem = $cache->{$problemID.':problem'};
  603:         foreach(split(/\:/,$cache->{$sequence.':'.$problemID.':parts'})) {
  604:             if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
  605:                $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
  606:                $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
  607:                  $prCount++;
  608:                  next;
  609:             }
  610:             $prCount++;
  611:         }
  612:     }
  613:     return $prCount;
  614: }
  615: 
  616: #######################################################
  617: #######################################################
  618: 
  619: =pod
  620: 
  621: =item &CreateLegend()
  622: 
  623: This function returns a formatted string containing the legend for the
  624: chart.  The legend describes the symbols used to represent grades for
  625: problems.
  626: 
  627: =cut
  628: 
  629: #######################################################
  630: #######################################################
  631: sub CreateLegend {
  632:     my $Str = "<p><pre>".
  633:               "   1  correct by student in 1 try\n".
  634:               "   7  correct by student in 7 tries\n".
  635:               "   *  correct by student in more than 9 tries\n".
  636: 	      "   +  correct by hand grading or override\n".
  637:               "   -  incorrect by override\n".
  638: 	      "   .  incorrect attempted\n".
  639: 	      "   #  ungraded attempted\n".
  640:               "      not attempted (blank field)\n".
  641: 	      "   x  excused".
  642:               "</pre><p>";
  643:     return $Str;
  644: }
  645: 
  646: #######################################################
  647: #######################################################
  648: 
  649: =pod
  650: 
  651: =item &CreateColumnSelectionBox()
  652: 
  653: If there are columns not being displayed then this selection box is created
  654: with a list of those columns.  When selections are made and the page
  655: refreshed, the columns will be removed from this box and the column is
  656: put back in the chart.  If there is no columns to select, no row is added
  657: to the interface table.
  658: 
  659: =over 4
  660: Input: $CacheData, $headings
  661: 
  662: $CacheData: A pointer to a hash tied to the cached data
  663: 
  664: $headings:  An array of the names of the columns for the student information.
  665: They are used for displaying which columns are missing.
  666: 
  667: Output: $notThere
  668: 
  669: $notThere: The string contains one row of a table.  The first column has the
  670: name of the selection box.  The second contains the selection box
  671: which has a size of four.
  672: 
  673: =back
  674: 
  675: =cut
  676: 
  677: #######################################################
  678: #######################################################
  679: sub CreateColumnSelectionBox {
  680:     my ($doNotShow)=@_;
  681: 
  682:     my $notThere = '';
  683:     $notThere .= '<select name="ReselectColumns" size="4" ';
  684:     $notThere .= 'multiple="true">'."\n";
  685: 
  686:     for(my $index=0; $index<$doNotShow->{'count'}; $index++) {
  687:         my $name = $doNotShow->{$index.':name'};
  688:         $notThere .= '<option value="';
  689:         $notThere .= $doNotShow->{$index.':id'}.'">';
  690:         $notThere .= $name.'</option>'."\n";
  691:     }
  692: 
  693:     $notThere .= '</select>';
  694: 
  695:     return $notThere;
  696: }
  697: 
  698: #######################################################
  699: #######################################################
  700: 
  701: =pod
  702: 
  703: =item &CreateColumnSelectors()
  704: 
  705: This function generates the checkboxes above the column headings.  The
  706: column will be removed if the checkbox is unchecked.
  707: 
  708: =over 4
  709: 
  710: Input: $CacheData, $headings
  711: 
  712: $CacheData: A pointer to a hash tied to the cached data
  713: 
  714: $headings:  An array of the names of the columns for the student 
  715: information.  They are used to know what are the student information columns
  716: 
  717: Output: $present
  718: 
  719: $present: The string contains the first row of a table.  Each column contains
  720: a checkbox which is left justified.  Currently left justification is used
  721: for consistency of location over the column in which it presides.
  722: 
  723: =back
  724: 
  725: =cut
  726: 
  727: #######################################################
  728: #######################################################
  729: sub CreateColumnSelectors {
  730:     my ($infoHeadings, $sequenceHeadings, $sequenceKeys)=@_;
  731: 
  732:     my $present = '';
  733:     for(my $index=0; $index<(scalar @$infoHeadings); $index++) {
  734:         $present .= '<td align="left">';
  735:         $present .= '<input type="checkbox" checked="on" ';
  736:         $present .= 'name="HeadingColumn'.$infoHeadings->[$index].'" />';
  737:         $present .= '</td>'."\n";
  738:     }
  739: 
  740:     for(my $index=0; $index<(scalar @$sequenceHeadings); $index++) {
  741:         $present .= '<td align="left">';
  742:         $present .= '<input type="checkbox" checked="on" ';
  743:         $present .= 'name="SequenceColumn'.$sequenceKeys->[$index].'" />';
  744:         $present .= '</td>'."\n";
  745:     }
  746: 
  747:     return $present;
  748: }
  749: 
  750: #######################################################
  751: #######################################################
  752: 
  753: =pod
  754: 
  755: =back
  756: 
  757: =head1 HELPER FUNCTIONS
  758: 
  759: =over 4
  760: 
  761: =cut 
  762: 
  763: #######################################################
  764: #######################################################
  765: sub FindSelectedStudent {
  766:     my($cache, $selectedName, $students)=@_;
  767: 
  768:     if($selectedName eq 'All Students' ||
  769:        $selectedName eq 'No Student Selected') {
  770:         return $selectedName;
  771:     }
  772: 
  773:     for(my $index=0; $index<(scalar @$students); $index++) {
  774:         my $fullname = $cache->{$students->[$index].':fullname'};
  775:         if($fullname eq $selectedName) {
  776:             if($cache->{'StudentAssessmentMove'} eq 'next') {
  777:                 if($index == ((scalar @$students) - 1)) {
  778:                     $selectedName = $students->[0];
  779:                     return $selectedName;
  780:                 } else {
  781:                     $selectedName = $students->[$index+1];
  782:                     return $selectedName;
  783:                 }
  784:             } elsif($cache->{'StudentAssessmentMove'} eq 'previous') {
  785:                 if($index == 0) {
  786:                     $selectedName = $students->[-1];
  787:                     return $selectedName;
  788:                 } else {
  789:                     $selectedName = $students->[$index-1];
  790:                     return $selectedName;
  791:                 }
  792:             } else {
  793:                 $selectedName = $students->[$index];
  794:                 return $selectedName;
  795:             }
  796:             last;
  797:         }
  798:     }
  799: 
  800:     return 'No Student Selected';
  801: }
  802: #######################################################
  803: #######################################################
  804: 
  805: =pod
  806: 
  807: =item &ShouldShowColumn()
  808: 
  809: Determine if a specified column should be shown on the chart.
  810: 
  811: =over 4
  812: 
  813: Input: $cache, $test
  814: 
  815: $cache: A pointer to the hash tied to the cached data
  816: 
  817: $test: The form name of the column (heading.$headingIndex) or 
  818: (sequence.$sequenceIndex)
  819: 
  820: =back
  821: 
  822: =cut
  823: 
  824: #######################################################
  825: #######################################################
  826: sub ShouldShowColumns {
  827:     my ($cache,$headings,$cacheKey)=@_;
  828: 
  829:     my @infoKeys=();
  830:     my @infoHeadings=();
  831: 
  832:     my @sequenceKeys=();
  833:     my @sequenceHeadings=();
  834: 
  835:     my %doNotShow;
  836: 
  837:     my $index;
  838:     my $count = 0;
  839:     my $check = '';
  840:     for($index=0; $index < scalar @$headings; $index++) {
  841:         $check = 'HeadingColumn'.$headings->[$index];
  842:         if($cache->{'HeadingsFound'} =~ /$check/) {
  843:             push(@infoHeadings, $headings->[$index]);
  844:             push(@infoKeys, $cacheKey->[$index]);
  845:         } else {
  846:             $doNotShow{$count.':name'} = $headings->[$index];
  847:             $doNotShow{$count.':id'} = 'HeadingColumn'.$headings->[$index];
  848:             $count++;
  849:         }
  850:     }
  851: 
  852:     foreach my $sequence (split(/\:/,$cache->{'orderedSequences'})) {
  853:         $check = 'SequenceColumn'.$sequence;
  854:         if($cache->{'SequencesFound'} eq 'All Sequences' ||
  855:            $cache->{'SequencesFound'} =~ /$check/) {
  856:             push(@sequenceHeadings, $cache->{$sequence.':title'});
  857:             push(@sequenceKeys, $sequence);
  858:         } else {
  859:             $doNotShow{$count.':name'} = $cache->{$sequence.':title'};
  860:             $doNotShow{$count.':id'} = 'SequenceColumn'.$sequence;
  861:             $count++;
  862:         }
  863:     }
  864: 
  865:     $doNotShow{'count'} = $count;
  866: 
  867:     return (\@infoHeadings, \@infoKeys, \@sequenceHeadings,
  868:             \@sequenceKeys, \%doNotShow);
  869: }
  870: 1;
  871: 
  872: #######################################################
  873: #######################################################
  874: 
  875: =pod 
  876: 
  877: =back
  878: 
  879: =cut
  880: 
  881: #######################################################
  882: #######################################################
  883: 
  884: __END__

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