--- loncom/interface/lonprintout.pm 2011/06/06 10:53:09 1.590 +++ loncom/interface/lonprintout.pm 2011/11/05 21:49:25 1.602 @@ -2,7 +2,7 @@ # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.590 2011/06/06 10:53:09 foxr Exp $ +# $Id: lonprintout.pm,v 1.602 2011/11/05 21:49:25 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -123,7 +123,7 @@ sub create_incomplete_folder_selstud_hel my $format_chooser = &generate_format_selector($helper, 'Format of the print job', - '','CHOOSE_STUDENTS_INCOMPLETE_FORMAT'); # end state. + 'CHOOSE_STUDENTS_INCOMPLETE_FORMAT'); # end state. return $resource_chooser . $student_chooser . $format_chooser; } @@ -172,7 +172,6 @@ sub create_incomplete_course_helper { my $format = &generate_format_selector($helper, 'Format of the print job', - '', 'INCOMPLETE_PROBLEMS_COURSE_FORMAT'); # end state. return $resource_chooser . $people_chooser . $format; @@ -356,7 +355,7 @@ sub generate_code_selector { - Bubble sheet type: + Bubblesheet type: $bubble_types @@ -395,21 +394,25 @@ CHOOSE_ANON1 return $result; } +# Returns the XML for choosing how assignments are to be formatted +# that text must still be parsed by the helper xml parser. +# Parameters: 3 (required) + +# helper - The helper; $helper->{'VARS'}->{'PRINT_TYPE'} used +# to check if splitting PDFs by section can be offered. +# title - Title for the current state. +# this_state - State name of the chooser. + sub generate_format_selector { - my ($helper,$title,$nextstate, $thisstate) = @_; + my ($helper,$title,$this_state) = @_; my $secpdfoption; - my $state = 'PRINT_FORMATTING'; - if ($thisstate) { - $state = $thisstate; - } unless (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_anon') || ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_anon_page') || ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_anon') ) { $secpdfoption = 'Each PDF contains exactly one section'; } return < - $nextstate +
How should the results be printed?
Start each student\'s assignment on a new page/column (add a pagefeed after each assignment) @@ -432,6 +435,103 @@ RESOURCE_SELECTOR #----------------------------------------------------------------------- +# Determine if a resource is incomplete given the map: +# Parameters: +# $username - Name of user for whom we are checking. +# $domain - Domain of user we are checking. +# $map - map name. +# Returns: +# 0 - map is not incomplete. +# 1 - map is incomplete. +# +sub incomplete { + my ($username, $domain, $map) = @_; + + + my $navmap = Apache::lonnavmaps::navmap->new($username, $domain); + + + if (defined($navmap)) { + my $res = $navmap->getResourceByUrl($map); + my $result = $res->is_incomplete(); + return $result; + } else { + return 1; + } +} +# +# When printing for students, the resoures and order of the +# resources may need to be altered if there are folders with +# random selectiopn or random ordering (or both) enabled. +# This sub computes the set of resources to print for a student +# modified both by random ordering and selection and filtered +# to only those that are in the original set selcted to be printed. +# +# Parameters: +# $helper - The helper we need $helper->{'VARS'}->{'symb'} +# to construct the navmap and the iteration. +# $seq - The original set of resources to print +# (really an array of resource names (array of symb's). +# $who - Student/domain for whome the sequence will be generated. +# +# Implicit inputs: +# $ +# Returns: +# reference to an array of resources that can be passed to +# print_resources. +# +sub master_seq_to_person_seq { + my ($helper, $seq, $who) = @_; + + + my ($username, $userdomain, $usersection) = split(/:/, $who); + + + # Toss the sequence up into a hash so that we have O(1) lookup time. + # on the items that come out of the user's list of resources. + # + + my %seq_hash = map {$_ => 1} @$seq; + my @output_seq; + + my ($map, $id, $url) = &Apache::lonnet::decode_symb($helper->{VARS}->{'symb'}); + my $navmap = Apache::lonnavmaps::navmap->new($username, $userdomain); + my $iterator = $navmap->getIterator($navmap->firstResource(), + $navmap->finishResource(), + {}, 1); + my %nonResourceItems = ( + $iterator->BEGIN_MAP => 1, + $iterator->BEGIN_BRANCH => 1, + $iterator->END_BRANCH => 1, + $iterator->END_MAP => 1, + $iterator->FORWARD => 1, + $iterator->BACKWARD => 1 + + ); # These items are not resources but appear in the midst of iteration. + + # Iterate on the resource..select the items that are randomly selected + # and that are in the seq_has. Presumably the iterator will take care + # of the random ordering part of the deal. + # + my $curres; + while ($curres = $iterator->next()) { + # + # Only process resources..that are not removed by randomout... + # and are selected for printint as well. + # + if (! exists $nonResourceItems{$curres} && ! $curres->randomout()) { + my $symb = $curres->symb(); + if (exists $seq_hash{$symb}) { + push(@output_seq, $symb); + } + } + } + + + return \@output_seq; # for now. + +} + # Fetch the contents of a resource, uninterpreted. # This is used here to fetch a latex file to be included @@ -606,7 +706,6 @@ sub ssi_with_retries { $ssi_last_error_resource = $resource; $ssi_last_error = $response->code . " " . $response->message; $content='\section*{!!! An error occurred !!!}'; - &Apache::lonnet::logthis("Error in SSI resource: $resource Error: $ssi_last_error"); } return $content; @@ -622,7 +721,6 @@ sub get_student_view_with_retries { $ssi_last_error_resource = $curresline.' for user '.$username.':'.$userdomain; $ssi_last_error = $response->code . " " . $response->message; $content='\section*{!!! An error occurred !!!}'; - &Apache::lonnet::logthis("Error in SSI (student view) resource: $curresline Error: $ssi_last_error User: $username:$userdomain"); } return $content; @@ -1710,6 +1808,7 @@ sub map_laystyle { sub print_page_in_course { my ($helper, $rparmhash, $currentURL, $resources) = @_; + my %parmhash = %$rparmhash; my @page_resources = @$resources; my $mode = $helper->{'VARS'}->{'LATEX_TYPE'}; @@ -1766,8 +1865,10 @@ sub print_page_in_course { } # these resources go through the XML transformer: - elsif ($resource_src =~ /\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { + elsif ($resource_src =~ /\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { + my $urlp = &Apache::lonnet::clutter($resource_src); + my %form; my %moreenv; @@ -1829,10 +1930,9 @@ sub print_page_in_course { $texversion.='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $texversion.=&path_to_problem($urlp,$LaTeXwidth); } else { - $texversion.='\vskip 0 mm \noindent\textbf{Prints from construction space - there is no title.}\vskip 0 mm '; - my $URLpath=$urlp; - $URLpath=~s/~([^\/]+)/public_html\/$1\/$1/; - $texversion.=&path_to_problem($URLpath,$LaTeXwidth); + $texversion.='\vskip 0 mm \noindent\textbf{'. + &mt("Printing from Construction Space: No Title").'}\vskip 0 mm '; + $texversion.=&path_to_problem($urlp,$LaTeXwidth); } $texversion.='\vskip 1 mm '.$answer.'\end{document}'; } @@ -1951,7 +2051,7 @@ sub recently_generated { # A reference to a page break hash. # # -# use Data::Dumper; +use Data::Dumper; # sub dump_helper_vars { # my ($helper) = @_; # my $helpervars = Dumper($helper->{'VARS'}); @@ -2171,9 +2271,12 @@ sub print_construction_sequence { # IF sequence, recurse: if ($urlp =~ /\.sequence$/) { +# +# FIXME: this does not work for co-authors my $sequence_url = $urlp; my $domain = $env{'user.domain'}; # Constr. space only on local my $user = $env{'user.name'}; +# FIXME: the substitutions below do not seem to make sense $sequence_url =~ s/^\/res\/$domain/\/home/; $sequence_url =~ s/^(\/home\/$user)/$1\/public_html/; @@ -2222,13 +2325,12 @@ sub print_construction_sequence { #BZ 5209 # 2 map_incomplete_problems_seq Print incomplete problems from the current # folder in student context. -# 101 map_incomplete_problems_people_seq Print incomplete problems from the +# 5 map_incomplete_problems_people_seq Print incomplete problems from the # current folder in privileged context. -# 102 incomplete_problems_selpeople_course Print incomplete problems for +# 5 incomplete_problems_selpeople_course Print incomplete problems for # selected people from the entire course. # # Item 101 has much the same processing as 8, -# Item 102 has much the same processing as 8. # # Differences: Item 101, 102 require per-student filtering of the resource # set so that only the incomplete resources are printed. @@ -2236,6 +2338,7 @@ sub print_construction_sequence { sub output_data { my ($r,$helper,$rparmhash) = @_; + my %parmhash = %$rparmhash; $ssi_error = 0; # This will be set nonzero by failing ssi's. $resources_printed = ''; @@ -2351,11 +2454,11 @@ ENDPART } else { #prints resource from the construction space - $currentURL='/'.$helper->{'VARS'}->{'filename'}; - if ($currentURL=~/([^?]+)/) {$currentURL=$1;} + $currentURL=$helper->{'VARS'}->{'filename'}; $cleanURL=$currentURL; } $selectionmade = 1; + if ($cleanURL!~m|^/adm/| && $cleanURL=~/\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { my $rndseed=time; @@ -2395,6 +2498,7 @@ ENDPART if(($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) { + $form{'problem_split'}=$parmhash{'problem_stream_switch'}; $form{'grade_target'}='answer'; $form{'answer_output_mode'}='tex'; @@ -2416,10 +2520,10 @@ ENDPART $texversion.='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $texversion.=&path_to_problem($cleanURL,$LaTeXwidth); } else { - $texversion.='\vskip 0 mm \noindent\textbf{Prints from construction space - there is no title.}\vskip 0 mm '; - my $URLpath=$cleanURL; - $URLpath=~s/~([^\/]+)/public_html\/$1\/$1/; - $texversion.=&path_to_problem($URLpath,$LaTeXwidth); + $texversion.='\vskip 0 mm \noindent\textbf{'. + &mt("Printing from Construction Space: No Title").'}\vskip 0 mm '; + + $texversion.=&path_to_problem($cleanURL,$LaTeXwidth); } $texversion.='\vskip 1 mm '.$answer.'\end{document}'; } @@ -2453,6 +2557,7 @@ ENDPART && $currentURL=~/\.(sequence|page)$/ && $helper->{'VARS'}->{'construction'} eq '1') { #printing content of sequence from the construction space +# FIXME: unclear how this would work $currentURL=~s|\/~([^\/]+)\/|\/home\/$1\/public_html\/|; $result .= &print_construction_sequence($currentURL, $helper, %form, @@ -2724,14 +2829,18 @@ ENDPART } elsif (($print_type eq 'problems_for_students') || ($print_type eq 'problems_for_students_from_page') || ($print_type eq 'all_problems_students') || - ($print_type eq 'resources_for_students')){ + ($print_type eq 'resources_for_students') || + ($print_type eq 'incomplete_problems_selpeople_course') || + ($print_type eq 'map_incomplete_problems_people_seq')){ #-- prints assignments for whole class or for selected students my $type; if (($print_type eq 'problems_for_students') || ($print_type eq 'problems_for_students_from_page') || - ($print_type eq 'all_problems_students') ) { + ($print_type eq 'all_problems_students') || + ($print_type eq 'incomplete_problems_selpeople_course') || + ($print_type eq 'map_incomplete_problems_people_seq')) { $selectionmade=5; $type='problems'; } elsif ($print_type eq 'resources_for_students') { @@ -2788,7 +2897,6 @@ ENDPART my $i = 0; my $last_section = (split(/:/,$students[0]))[2]; foreach my $person (@students) { - my $duefile="/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.due"; if (-e $duefile) { my $temp_file = Apache::File->new('>>'.$duefile); @@ -2804,9 +2912,10 @@ ENDPART } else { $i=int($student_counter/$helper->{'VARS'}{'NUMBER_TO_PRINT'}); } + my $actual_seq = master_seq_to_person_seq($helper, \@master_seq, $person); my ($output,$fullname, $printed)=&print_resources($r,$helper, $person,$type, - \%moreenv,\@master_seq, + \%moreenv, $actual_seq, $flag_latex_header_remove, $LaTeXwidth); $resources_printed .= ":"; @@ -2832,17 +2941,24 @@ ENDPART my $code_option=$helper->{'VARS'}->{'CODE_OPTION'}; my @lines = &Apache::grades::get_scantronformat_file(); - my ($code_type,$code_length)=('letter',6); + my ($code_type,$code_length,$bubbles_per_row)=('letter',6,10); foreach my $line (@lines) { - my ($name,$type,$length) = (split(/:/,$line))[0,2,4]; + chomp($line); + my ($name,$type,$length,$bubbles_per_item) = + (split(/:/,$line))[0,2,4,17]; if ($name eq $code_option) { $code_length=$length; if ($type eq 'number') { $code_type = 'number'; } + chomp($bubbles_per_item); + if (($bubbles_per_item ne '') && ($bubbles_per_item > 0)) { + $bubbles_per_row = $bubbles_per_item; + } } } my %moreenv = ('textwidth' => &get_textwidth($helper,$LaTeXwidth)); $moreenv{'problem_split'} = $parmhash{'problem_stream_switch'}; $moreenv{'instructor_comments'}='hide'; + $moreenv{'bubbles_per_row'} = $bubbles_per_row; my $seed=time+($$<<16)+($$); my @allcodes; if ($old_name) { @@ -3159,7 +3275,18 @@ sub print_resources { my ($username,$userdomain,$usersection) = split /:/,$person; my $fullname = &get_name($username,$userdomain); my $namepostfix = "\\\\"; # Both anon and not anon should get the same vspace. - if ($person =~ 'anon') { + + # + # Figure out if we need to filter the output by + # the incomplete problems for that person + # + my $print_type = $helper->{'VARS'}->{'PRINT_TYPE'}; + my $print_incomplete = 0; + if (($print_type eq 'map_incomplete_problems_people_seq') || + ($print_type eq 'incomplete_problems_selpeople_course')) { + $print_incomplete = 1; + } + if ($person eq 'anonymous') { $namepostfix .="Name: "; $fullname = "CODE - ".$moreenv->{'CODE'}; } @@ -3168,6 +3295,7 @@ sub print_resources { # my $i = 0; + my $actually_printed = 0; # Count of resources printed. #goes through all resources, checks if they are available for #current student, and produces output @@ -3184,6 +3312,7 @@ sub print_resources { # so we will just rely on prntout.pl to strip ENDOFSTUDENTSTAMP from the # postscript. Each ENDOFSTUDENTSTAMP will go on a line by itself. # + my $syllabus_first = 0; foreach my $curresline (@{$master_seq}) { if (defined $page_breaks{$curresline}) { @@ -3196,6 +3325,10 @@ sub print_resources { if ( !($type eq 'problems' && ($curresline!~ m/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) ) { my ($map,$id,$res_url) = &Apache::lonnet::decode_symb($curresline); + if ($print_incomplete && !&incomplete($username, $userdomain, $res_url)) { + next; + } + $actually_printed++; # we're going to print one. if (&Apache::lonnet::allowed('bre',$res_url)) { if ($res_url!~m|^ext/| && $res_url=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)$/) { @@ -3209,6 +3342,7 @@ sub print_resources { $rendered = &print_latex_header().$rendered; } } +; if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { @@ -3220,6 +3354,8 @@ sub print_resources { # Use a copy of the hash so we don't pervert it on future loop passes. my %answerenv = %{$moreenv}; $answerenv{'answer_output_mode'}='tex'; + + $answerenv{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; &Apache::lonxml::restore_problem_counter(); @@ -3294,6 +3430,20 @@ sub print_resources { } if (&Apache::loncommon::connection_aborted($r)) { last; } } + # If we are printing incomplete it's possible we don't have + # anything to print. The print subsystem is not so good at handling + # that so we're going to generate a stub that says there are no + # incomplete resources for the person. + # + + if ($actually_printed == 0) { + $current_output = &encapsulate_minipage("\\vskip -10mm \nNo incomplete resources\n \\vskip 100 mm { }\n"); + if ($remove_latex_header eq "NO") { + $current_output = &print_latex_header() . $current_output; + } else { + $current_output = &latex_header_footer_remove($current_output); + } + } if ($syllabus_first) { $current_output =~ s/\\\\ Last updated:/Last updated:/ @@ -3330,8 +3480,6 @@ sub handler { &init_perm(); - - my $helper = printHelper($r); if (!ref($helper)) { return $helper; @@ -3495,8 +3643,8 @@ sub printHelper { } # Detect whether we're coming from construction space - if ($env{'form.postdata'}=~/^(?:http:\/\/[^\/]+\/|\/|)\~([^\/]+)\/(.*)$/) { - $helper->{VARS}->{'filename'} = "~$1/$2"; + if ($env{'form.postdata'}=~m{^/priv}) { + $helper->{VARS}->{'filename'} = $env{'form.postdata'}; $helper->{VARS}->{'construction'} = 1; } else { if ($env{'form.postdata'}) { @@ -3718,7 +3866,7 @@ sub printHelper { } push(@{$printChoices}, - [&mt('Selected Incomplete [_1]Problems[_2] from folder [_3]' . $textSuffix, + [&mt('Selected [_1]Incomplete Problems[_2] from folder [_3]' . $textSuffix, '', '', ''. $sequenceTitle . ''), $printSelector, @@ -3765,7 +3913,7 @@ sub printHelper { # BZ 5209 - incomplete problems from entire course: push(@{$printChoices}, - [&mtn('Selected incomplete Problems from entire course for selected people'), + [&mtn('Selected Incomplete Problems from entire course for selected people'), 'incomplete_problems_selpeople_course', 'INCOMPLETE_PROBLEMS_COURSE_RESOURCES']); my $helperFragment = &create_incomplete_course_helper($helper); # Create needed states. @@ -3838,7 +3986,7 @@ ALL_PROBLEMS } my $randomly_ordered_warning = - &get_randomly_ordered_warning($helper,$map); + &get_randomly_ordered_warning($helper, $map); # resource_selector will hold a few states that: # - Allow resources to be selected for printing. @@ -3857,14 +4005,9 @@ ALL_PROBLEMS $map, $isProblem, '', $symbFilter, $start_new_option); - my $secpdfoption; - unless (($helper->{'VARS'} eq 'problems_for_anon') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_anon_page') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_anon') ) { - $secpdfoption = 'Each PDF contains exactly one section'; - } $resource_selector .= &generate_format_selector($helper, - 'How should results be printed?'). + 'How should results be printed?', + 'PRINT_FORMATTING'). &generate_resource_chooser('CHOOSE_STUDENTS_PAGE', 'Select Problem(s) to print', "multichoice='1' addstatus='1' closeallpages ='1'", @@ -3998,10 +4141,9 @@ ALL_PROBLEMS
RESOURCE_SELECTOR - my $nextstate = 'NUMBER_PER_PDF'; $resource_selector .= &generate_format_selector($helper, 'Format of the print job', - $nextstate); + 'PRINT_FORMATTING'); &Apache::lonxml::xmlparse($r, 'helper', < @@ -4042,7 +4184,7 @@ CHOOSE_STUDENTS1 - Bubble sheet type: + Bubblesheet type: $codechoice