Annotation of loncom/interface/statistics/lonstudentassessment.pm, revision 1.28
1.1 stredwic 1: # The LearningOnline Network with CAPA
2: # (Publication Handler
3: #
1.28 ! matthew 4: # $Id: lonstudentassessment.pm,v 1.27 2003/01/13 01:34:11 minaeibi Exp $
1.1 stredwic 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
1.28 ! matthew 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: #######################################################
1.1 stredwic 50:
1.21 minaeibi 51: package Apache::lonstudentassessment;
1.1 stredwic 52:
53: use strict;
1.28 ! matthew 54: use Apache::lonstatistics;
1.1 stredwic 55: use Apache::lonhtmlcommon;
56: use Apache::loncoursedata;
1.28 ! matthew 57: use Apache::lonnet; # for logging porpoises
1.1 stredwic 58: use GDBM_File;
59:
1.28 ! matthew 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
1.4 stredwic 83:
1.28 ! matthew 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: #######################################################
1.1 stredwic 97: sub BuildStudentAssessmentPage {
1.2 stredwic 98: my ($cacheDB,$students,$courseID,$formName,$headings,$spacing,
99: $studentInformation,$r,$c)=@_;
1.1 stredwic 100: my %cache;
1.6 stredwic 101: unless(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
1.11 stredwic 102: $r->print('<html><body>Unable to tie database.</body></html>');
1.2 stredwic 103: return;
1.1 stredwic 104: }
1.3 stredwic 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: }
1.4 stredwic 129: my ($infoHeadings, $infoKeys, $sequenceHeadings, $sequenceKeys,
1.21 minaeibi 130: $doNotShow) =
1.4 stredwic 131: &ShouldShowColumns(\%cache, $headings, $studentInformation);
1.3 stredwic 132:
1.21 minaeibi 133: my $selectedName = &FindSelectedStudent(\%cache,
1.2 stredwic 134: $cache{'StudentAssessmentStudent'},
135: $students);
1.4 stredwic 136: $r->print(&CreateInterface(\%cache, $selectedName, $students, $formName,
137: $doNotShow));
1.7 stredwic 138: $r->rflush();
1.1 stredwic 139:
1.4 stredwic 140: my $Str = '';
1.1 stredwic 141: if($selectedName eq 'No Student Selected') {
1.4 stredwic 142: $Str .= '<h3><font color=blue>WARNING: ';
143: $Str .= 'Please select a student</font></h3>';
144: $r->print($Str);
1.2 stredwic 145: return;
1.1 stredwic 146: }
147:
1.2 stredwic 148: $r->print(&CreateTableHeadings(\%cache, $spacing, $infoKeys, $infoHeadings,
149: $sequenceKeys, $sequenceHeadings));
150: untie(%cache);
1.6 stredwic 151: if($c->aborted()) { return $Str; }
1.2 stredwic 152:
1.1 stredwic 153: my $selected=0;
1.24 minaeibi 154: my $Count = 0;
1.2 stredwic 155: $r->print('<pre>'."\n");
1.1 stredwic 156: foreach (@$students) {
1.8 stredwic 157: if($c->aborted()) { return $Str; }
1.17 minaeibi 158: next if ($_ ne $selectedName &&
1.1 stredwic 159: $selectedName ne 'All Students');
160: $selected = 1;
1.2 stredwic 161:
1.8 stredwic 162: my @who = ($_);
1.17 minaeibi 163: next if(&Apache::loncoursedata::DownloadStudentCourseData(\@who, 'true',
164: $cacheDB, 'true',
1.8 stredwic 165: 'false', $courseID,
166: $r, $c) ne 'OK');
1.6 stredwic 167: next if($c->aborted());
1.2 stredwic 168:
1.6 stredwic 169: if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
1.8 stredwic 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: }
1.24 minaeibi 186: $Count++;
187: my $out = '';
1.27 minaeibi 188: $out .= sprintf("%3d) ", $Count);
1.24 minaeibi 189: if($Count % 2) {
190: $out .= '<bgcolor="#FFFFFF">';
191: } else {
1.27 minaeibi 192: $out .= '<bgcolor="#505050">';
1.24 minaeibi 193: }
194: my $displayString = $out.'DISPLAYDATA'.$spacing;
195: $r->print(&Apache::lonhtmlcommon::FormatStudentInformation(
1.2 stredwic 196: \%cache, $_,
1.8 stredwic 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,
1.2 stredwic 218: $displayString,
219: 'preformatted'));
220: $r->print(&StudentReport(\%cache, $_, $spacing, $sequenceKeys));
221: $r->print("\n");
1.7 stredwic 222: $r->rflush();
1.1 stredwic 223: untie(%cache);
224: }
225: }
1.26 minaeibi 226: $r->print('</pre>'."\n");
1.1 stredwic 227: if($selected == 0) {
1.4 stredwic 228: $Str .= '<h3><font color=blue>WARNING: ';
1.26 minaeibi 229: $Str .= 'No Students enrolled OR Please select a student</font></h3>';
1.4 stredwic 230: $r->print($Str);
1.26 minaeibi 231: } else {
232: if(tie(%cache,'GDBM_File',$cacheDB,&GDBM_READER(),0640)) {
233: $r->print(&StudentAverageTotal(\%cache, $students, $sequenceKeys));
234: untie(%cache);
235: }
1.1 stredwic 236: }
1.2 stredwic 237: return;
238: }
1.28 ! matthew 239: #######################################################
! 240: #######################################################
! 241:
! 242: =pod
1.2 stredwic 243:
1.28 ! matthew 244: =item &CreateInterface()
1.21 minaeibi 245:
1.28 ! matthew 246: Called by &BuildStudentAssessmentPage to create the top part of the
! 247: page which displays the chart.
! 248:
! 249: Inputs:
! 250:
! 251: =over 4
1.2 stredwic 252:
1.28 ! matthew 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: #######################################################
1.2 stredwic 274: sub CreateInterface {
1.4 stredwic 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 .= '   '."\n";
1.17 minaeibi 283: $Str .= &Apache::lonhtmlcommon::StudentOptions($cache, $students,
1.21 minaeibi 284: $selectedName,
285: 'StudentAssessment',
1.2 stredwic 286: $formName);
1.4 stredwic 287: $Str .= "\n".'   '."\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";
1.3 stredwic 296:
1.4 stredwic 297: $Str .= '<tr><td align="center">'."\n";
1.3 stredwic 298: my @sections = split(':',$cache->{'sectionList'});
299: my @selectedSections = split(':',$cache->{'sectionsSelected'});
1.4 stredwic 300: $Str .= &Apache::lonhtmlcommon::MultipleSectionSelect(\@sections,
1.3 stredwic 301: \@selectedSections,
302: 'Statistics');
1.4 stredwic 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";
1.18 matthew 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
1.21 minaeibi 314: $ENV{'form.displaymode'} = 'Display with links';
1.18 matthew 315: } else {
316: $Str .= 'value="Display with links" />';
317: }
318: $Str .= "\n";
1.4 stredwic 319: $Str .= '</td></tr></table>'."\n";
1.2 stredwic 320:
1.4 stredwic 321: return $Str;
1.1 stredwic 322: }
1.28 ! matthew 323: #######################################################
! 324: #######################################################
1.1 stredwic 325:
1.28 ! matthew 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: #######################################################
1.2 stredwic 360: sub CreateTableHeadings {
361: my($cache,$spacing,$infoKeys,$infoHeadings,$sequenceKeys,
362: $sequenceHeadings)=@_;
363:
1.24 minaeibi 364: # my $Str = '     ';
1.2 stredwic 365: my $Str = '';
1.4 stredwic 366: $Str .= '<table border="0" cellpadding="0" cellspacing="0">'."\n";
367: $Str .= '<tr>'."\n";
1.27 minaeibi 368: $Str .= '<td><pre> </pre></td>'."\n";
1.4 stredwic 369: $Str .= &CreateColumnSelectors($infoHeadings, $sequenceHeadings,
370: $sequenceKeys);
371: $Str .= '<td></td></tr>'."\n";
1.2 stredwic 372:
1.4 stredwic 373: $Str .= '<tr>'."\n";
1.27 minaeibi 374: my $displayString = '';
375: $displayString .= '<td><pre> </pre></td>'."\n";
376: $displayString .= '<td align="left"><pre><a href="/adm/statistics?';
1.2 stredwic 377: $displayString .= 'sort=LINKDATA">DISPLAYDATA</a>FORMATTING';
378: $displayString .= $spacing.'</pre></td>'."\n";
1.17 minaeibi 379: $Str .= &Apache::lonhtmlcommon::CreateHeadings($cache,
1.2 stredwic 380: $infoKeys,
381: $infoHeadings,
382: $displayString,
383: 'preformatted');
384:
1.8 stredwic 385: $displayString = '<td align="left"><pre>DISPLAYDATAFORMATTING'.$spacing;
1.2 stredwic 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:
1.28 ! matthew 399: #######################################################
! 400: #######################################################
! 401:
1.2 stredwic 402: =pod
403:
1.28 ! matthew 404: =item &StudentReport()
1.2 stredwic 405:
1.28 ! matthew 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:
1.2 stredwic 410:
411: =over 4
412:
1.28 ! matthew 413: =item $cache The ubiquitous cache
! 414:
! 415: =item $name The name and domain of the current student in name:domain format
1.2 stredwic 416:
1.28 ! matthew 417: =item $spacing A string containing spaces.
1.2 stredwic 418:
1.28 ! matthew 419: =item $showSequences Array ref containing the sequences to display
1.2 stredwic 420:
1.28 ! matthew 421: =back
1.2 stredwic 422:
423: Output: $Str
424:
1.21 minaeibi 425: $Str: Formatted string that is an entire row of the chart. It is a
1.2 stredwic 426: concatenation of student information and student course information.
427:
428: =cut
1.1 stredwic 429:
1.28 ! matthew 430: #######################################################
! 431: #######################################################
1.1 stredwic 432: sub StudentReport {
1.2 stredwic 433: my ($cache,$name,$spacing,$showSequences)=@_;
434: my ($username,$domain)=split(':',$name);
1.1 stredwic 435:
436: my $Str = '';
1.8 stredwic 437: if(defined($cache->{$name.':error'})) {
1.10 stredwic 438: return $Str;
1.8 stredwic 439: }
1.1 stredwic 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:
1.10 stredwic 446: my $hasVersion = 'false';
447: my $hasFinalData = 'false';
1.2 stredwic 448: foreach my $sequence (@$showSequences) {
1.10 stredwic 449: my $hasData = 'false';
1.2 stredwic 450: my $characterCount=0;
1.1 stredwic 451: foreach my $problemID (split(':', $cache->{$sequence.':problems'})) {
452: my $problem = $cache->{$problemID.':problem'};
1.2 stredwic 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'})) {
1.9 stredwic 458: if($cache->{$name.':'.$problemID.':NoVersion'} eq 'true' ||
1.10 stredwic 459: $cache->{$name.':'.$problemID.':'.$_.':code'} eq ' ' ||
460: $cache->{$name.':'.$problemID.':'.$_.':code'} eq '') {
1.8 stredwic 461: $Str .= ' ';
1.10 stredwic 462: $characterCount++;
1.8 stredwic 463: next;
1.2 stredwic 464: }
1.10 stredwic 465: $hasVersion = 'true';
466: $hasData = 'true';
1.18 matthew 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;
1.21 minaeibi 471: $Str .= '&command=submission">';
1.18 matthew 472: }
1.8 stredwic 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;
1.2 stredwic 477: }
1.8 stredwic 478: $Str .= $code;
1.18 matthew 479: if (lc($ENV{'form.displaymode'}) ne 'display without links') {
480: $Str .= '</a>';
481: }
1.10 stredwic 482: $characterCount++;
1.2 stredwic 483: }
484: }
485:
486: # Output the number of correct answers for the current sequence.
1.17 minaeibi 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:
1.28 ! matthew 527: #######################################################
! 528: #######################################################
1.17 minaeibi 529:
1.28 ! matthew 530: #######################################################
! 531: #######################################################
1.17 minaeibi 532: sub StudentAverageTotal {
1.21 minaeibi 533: my ($cache, $students, $sequenceKeys)=@_;
1.23 minaeibi 534: my $Str = "\n<b>Summary Tables:</b>\n";
1.21 minaeibi 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) {
1.23 minaeibi 543: $Correct{$sequence} +=
544: $cache->{$name.':'.$sequence.':problemsCorrect'};
1.17 minaeibi 545: }
1.21 minaeibi 546: $ProblemsSolved += $cache->{$name.':problemsSolved'};
547: $TotalProblems += $cache->{$name.':totalProblems'};
1.1 stredwic 548: }
1.25 matthew 549: if ($StudentCount) {
1.27 minaeibi 550: $ProblemsSolved = sprintf( "%.2f",
551: $ProblemsSolved/$StudentCount);
1.25 matthew 552: $TotalProblems /= $StudentCount;
553: } else {
554: $ProblemsSolved = 0;
555: $TotalProblems = 0;
556: }
1.27 minaeibi 557:
1.24 minaeibi 558: $Str .= '<table border=2 cellspacing="1">'."\n";
1.23 minaeibi 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:
1.24 minaeibi 567: $Str .= '<table border=2 cellspacing="1">'."\n";
1.23 minaeibi 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'};
1.24 minaeibi 573: #my @problems=split(':', $cache->{$S.':problems'});
1.23 minaeibi 574: #my $pCount=scalar @problems;
575: my $pCount=MaxSeqPr($cache,@$students[0],$S);
1.25 matthew 576: my $crr;
577: if ($StudentCount) {
578: $crr=sprintf( "%.2f", $Correct{$S}/$StudentCount );
579: } else {
580: $crr="0.00";
581: }
1.23 minaeibi 582: $Str .= '<tr><td>'.$title.
583: '</td><td align=center>'.$pCount.
584: '</td><td align=center>'.$crr.
585: '</td></tr>'."\n";
1.10 stredwic 586: }
1.1 stredwic 587:
1.23 minaeibi 588: $Str .= '</table>'."\n";
589:
1.1 stredwic 590: return $Str;
591: }
1.23 minaeibi 592:
1.28 ! matthew 593: #######################################################
! 594: #######################################################
1.23 minaeibi 595:
1.28 ! matthew 596: #######################################################
! 597: #######################################################
1.23 minaeibi 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:
1.28 ! matthew 616: #######################################################
! 617: #######################################################
1.17 minaeibi 618:
1.2 stredwic 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:
1.28 ! matthew 629: #######################################################
! 630: #######################################################
1.2 stredwic 631: sub CreateLegend {
632: my $Str = "<p><pre>".
1.13 minaeibi 633: " 1 correct by student in 1 try\n".
634: " 7 correct by student in 7 tries\n".
1.12 minaeibi 635: " * correct by student in more than 9 tries\n".
1.20 minaeibi 636: " + correct by hand grading or override\n".
1.12 minaeibi 637: " - incorrect by override\n".
638: " . incorrect attempted\n".
639: " # ungraded attempted\n".
1.13 minaeibi 640: " not attempted (blank field)\n".
1.12 minaeibi 641: " x excused".
1.17 minaeibi 642: "</pre><p>";
1.2 stredwic 643: return $Str;
644: }
645:
1.28 ! matthew 646: #######################################################
! 647: #######################################################
! 648:
1.2 stredwic 649: =pod
650:
651: =item &CreateColumnSelectionBox()
652:
653: If there are columns not being displayed then this selection box is created
1.17 minaeibi 654: with a list of those columns. When selections are made and the page
1.2 stredwic 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:
1.17 minaeibi 664: $headings: An array of the names of the columns for the student information.
1.2 stredwic 665: They are used for displaying which columns are missing.
666:
667: Output: $notThere
668:
1.17 minaeibi 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
1.2 stredwic 671: which has a size of four.
672:
673: =back
674:
675: =cut
676:
1.28 ! matthew 677: #######################################################
! 678: #######################################################
1.2 stredwic 679: sub CreateColumnSelectionBox {
1.4 stredwic 680: my ($doNotShow)=@_;
1.2 stredwic 681:
1.4 stredwic 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'}.'">';
1.2 stredwic 690: $notThere .= $name.'</option>'."\n";
691: }
692:
1.4 stredwic 693: $notThere .= '</select>';
1.2 stredwic 694:
1.4 stredwic 695: return $notThere;
1.2 stredwic 696: }
697:
1.28 ! matthew 698: #######################################################
! 699: #######################################################
! 700:
1.2 stredwic 701: =pod
702:
703: =item &CreateColumnSelectors()
704:
1.17 minaeibi 705: This function generates the checkboxes above the column headings. The
1.2 stredwic 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:
1.28 ! matthew 727: #######################################################
! 728: #######################################################
1.2 stredwic 729: sub CreateColumnSelectors {
1.4 stredwic 730: my ($infoHeadings, $sequenceHeadings, $sequenceKeys)=@_;
1.2 stredwic 731:
1.4 stredwic 732: my $present = '';
733: for(my $index=0; $index<(scalar @$infoHeadings); $index++) {
1.2 stredwic 734: $present .= '<td align="left">';
735: $present .= '<input type="checkbox" checked="on" ';
1.4 stredwic 736: $present .= 'name="HeadingColumn'.$infoHeadings->[$index].'" />';
737: $present .= '</td>'."\n";
1.2 stredwic 738: }
739:
1.4 stredwic 740: for(my $index=0; $index<(scalar @$sequenceHeadings); $index++) {
1.2 stredwic 741: $present .= '<td align="left">';
742: $present .= '<input type="checkbox" checked="on" ';
1.4 stredwic 743: $present .= 'name="SequenceColumn'.$sequenceKeys->[$index].'" />';
744: $present .= '</td>'."\n";
1.2 stredwic 745: }
746:
1.4 stredwic 747: return $present;
1.2 stredwic 748: }
749:
1.28 ! matthew 750: #######################################################
! 751: #######################################################
! 752:
! 753: =pod
! 754:
! 755: =back
1.2 stredwic 756:
1.28 ! matthew 757: =head1 HELPER FUNCTIONS
1.2 stredwic 758:
1.28 ! matthew 759: =over 4
! 760:
! 761: =cut
! 762:
! 763: #######################################################
! 764: #######################################################
1.2 stredwic 765: sub FindSelectedStudent {
766: my($cache, $selectedName, $students)=@_;
1.3 stredwic 767:
1.17 minaeibi 768: if($selectedName eq 'All Students' ||
1.3 stredwic 769: $selectedName eq 'No Student Selected') {
770: return $selectedName;
771: }
772:
773: for(my $index=0; $index<(scalar @$students); $index++) {
1.2 stredwic 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];
1.3 stredwic 779: return $selectedName;
1.2 stredwic 780: } else {
781: $selectedName = $students->[$index+1];
1.3 stredwic 782: return $selectedName;
1.2 stredwic 783: }
784: } elsif($cache->{'StudentAssessmentMove'} eq 'previous') {
785: if($index == 0) {
786: $selectedName = $students->[-1];
1.3 stredwic 787: return $selectedName;
1.2 stredwic 788: } else {
789: $selectedName = $students->[$index-1];
1.3 stredwic 790: return $selectedName;
1.2 stredwic 791: }
792: } else {
793: $selectedName = $students->[$index];
1.3 stredwic 794: return $selectedName;
1.2 stredwic 795: }
796: last;
797: }
798: }
799:
1.3 stredwic 800: return 'No Student Selected';
1.2 stredwic 801: }
1.28 ! matthew 802: #######################################################
! 803: #######################################################
1.2 stredwic 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:
1.28 ! matthew 824: #######################################################
! 825: #######################################################
1.2 stredwic 826: sub ShouldShowColumns {
827: my ($cache,$headings,$cacheKey)=@_;
828:
829: my @infoKeys=();
830: my @infoHeadings=();
831:
832: my @sequenceKeys=();
833: my @sequenceHeadings=();
834:
1.4 stredwic 835: my %doNotShow;
836:
1.2 stredwic 837: my $index;
1.4 stredwic 838: my $count = 0;
839: my $check = '';
1.2 stredwic 840: for($index=0; $index < scalar @$headings; $index++) {
1.4 stredwic 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: }
1.2 stredwic 850: }
851:
852: foreach my $sequence (split(/\:/,$cache->{'orderedSequences'})) {
1.4 stredwic 853: $check = 'SequenceColumn'.$sequence;
1.21 minaeibi 854: if($cache->{'SequencesFound'} eq 'All Sequences' ||
1.4 stredwic 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: }
1.2 stredwic 863: }
864:
1.4 stredwic 865: $doNotShow{'count'} = $count;
1.2 stredwic 866:
1.21 minaeibi 867: return (\@infoHeadings, \@infoKeys, \@sequenceHeadings,
1.4 stredwic 868: \@sequenceKeys, \%doNotShow);
1.2 stredwic 869: }
1.28 ! matthew 870: 1;
! 871:
! 872: #######################################################
! 873: #######################################################
1.2 stredwic 874:
1.28 ! matthew 875: =pod
! 876:
! 877: =back
! 878:
! 879: =cut
! 880:
! 881: #######################################################
! 882: #######################################################
1.2 stredwic 883:
1.1 stredwic 884: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>