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