--- loncom/interface/lonstatistics.pm 2003/02/25 20:47:47 1.60 +++ loncom/interface/lonstatistics.pm 2003/02/28 20:50:33 1.61 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: lonstatistics.pm,v 1.60 2003/02/25 20:47:47 matthew Exp $ +# $Id: lonstatistics.pm,v 1.61 2003/02/28 20:50:33 matthew Exp $ # # Copyright Michigan State University Board of Trustees # @@ -61,20 +61,30 @@ package Apache::lonstatistics; use strict; use Apache::Constants qw(:common :http); +use vars qw( + @FullClasslist + @Students + @Sections + @SelectedSections + %StudentData + @StudentDataOrder + @SelectedStudentData + $top_map + @Sequences + @SelectedMaps + @Assessments); + use Apache::lonnet(); use Apache::lonhomework; use Apache::loncommon; use Apache::loncoursedata; use Apache::lonhtmlcommon; -use Apache::lonproblemanalysis; -use Apache::lonproblemstatistics; -use Apache::lonstudentassessment; +use Apache::lonproblemanalysis(); +use Apache::lonproblemstatistics(); +use Apache::lonstudentassessment(); use Apache::lonpercentage; use GDBM_File; -use vars qw/@FullClasslist @Students @Sections @SelectedSections - $curr_student $prev_student $next_student - $top_map @Sequences @Assessments /; ####################################################### ####################################################### @@ -104,10 +114,6 @@ use vars qw/@FullClasslist @Students @Se # # Classlist variables # -my @FullClasslist; -my @Students; -my @Sections; -my @SelectedSections; my $curr_student; my $prev_student; my $next_student; @@ -131,6 +137,12 @@ undef the following package variables: =item @SelectedSections +=item %StudentData + +=item @StudentDataOrder + +=item @SelectedStudentData + =item $curr_student =item $prev_student @@ -148,6 +160,8 @@ sub clear_classlist_variables { undef(@Students); undef(@Sections); undef(@SelectedSections); + undef(%StudentData); + undef(@SelectedStudentData); undef($curr_student); undef($prev_student); undef($next_student); @@ -173,6 +187,10 @@ the following package variables: =item @SelectedSections +=item %StudentData + +=item @SelectedStudentData + =item $curr_student =item $prev_student @@ -201,26 +219,42 @@ sub PrepareClasslist { $cdom,$cnum); if (exists($ENV{'form.Section'})) { if (ref($ENV{'form.Section'})) { - @SelectedSections = @$ENV{'form.Section'}; - # Remove the empty sections - for (my $i=0; $i<=$#SelectedSections; $i++) { - if ($SelectedSections[$i] =~ /^\s*$/) { - splice(@SelectedSections,$i,1); - } - } - } else { - if ($ENV{'form.Section'} !~ /^\s*$/) { - @SelectedSections = ($ENV{'form.Section'}); - } + @SelectedSections = @{$ENV{'form.Section'}}; + } elsif ($ENV{'form.Section'} !~ /^\s*$/) { + @SelectedSections = ($ENV{'form.Section'}); + } + } + @SelectedSections = ('all') if (! @SelectedSections); + foreach (@SelectedSections) { + if ($_ eq 'all') { + @SelectedSections = ('all'); } } - @SelectedSections = ('any') if (! @SelectedSections); + # + # Set up %StudentData + @StudentDataOrder = qw/fullname username domain id section status/; + foreach my $field (@StudentDataOrder) { + $StudentData{$field}->{'title'} = $field; + $StudentData{$field}->{'base_width'} = + scalar (my @Tmp = split(//,$field)); + $StudentData{$field}->{'width'} = + $StudentData{$field}->{'base_width'}; + } + # # Process the classlist while (my ($student,$student_data) = each (%$classlist)) { my $studenthash = (); for (my $i=0; $i< scalar(@$field_names);$i++) { - $studenthash->{$field_names->[$i]}=$student_data->[$i]; + my $field = $field_names->[$i]; + # Store the data + $studenthash->{$field}=$student_data->[$i]; + # Keep track of the width of the fields + next if (! exists($StudentData{$field})); + my $length = scalar(my @Tmp1 = split(//,$student_data->[$i])); + if ($StudentData{$field}->{'width'} < $length) { + $StudentData{$field}->{'width'} = $length; + } } push (@FullClasslist,$studenthash); # @@ -234,7 +268,7 @@ sub PrepareClasslist { # # Only put in the list those students we are interested in foreach my $sect (@SelectedSections) { - if (($sect eq 'any') || ($section eq $sect)) { + if (($sect eq 'all') || ($section eq $sect)) { push (@Students,$studenthash); last; } @@ -243,13 +277,13 @@ sub PrepareClasslist { # # Put the consolidated section data in the right place @Sections = sort {$a cmp $b} keys(%Sections); + unshift(@Sections,'all'); # Put 'all' at the front of the list # # Sort the Students my $sortby = 'fullname'; $sortby = $ENV{'form.sort'} if (exists($ENV{'form.sort'})); my @TmpStudents = sort { $a->{$sortby} cmp $b->{$sortby} || $a->{'fullname'} cmp $b->{'fullname'} } @Students; - @Students = @TmpStudents; # # Now deal with that current student thing.... @@ -274,16 +308,91 @@ sub PrepareClasslist { $next_student = $Students[$i+1]; } } + # + if (exists($ENV{'form.StudentData'})) { + if (ref($ENV{'form.StudentData'}) eq 'ARRAY') { + @SelectedStudentData = @{$ENV{'form.StudentData'}}; + } else { + @SelectedStudentData = ($ENV{'form.StudentData'}); + } + } else { + @SelectedStudentData = ('fullname'); + } + foreach (@SelectedStudentData) { + if ($_ eq 'all') { + @SelectedStudentData = ('all'); + last; + } + } + # + return; } ####################################################### ####################################################### -# -# Course Sequences variables -# -my $top_map; -my @Sequences; -my @Assessments; + +=pod + +=item ¤t_student() + +Returns a pointer to a hash containing data about the currently +selected student. + +=cut + +####################################################### +####################################################### +sub current_student { + if (defined($curr_student)) { + return $curr_student; + } else { + return 'All Students'; + } +} + +####################################################### +####################################################### + +=pod + +=item &previous_student() + +Returns a pointer to a hash containing data about the student prior +in the list of students. Or something. + +=cut + +####################################################### +####################################################### +sub previous_student { + if (defined($prev_student)) { + return $prev_student; + } else { + return 'No Student Selected'; + } +} + +####################################################### +####################################################### + +=pod + +=item &next_student() + +Returns a pointer to a hash containing data about the next student +to be viewed. + +=cut + +####################################################### +####################################################### +sub next_student { + if (defined($next_student)) { + return $next_student; + } else { + return 'No Student Selected'; + } +} ####################################################### ####################################################### @@ -307,6 +416,32 @@ sub clear_sequence_variables { =pod +=item &SetSelectedMaps($elementname) + +Sets the @SelectedMaps array from $ENV{'form.'.$elementname}; + +=cut + +####################################################### +####################################################### +sub SetSelectedMaps { + my $elementname = shift; + if (exists($ENV{'form.'.$elementname})) { + if (ref($ENV{'form.'.$elementname})) { + @SelectedMaps = @{$ENV{'form.'.$elementname}}; + } else { + @SelectedMaps = ($ENV{'form.'.$elementname}); + } + } else { + @SelectedMaps = ('all'); + } +} + +####################################################### +####################################################### + +=pod + =item &PrepareCourseData($r) =cut @@ -316,7 +451,8 @@ sub clear_sequence_variables { sub PrepareCourseData { my ($r) = @_; &clear_sequence_variables(); - my ($top,$sequences,$assessments) = &Apache::loncoursedata::get_sequence_assessment_data(); + my ($top,$sequences,$assessments) = + &Apache::loncoursedata::get_sequence_assessment_data(); if (! defined($top) || ! ref($top)) { # There has been an error, better report it &Apache::lonnet::logthis('top is undefined'); @@ -324,29 +460,148 @@ sub PrepareCourseData { } $top_map = $top if (ref($top)); @Sequences = @{$sequences} if (ref($sequences) eq 'ARRAY'); - @Assessments = @{$assessments} if (ref($assessments) eq 'HASH'); + @Assessments = @{$assessments} if (ref($assessments) eq 'ARRAY'); + # + # Compute column widths + foreach my $seq (@Sequences) { + my $name_length = scalar(my @Tmp1 = split(//,$seq->{'title'})); + my $num_parts = $seq->{'num_assess_parts'}; + # + # The number of columns needed for the summation text: + # " 1/5" = 1+3 columns, " 10/99" = 1+5 columns + my $sum_length = 1+1+2*(scalar(my @Tmp2 = split(//,$num_parts))); + my $num_col = $num_parts+$sum_length; + if ($num_col < $name_length) { + $num_col = $name_length; + } + $seq->{'base_width'} = $name_length; + $seq->{'width'} = $num_col; + } + return; +} + +####################################################### +####################################################### =pod - ## - ## Debugging code - ## - foreach my $s (@Sequences) { - next if ($s->{'title'} ne 'Bioenergetics: Enzyme Regulation'); - &Apache::lonnet::logthis('-----------------------------------'); - &Apache::lonnet::logthis('title = '.$s->{'title'}); - &Apache::lonnet::logthis('symb = '.$s->{'symb'}); - &Apache::lonnet::logthis('num_assess = '.$s->{'num_assess'}); - foreach my $a (@{$s->{'contents'}}) { - &Apache::lonnet::logthis(' --------------------------------'); - &Apache::lonnet::logthis(' title = '.$a->{'title'}); - &Apache::lonnet::logthis(' symb = '.$a->{'symb'}); +=item &log_sequence($sequence,$recursive,$padding) + +Write data about the sequence to a logfile. If $recursive is not +undef the data is written recursively. $padding is used for recursive +calls. + +=cut + +####################################################### +####################################################### +sub log_sequence { + my ($seq,$recursive,$padding) = @_; + $padding = '' if (! defined($padding)); + if (ref($seq) ne 'HASH') { + &Apache::lonnet::logthis('log_sequence passed bad sequnce'); + return; + } + &Apache::lonnet::logthis($padding.'sequence '.$seq->{'title'}); + while (my($key,$value) = each(%$seq)) { + next if ($key eq 'contents'); + if (ref($value) eq 'ARRAY') { + for (my $i=0;$i< scalar(@$value);$i++) { + &Apache::lonnet::logthis($padding.$key.'['.$i.']='. + $value->[$i]); + } + } else { + &Apache::lonnet::logthis($padding.$key.'='.$value); + } + } + if (defined($recursive)) { + &Apache::lonnet::logthis($padding.'-'x20); + &Apache::lonnet::logthis($padding.'contains:'); + foreach my $item (@{$seq->{'contents'}}) { + if ($item->{'type'} eq 'container') { + &log_sequence($item,$recursive,$padding.' '); + } else { + &Apache::lonnet::logthis($padding.'title = '.$item->{'title'}); + while (my($key,$value) = each(%$item)) { + next if ($key eq 'title'); + if (ref($value) eq 'ARRAY') { + for (my $i=0;$i< scalar(@$value);$i++) { + &Apache::lonnet::logthis($padding.$key.'['.$i.']='. + $value->[$i]); + } + } else { + &Apache::lonnet::logthis($padding.$key.'='.$value); + } + } + } } + &Apache::lonnet::logthis($padding.'end contents of '.$seq->{'title'}); + &Apache::lonnet::logthis($padding.'-'x20); } + return; +} + +############################################## +############################################## + +=pod + +=item &StudentDataSelect($elementname,$status,$numvisible,$selected) + +Returns html for a selection box allowing the user to choose one (or more) +of the fields of student data available (fullname, username, id, section, etc) + +=over 4 + +=item $elementname The name of the HTML form element + +=item $status 'multiple' or 'single' selection box + +=item $numvisible The number of options to be visible + +=back =cut - return; +############################################## +############################################## +sub StudentDataSelect { + my ($elementname,$status,$numvisible)=@_; + if ($numvisible < 1) { + return; + } + # + # Build the form element + my $Str = "\n"; + $Str .= '\n"; + return $Str; } ############################################## @@ -354,7 +609,7 @@ sub PrepareCourseData { =pod -=item &MapSelect($elementname,$status,$numvisible,$selected,$restriction) +=item &MapSelect($elementname,$status,$numvisible,$restriction) Returns html for a selection box allowing the user to choose one (or more) of the sequences in the course. The values of the sequences are the symbs. @@ -368,10 +623,6 @@ If the top sequence is selected, the val =item $numvisible The number of options to be visible -=item $selected Array ref to the names of the already selected maps. -If undef, $ENV{'form.'.$elementname} is used. -If $ENV{'form.'.$elementname} is also empty, none will be selected. - =item $restriction Code reference to subroutine which returns true or false. The code must expect a reference to a sequence data structure. @@ -382,30 +633,13 @@ false. The code must expect a reference ############################################## ############################################## sub MapSelect { - my ($elementname,$status,$numvisible,$selected,$restriction)=@_; + my ($elementname,$status,$numvisible,$restriction)=@_; if ($numvisible < 1) { return; } # # Set up array of selected items - my @Selected; - if (! defined($selected)) { - if (exists($ENV{'form.'.$elementname})) { - if (ref($ENV{'form.'.$elementname})) { - @Selected = @$ENV{'form.'.$elementname}; - } else { - @Selected = ($ENV{'form.'.$elementname}); - } - } else { - @Selected = (); - } - } else { - if (ref($selected)) { - @Selected = @$selected; - } else { - @Selected = ($selected); - } - } + &SetSelectedMaps($elementname); # # Set up the restriction call if (! defined($restriction)) { @@ -420,23 +654,40 @@ sub MapSelect { } $Str .= 'size="'.$numvisible.'" >'."\n"; # + # Deal with 'all' + foreach (@SelectedMaps) { + if ($_ eq 'all') { + @SelectedMaps = ('all'); + last; + } + } + # + # Put in option for 'all' + $Str .= ' \n"; + $Str .= '>'.$seq->{'title'}."\n"; } $Str .= "\n"; return $Str; } - ############################################## ############################################## @@ -486,7 +737,7 @@ sub SectionSelect { foreach my $s (@Sections) { $Str .= '