--- loncom/interface/Attic/lonchart.pm 2002/07/02 15:13:06 1.50
+++ loncom/interface/Attic/lonchart.pm 2002/07/09 15:43:49 1.59
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# (Publication Handler
#
-# $Id: lonchart.pm,v 1.50 2002/07/02 15:13:06 stredwic Exp $
+# $Id: lonchart.pm,v 1.59 2002/07/09 15:43:49 stredwic Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -46,24 +46,113 @@
#
###
+=pod
+
+=head1 NAME
+
+lonchart
+
+=head1 SYNOPSIS
+
+Quick display of students grades for a course in a compressed table format.
+
+=head1 DESCRIPTION
+
+This module process all student grades for a course and turns them into a
+table like structure.
+
+This is part of the LearningOnline Network with CAPA project
+described at http://www.lon-capa.org
+
+lonchart presents the user with a condensed view all a course's data. The
+class title, the number of students, and the date for the last update of the
+displayed data. There is also a legend that describes the chart values.
+
+For each valid grade for a student is linked with a submission record for that
+problem. The ability to add and remove columns of data from the chart was
+added for reducing the burden of having to scroll through large quantities
+of data. The interface also allows for sorting of students by username,
+last name, and section number of class. Active and expired students are
+also available.
+
+The interface is controlled by three primary buttons: Recalculate Chart,
+Refresh Chart, and Reset Selections. Recalculate Chart will update
+the chart to the most recent data and keep the display settings for the chart
+the same. Refresh Chart is used to redisplay the chart after selecting
+different output formatting. Reset Selections is used to set the chart
+display options back to default values.
+
+=head1 CODE LAYOUT DESCRIPTION
+
+The code is broken down into three components: formatting data for printing,
+helper functions, and the central processing functions. The module is broken
+into chunks for each component.
+
+=head1 PACKAGES USED
+
+ Apache::Constants qw(:common :http)
+ Apache::lonnet()
+ Apache::loncommon()
+ HTML::TokeParser
+ GDBM_File
+
+=cut
+
package Apache::lonchart;
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet();
use Apache::loncommon();
+use Apache::loncoursedata();
use HTML::TokeParser;
use GDBM_File;
-my $jr;
+#my $jr;
+
+=pod
+
+=head1 FORMAT DATA FOR PRINTING
+
+=cut
+
# ----- FORMAT PRINT DATA ----------------------------------------------
+=pod
+
+=item &FormatStudentInformation()
+
+This function produces a formatted string of the student's information:
+username, domain, section, full name, and PID.
+
+=over 4
+
+Input: $cache, $name, $studentInformation, $spacePadding
+
+$cache: This is a pointer to a hash that is tied to the cached data
+
+$name: The name and domain of the current student in name:domain format
+
+$studentInformation: A pointer to an array holding the names used to
+
+remove data from the hash. They represent the name of the data to be removed.
+
+$spacePadding: Extra spaces that represent the space between columns
+
+Output: $Str
+
+$Str: Formatted string.
+
+=back
+
+=cut
+
sub FormatStudentInformation {
- my ($cache,$name,$studentInformation,$reselected,$spacePadding)=@_;
+ my ($cache,$name,$studentInformation,$spacePadding)=@_;
my $Str='';
for(my $index=0; $index<(scalar @$studentInformation); $index++) {
- if(!&ShouldShowColumn($reselected, 'heading', $index)) {
+ if(!&ShouldShowColumn($cache, 'ChartHeading'.$index)) {
next;
}
my $data=$cache->{$name.':'.$studentInformation->[$index]};
@@ -79,8 +168,42 @@ sub FormatStudentInformation {
return $Str;
}
+=pod
+
+=item &FormatStudentData()
+
+First, FormatStudentInformation is called and prefixes the course information.
+This function produces a formatted string of the student's course information.
+Each column of data represents all the problems for a given sequence. For
+valid grade data, a link is created for that problem to a submission record
+for that problem.
+
+=over 4
+
+Input: $name, $studentInformation, $spacePadding, $ChartDB
+
+$name: The name and domain of the current student in name:domain format
+
+$studentInformation: A pointer to an array holding the names used to
+remove data from the hash. They represent
+the name of the data to be removed.
+
+$spacePadding: Extra spaces that represent the space between columns
+
+$ChartDB: The name of the cached data database which will be tied to that
+database.
+
+Output: $Str
+
+$Str: Formatted string that is an entire row of the chart. It is a
+concatenation of student information and student course information.
+
+=back
+
+=cut
+
sub FormatStudentData {
- my ($reselected,$name,$coid,$studentInformation,$spacePadding,$ChartDB)=@_;
+ my ($name,$studentInformation,$spacePadding,$ChartDB)=@_;
my ($sname,$sdom) = split(/\:/,$name);
my $Str;
my %CacheData;
@@ -91,7 +214,7 @@ sub FormatStudentData {
# Handle Student information ------------------------------------------
# Handle user data
$Str=&FormatStudentInformation(\%CacheData, $name, $studentInformation,
- $reselected, $spacePadding);
+ $spacePadding);
# Handle errors
if($CacheData{$name.':error'} =~ /environment/) {
@@ -113,7 +236,7 @@ sub FormatStudentData {
my $problemsSolved = 0;
my $numberOfParts = 0;
foreach my $sequence (split(/\:/,$CacheData{'orderedSequences'})) {
- if(!&ShouldShowColumn($reselected, 'sequence', $sequence)) {
+ if(!&ShouldShowColumn(\%CacheData, 'ChartSequence'.$sequence)) {
next;
}
@@ -122,6 +245,8 @@ sub FormatStudentData {
my $problem = $CacheData{$problemID.':problem'};
my $LatestVersion = $CacheData{$name.":version:$problem"};
+ # Output blanks for all the parts of this problem if there
+ # is no version information about the current problem.
if(!$LatestVersion) {
foreach my $part (split(/\:/,$CacheData{$sequence.':'.
$problemID.
@@ -134,13 +259,19 @@ sub FormatStudentData {
}
my %partData=undef;
- #initialize data, displays skips correctly
+ # Initialize part data, display skips correctly
+ # Skip refers to when a student made no submissions on that
+ # part/problem.
foreach my $part (split(/\:/,$CacheData{$sequence.':'.
$problemID.
':parts'})) {
$partData{$part.':tries'}=0;
$partData{$part.':code'}=' ';
}
+
+ # Looping through all the versions of each part, starting with the
+ # oldest version. Basically, it gets the most recent
+ # set of grade data for each part.
for(my $Version=1; $Version<=$LatestVersion; $Version++) {
foreach my $part (split(/\:/,$CacheData{$sequence.':'.
$problemID.
@@ -148,6 +279,7 @@ sub FormatStudentData {
if(!defined($CacheData{$name.":$Version:$problem".
":resource.$part.solved"})) {
+ # No grade for this submission, so skip
next;
}
@@ -171,6 +303,9 @@ sub FormatStudentData {
}
}
+ # All grades (except for versionless parts) are displayed as links
+ # to their submission record. Loop through all the parts for the
+ # current problem in the correct order and prepare the output links
$Str.='';
@@ -196,6 +331,9 @@ sub FormatStudentData {
$Str.='';
}
+ # Output the number of correct answers for the current sequence.
+ # This part takes up 6 character slots, but is formated right
+ # justified.
my $spacesNeeded=$CacheData{$sequence.':columnWidth'}-$characterCount;
$spacesNeeded -= 3;
$Str .= (' 'x$spacesNeeded);
@@ -208,22 +346,55 @@ sub FormatStudentData {
$Str .= $spacePadding;
}
- $Str .= ''.$problemsSolved.
- ' / '.$totalProblems.'
';
+ # Output the total correct problems over the total number of problems.
+ # I don't like this type of formatting, but it is a solution. Need
+ # a way to dynamically determine the space requirements.
+ my $outputProblemsSolved = sprintf( "%4d", $problemsSolved );
+ my $outputTotalProblems = sprintf( "%4d", $totalProblems );
+ $Str .= ''.$outputProblemsSolved.
+ ' / '.$outputTotalProblems.'
';
untie(%CacheData);
return $Str;
}
+=pod
+
+=item &CreateTableHeadings()
+
+This function generates the column headings for the chart.
+
+=over 4
+
+Inputs: $CacheData, $studentInformation, $headings, $spacePadding
+
+$CacheData: pointer to a hash tied to the cached data database
+
+$studentInformation: a pointer to an array containing the names of the data
+held in a column and is used as part of a key into $CacheData
+
+$headings: The names of the headings for the student information
+
+$spacePadding: The spaces to go between columns
+
+Output: $Str
+
+$Str: A formatted string of the table column headings.
+
+=back
+
+=cut
+
sub CreateTableHeadings {
- my ($CacheData,$studentInformation,$headings,$reselected,$spacePadding)=@_;
- my $Str='
'; + my ($CacheData,$studentInformation,$headings,$spacePadding)=@_; + my $Str=''; for(my $index=0; $index<(scalar @$headings); $index++) { - if(!&ShouldShowColumn($reselected, 'heading', $index)) { + if(!&ShouldShowColumn($CacheData, 'ChartHeading'.$index)) { next; } + $Str .= ' '; return $Str; } +=pod + +=item &CreateColumnSelectionBox() + +If there are columns not being displayed then this selection box is created +with a list of those columns. When selections are made and the page +refreshed, the columns will be removed from this box and the column is +put back in the chart. If there is no columns to select, no row is added +to the interface table. + +=over 4 +Input: $CacheData, $headings + + +$CacheData: A pointer to a hash tied to the cached data + +$headings: An array of the names of the columns for the student information. +They are used for displaying which columns are missing. + +Output: $notThere + +$notThere: The string contains one row of a table. The first column has the +name of the selection box. The second contains the selection box +which has a size of four. + +=back + +=cut + sub CreateColumnSelectionBox { - my ($CacheData,$studentInformation,$headings,$reselected,$spacePadding)=@_; + my ($CacheData,$headings)=@_; my $missing=0; my $notThere=''; } foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) { - if(!&ShouldShowColumn($reselected, 'sequence', $sequence)) { + if(!&ShouldShowColumn($CacheData, 'ChartSequence'.$sequence)) { next; } + $Str .= ' '; my $data=$$headings[$index]; $Str .= $data; @@ -232,13 +403,15 @@ sub CreateTableHeadings { $Str .= (' 'x($CacheData->{$$studentInformation[$index].'Length'}- $length)); $Str .= $spacePadding; + $Str .= ''; } - $Str .= 'Total Solved/Total Problems'; - $Str .= ''; + $Str .= ' '; my $name = $CacheData->{$sequence.':title'}; $Str .= $name; my @titleLength=split(//,$CacheData->{$sequence.':title'}); @@ -246,39 +419,69 @@ sub CreateTableHeadings { (scalar @titleLength); $Str .= (' 'x$leftover); $Str .= $spacePadding; + $Str .= ''; + $Str .= ' Total Solved/Total Problems'; } +=pod + +=item &CreateColumnSelectors() + +This function generates the checkboxes above the column headings. The +column will be removed if the checkbox is unchecked. + +=over 4 + +Input: $CacheData, $headings + +$CacheData: A pointer to a hash tied to the cached data + +$headings: An array of the names of the columns for the student +information. They are used to know what are the student information columns + +Output: $present + +$present: The string contains the first row of a table. Each column contains +a checkbox which is left justified. Currently left justification is used +for consistency of location over the column in which it presides. + +=back + +=cut + sub CreateColumnSelectors { - my ($CacheData,$studentInformation,$headings,$reselected,$spacePadding)=@_; + my ($CacheData,$headings)=@_; my $found=0; my ($name, $length, $position); - my $present=' Select column to view:'; my $name; $notThere .= ' '; - $notThere .= ' '; + + my $present = ''; for(my $index=0; $index<(scalar @$headings); $index++) { - if(!&ShouldShowColumn($reselected, 'heading', $index)) { + if(!&ShouldShowColumn($CacheData, 'ChartHeading'.$index)) { next; } - $name = $headings->[$index]; - $length=$CacheData->{$$studentInformation[$index].'Length'}; - $position=int($length/2); - $present .= (' 'x($position)); + $present .= ' '."\n";; } +=pod + +=item &CreateForm() + +The interface for this module consists primarily of the controls in this +function. The student status selection (active, expired, any) is set here. +The sort buttons: username, last name, and section are set here. The +other buttons are Recalculate Chart, Refresh Chart, and Reset Selections. +These controls are in a table to clean up the interface. + +=over 4 + +Input: $CacheData + +$CacheData is a hash pointer to tied database for cached data. + +Output: $Ptr + +$Ptr is a string containing all the html for the above mentioned buttons. + +=back + +=cut + sub CreateForm { + my ($CacheData)=@_; my $OpSel1=''; my $OpSel2=''; my $OpSel3=''; - my $Status = $ENV{'form.status'}; + my $Status = $CacheData->{'form.ChartStatus'}; if ( $Status eq 'Any' ) { $OpSel3='selected'; } elsif ($Status eq 'Expired' ) { $OpSel2 = 'selected'; } else { $OpSel1 = 'selected'; } - my $Ptr .= ''; $present .= ''; - $position+=2; - $present .= (' 'x($length-$position)); - $present .= $spacePadding; + $present .= 'name="ChartHeading'.$index.'" />'; + $present .= ' '; $found++; } foreach my $sequence (split(/\:/,$CacheData->{'orderedSequences'})) { - if(!&ShouldShowColumn($reselected, 'sequence', $sequence)) { + if(!&ShouldShowColumn($CacheData, 'ChartSequence'.$sequence)) { next; } - $name = $CacheData->{$sequence.':title'}; - $length=$CacheData->{$sequence.':columnWidth'}; - $position=int($length/2); - $present .= (' 'x($position)); + $present .= ''; $present .= ''; - $position+=2; - $present .= (' 'x($length-$position)); - $present .= $spacePadding; + $present .= 'name="ChartSequence'.$sequence.'" />'; + $present .= ' '; $found++; } - if($found) { - $present .= ''; - $present = $present; - } else { + if(!$found) { $present = ''; } - return $present.''."\n";; + return $present.'