--- loncom/interface/lonprintout.pm 2010/08/04 22:17:14 1.583 +++ loncom/interface/lonprintout.pm 2011/12/21 21:25:40 1.611 @@ -1,8 +1,8 @@ -# + # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.583 2010/08/04 22:17:14 raeburn Exp $ +# $Id: lonprintout.pm,v 1.611 2011/12/21 21:25:40 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -45,13 +45,13 @@ use Apache::londefdef; use File::Basename; use HTTP::Response; - use LONCAPA::map(); use POSIX qw(strftime); use Apache::lonlocal; use Carp; use LONCAPA; + my %perm; my %parmhash; my $resources_printed; @@ -76,7 +76,145 @@ my $font_size = 'normalsize'; # Default #---------------------------- Helper helpers. ------------------------- -# Returns the text needd for a student chooser. +# BZ5209: +# Create the states needed to run the helper for incomplete problems from +# the current folder for selected students. +# This includes: +# - A resource selector limited to problems (incompleteness must be +# calculated on a student per student basis. +# - A student selector. +# - Tie in to the FORMAT of the print job. +# +# States: +# CHOOSE_INCOMPLETE_PEOPLE_SEQ - Resource selection. +# CHOOSE_STUDENTS_INCOMPLETE - Student selection. +# CHOOSE_STUDENTS_INCOMPLETE_FORMAT - Format selection +# Parameters: +# helper - the helper which already contains info about the current folder we can +# purloin. +# url - Top url of the sequence +# Return: +# XML that can be parsed by the helper to drive the state machine. +# +sub create_incomplete_folder_selstud_helper($helper) +{ + my ($helper, $map) = @_; + + + my $symbFilter = '$res->shown_symb()'; + my $selFilter = '$res->is_problem()'; + + + my $resource_chooser = &generate_resource_chooser('CHOOSE_INCOMPLETE_PEOPLE_SEQ', + 'Select problem(s) to print', + 'multichoice="1" toponly="1" addstatus="1" closeallpages="1"', + 'RESOURCES', + 'CHOOSE_STUDENTS_INCOMPLETE', + $map, + $selFilter, + '', + $symbFilter, + ''); + + my $student_chooser = &generate_student_chooser('CHOOSE_STUDENTS_INCOMPLETE', + 'student_sort', + 'STUDENTS', + 'CHOOSE_STUDENTS_INCOMPLETE_FORMAT'); + + my $format_chooser = &generate_format_selector($helper, + 'Format of the print job', + 'CHOOSE_STUDENTS_INCOMPLETE_FORMAT'); # end state. + + return $resource_chooser . $student_chooser . $format_chooser; +} + + +# BZ 5209 +# Create the states needed to run the helper for incomplete problems from +# the current folder for selected students. +# This includes: +# - A resource selector limited to problems. (incompleteness must be calculated +# on a student per student basis. +# - A student selector. +# - Tie in to format for the print job. +# States: +# INCOMPLETE_PROBLEMS_COURSE_RESOURCES - Resource selector. +# INCOMPLETE_PROBLEMS_COURSE_STUDENTS - Student selector. +# INCOMPLETE_PROBLEMS_COURSE_FORMAT - Format selection. +# +# Parameters: +# helper - Helper we are creating states for. +# Returns: +# Text that can be parsed by the helper. +# + +sub create_incomplete_course_helper { + my $helper = shift; + + my $filter = '$res->is_problem() || $res->contains_problem() || $res->is_sequence() || $res->is_practice())'; + my $symbfilter = '$res->shown_symb()'; + + my $resource_chooser = &generate_resource_chooser('INCOMPLETE_PROBLEMS_COURSE_RESOURCES', + 'Select problem(s) to print', + 'multichoice = "1" suppressEmptySequences="0" addstatus="1" closeallpagtes="1"', + 'RESOURCES', + 'INCOMPLETE_PROBLEMS_COURSE_STUDENTS', + '', + $filter, + '', + $symbfilter, + ''); + + my $people_chooser = &generate_student_chooser('INCOMPLETE_PROBLEMS_COURSE_STUDENTS', + 'student_sort', + 'STUDENTS', + 'INCOMPLETE_PROBLEMS_COURSE_FORMAT'); + + my $format = &generate_format_selector($helper, + 'Format of the print job', + 'INCOMPLETE_PROBLEMS_COURSE_FORMAT'); # end state. + + return $resource_chooser . $people_chooser . $format; + + +} + +# BZ5209 +# Creates the states needed to run the print helper for a student +# that wants to print his incomplete problems from the current folder. +# Parameters: +# $helper - helper we are generating states for. +# $map - The map for which the student wants incomplete problems. +# Returns: +# XML that defines the helper states being created. +# +# States: +# CHOOSE_INCOMPLETE_SEQ - Resource selector. +# +sub create_incomplete_folder_helper { + my ($helper, $map) = @_; + + my $filter = '$res->is_problem()'; + $filter .= ' && $res->resprintable() '; + $filter .= ' && $res->is_incomplete() '; + + my $symfilter = '$res->shown_symb()'; + + my $resource_chooser = &generate_resource_chooser('CHOOSE_INCOMPLETE_SEQ', + 'Select problem(s) to print', + 'multichoice="1", toponly ="1", addstatus="1", closeallpages="1"', + 'RESOURCES', + 'PAGESIZE', + $map, + $filter, '', + $symfilter, + ''); + + return $resource_chooser; +} + + +# Returns the text neded for a student chooser. # that text must still be parsed by the helper xml parser. # Parameters: # this_state - State name of the chooser. @@ -164,7 +302,6 @@ CHOOSE_RESOURCES CHOOSE_RESOURCES - return $result; } # @@ -217,7 +354,7 @@ sub generate_code_selector { - Bubble sheet type: + Bubblesheet type: $bubble_types @@ -256,8 +393,145 @@ 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,$this_state) = @_; + my $secpdfoption; + 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 < +
How should the results be printed?
+ + Start each student\'s assignment on a new page/column (add a pagefeed after each assignment) + Add one empty page/column after each student\'s assignment + Add two empty pages/column after each student\'s assignment + Add three empty pages/column after each student\'s assignment + + PAGESIZE +
How do you want assignments split into PDF files?
+ + All assignments in a single PDF file + $secpdfoption + Each PDF contains exactly one assignment + + Specify the number of assignments per PDF: + + +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 @@ -360,9 +634,10 @@ sub include_pdf { # (unlikely). If it did exist, add the pdf to the set of files/images that # need tob e converted for this print job: - $file =~ s|(.*)/res/|/home/httpd/html/res/|; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; + $file =~ s{(.*)/res/}{$londocroot/res/}; - open(FILE,">>/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout.dat"); + open(FILE,">>$Apache::lonnet::perlvar{'lonPrtDir'}/$env{'user.name'}_$env{'user.domain'}_printout.dat"); print FILE ("$file\n"); close (FILE); @@ -432,7 +707,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; @@ -448,7 +722,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; @@ -1536,6 +1809,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'}; @@ -1592,8 +1866,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; @@ -1655,10 +1931,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}'; } @@ -1707,8 +1982,8 @@ sub print_page_in_course { # List of recently generated print files # sub recently_generated { - my $r=shift; - my $prtspool=$r->dir_config('lonPrtDir'); + my ($prtspool) = @_; + my $output; my $zip_result; my $pdf_result; opendir(DIR,$prtspool); @@ -1741,10 +2016,10 @@ sub recently_generated { if ($ext eq 'zip') { $zip_result .= $result; } } if ($zip_result || $pdf_result) { - $r->print('
'); + $output ='
'; } if ($zip_result) { - $r->print('

'.&mt('Recently generated printout zip files')."

\n" + $output .='

'.&mt('Recently generated printout zip files')."

\n" .&Apache::loncommon::start_data_table() .&Apache::loncommon::start_data_table_header_row() .''.&mt('Download').'' @@ -1752,11 +2027,10 @@ sub recently_generated { .''.&mt('File Size (Bytes)').'' .&Apache::loncommon::end_data_table_header_row() .$zip_result - .&Apache::loncommon::end_data_table() - ); + .&Apache::loncommon::end_data_table(); } if ($pdf_result) { - $r->print('

'.&mt('Recently generated printouts')."

\n" + $output .='

'.&mt('Recently generated printouts')."

\n" .&Apache::loncommon::start_data_table() .&Apache::loncommon::start_data_table_header_row() .''.&mt('Download').'' @@ -1764,9 +2038,9 @@ sub recently_generated { .''.&mt('File Size (Bytes)').'' .&Apache::loncommon::end_data_table_header_row() .$pdf_result - .&Apache::loncommon::end_data_table() - ); + .&Apache::loncommon::end_data_table(); } + return $output; } # @@ -1926,17 +2200,20 @@ sub set_form_extraspace { # sub print_construction_sequence { my ($currentURL, $helper, %form, $LaTeXwidth) = @_; + my $result; my $rndseed=time; if ($helper->{'VARS'}->{'curseed'}) { $rndseed=$helper->{'VARS'}->{'curseed'}; } - my $errtext=&LONCAPA::map::mapread($currentURL); + my $errtext=&LONCAPA::map::mapread(&Apache::lonnet::filelocation('',$currentURL)); + # # These make this all support recursing for subsequences. # my @order = @LONCAPA::map::order; my @resources = @LONCAPA::map::resources; + for (my $member=0;$member<=$#order;$member++) { $resources[$order[$member]]=~/^([^:]*):([^:]*):/; my $urlp=$2; @@ -1952,7 +2229,7 @@ sub print_construction_sequence { } if((($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) && - ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) { + ($urlp=~/$LONCAPA::assess_page_re/)) { # Don't permanently modify %$form... my %answerform = %form; $answerform{'grade_target'}='answer'; @@ -1996,14 +2273,7 @@ sub print_construction_sequence { # IF sequence, recurse: if ($urlp =~ /\.sequence$/) { - my $sequence_url = $urlp; - my $domain = $env{'user.domain'}; # Constr. space only on local - my $user = $env{'user.name'}; - - $sequence_url =~ s/^\/res\/$domain/\/home/; - $sequence_url =~ s/^(\/home\/$user)/$1\/public_html/; -# $sequence_url =~ s|\/~([^\/]+)\/|\/home\/$1\/public_html\/|; - $result .= &print_construction_sequence($sequence_url, + $result .= &print_construction_sequence($urlp, $helper, %form, $LaTeXwidth); } @@ -2027,12 +2297,44 @@ sub print_construction_sequence { return $result; } +# +# Top level for generating print output. +# +# May call print_resources if multiple resources will be printed. +# +# The main driver is $selectionmade which reflects the type of print out +# requested: +# Value Print type: +# 1 Print resource that's being looked at. +# 2 Print problems in a map or in a page. +# 3 Print pages in a map or resources in a page. +# 4 Print all problems or all resources. +# 5 Print problems for seleted students. +# 6 Print selected problems from a folder. +# 7 Print print selected resources from some scope. +# 8 Print resources for selected students. +# +#BZ 5209 +# 2 map_incomplete_problems_seq Print incomplete problems from the current +# folder in student context. +# 5 map_incomplete_problems_people_seq Print incomplete problems from the +# current folder in privileged context. +# 5 incomplete_problems_selpeople_course Print incomplete problems for +# selected people from the entire course. +# +# Item 101 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. +# For item 100, filtering was done at the helper level. + sub output_data { my ($r,$helper,$rparmhash) = @_; my %parmhash = %$rparmhash; $ssi_error = 0; # This will be set nonzero by failing ssi's. $resources_printed = ''; $font_size = $helper->{'VARS'}->{'fontsize'}; + my $print_type = $helper->{'VARS'}->{'PRINT_TYPE'}; # Allows textual simplification. my $do_postprocessing = 1; my $js = < @@ -2082,7 +2384,7 @@ ENDPART $env{'form.pagebreaks'} = $helper->{'VARS'}->{'FINISHPAGE'}; &set_form_extraspace($helper); - $env{'form.lastprinttype'} = $helper->{'VARS'}->{'PRINT_TYPE'}; + $env{'form.lastprinttype'} = $print_type; &Apache::loncommon::store_course_settings('print', {'pagebreaks' => 'scalar', 'extraspace' => 'scalar', @@ -2132,7 +2434,7 @@ ENDPART &Apache::lonnet::delenv('construct.style'); } - if ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'current_document') { + if ($print_type eq 'current_document') { #-- single document - problem, page, html, xml, ... my ($currentURL,$cleanURL); @@ -2143,11 +2445,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; @@ -2187,6 +2489,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'; @@ -2208,10 +2511,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}'; } @@ -2243,10 +2546,6 @@ ENDPART } } elsif ($cleanURL!~m|^/adm/| && $currentURL=~/\.(sequence|page)$/ && $helper->{'VARS'}->{'construction'} eq '1') { - #printing content of sequence from the construction space - - - $currentURL=~s|\/~([^\/]+)\/|\/home\/$1\/public_html\/|; $result .= &print_construction_sequence($currentURL, $helper, %form, $LaTeXwidth); $result .= '\end{document}'; @@ -2294,32 +2593,35 @@ ENDPART $result.=&unsupported($currentURL,$helper->{'VARS'}->{'LATEX_TYPE'}, $helper->{'VARS'}->{'symb'}); } - } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_in_page') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_resources_in_page') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_pages') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_resources') or # BUGBUG - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'select_sequences') + } elsif (($print_type eq 'map_problems') or + ($print_type eq 'map_problems_in_page') or + ($print_type eq 'map_resources_in_page') or + ($print_type eq 'map_problems_pages') or + ($print_type eq 'all_problems') or + ($print_type eq 'all_resources') or # BUGBUG + ($print_type eq 'select_sequences') or + ($print_type eq 'map_incomplete_problems_seq') ) { #-- produce an output string - if (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_in_page') ) { + if (($print_type eq 'map_problems') or + ($print_type eq 'map_incomplete_problems_seq') or + ($print_type eq 'map_problems_in_page') ) { $selectionmade = 2; - } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_pages') or - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_resources_in_page')) + } elsif (($print_type eq 'map_problems_pages') or + ($print_type eq 'map_resources_in_page')) { $selectionmade = 3; - } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems') + } elsif (($print_type eq 'all_problems') ) { $selectionmade = 4; - } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_resources') { #BUGBUG + } elsif ($print_type eq 'all_resources') { #BUGBUG $selectionmade = 4; - } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'select_sequences') { + } elsif ($print_type eq 'select_sequences') { $selectionmade = 7; } + $form{'problem_split'}=$parmhash{'problem_stream_switch'}; $form{'suppress_tries'}=$parmhash{'suppress_tries'}; $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; @@ -2369,8 +2671,8 @@ ENDPART unless (($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only') || (($i==0) && (($urlp=~/\.page$/) || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_in_page') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_resources_in_page')))) { + ($print_type eq 'map_problems_in_page') || + ($print_type eq 'map_resources_in_page')))) { $flag_latex_header_remove = 'YES'; } } @@ -2405,7 +2707,7 @@ ENDPART $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; } } else { - if ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/) { + if ($urlp=~/$LONCAPA::assess_page_re/) { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); # $texversion =~ s/\\begin{document}//; # FIXME my $title = &Apache::lonnet::gettitle($master_seq[$i]); @@ -2510,20 +2812,24 @@ ENDPART $result =~ s/\\usepackage{calc}/\\usepackage{calc}\\usepackage{longtable}/; } $result .= '\end{document}'; - } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students_from_page') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems_students') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_students')){ + } 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 'incomplete_problems_selpeople_course') || + ($print_type eq 'map_incomplete_problems_people_seq')){ #-- prints assignments for whole class or for selected students my $type; - if (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students_from_page') || - ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems_students') ) { + if (($print_type eq 'problems_for_students') || + ($print_type eq 'problems_for_students_from_page') || + ($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 ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_students') { + } elsif ($print_type eq 'resources_for_students') { $selectionmade=8; $type='resources'; } @@ -2572,12 +2878,11 @@ ENDPART ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes')) { $moreenv{'problem_split'}='yes'; } - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Print Status','Class Print Status',$#students+1,'inline','75'); + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$#students+1); my $student_counter=-1; 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); @@ -2593,9 +2898,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 .= ":"; @@ -2608,9 +2914,9 @@ ENDPART } &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); $result .= $print_array[0].' \end{document}'; - } elsif (($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') ) { + } elsif (($print_type eq 'problems_for_anon') || + ($print_type eq 'problems_for_anon_page') || + ($print_type eq 'resources_for_anon') ) { my $cdom =$env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum =$env{'course.'.$env{'request.course.id'}.'.num'}; my $num_todo=$helper->{'VARS'}->{'NUMBER_TO_PRINT_TOTAL'}; @@ -2621,17 +2927,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) { @@ -2672,14 +2985,15 @@ ENDPART @allcodes=keys(%allcodes); } my @master_seq=split /\|\|\|/, $helper->{'VARS'}->{'RESOURCES'}; - my ($type) = split(/_/,$helper->{'VARS'}->{'PRINT_TYPE'}); + my ($type) = split(/_/,$print_type); &adjust_number_to_print($helper); my $number_per_page=$helper->{'VARS'}->{'NUMBER_TO_PRINT'}; - if ($number_per_page eq '0' || $number_per_page eq 'all') { - $number_per_page=$num_todo; + if ($number_per_page eq '0' || $number_per_page eq 'all' + || $number_per_page eq 'section') { + $number_per_page=$num_todo > 0 ? $num_todo : 1; } my $flag_latex_header_remove = 'NO'; - my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,'Print Status','Class Print Status',$num_todo,'inline','75'); + my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r,$num_todo); my $count=0; foreach my $code (sort(@allcodes)) { my $file_num=int($count/$number_per_page); @@ -2702,7 +3016,7 @@ ENDPART } &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state); $result .= $print_array[0].' \end{document}'; - } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_from_directory') { + } elsif ($print_type eq 'problems_from_directory') { #prints selected problems from the subdirectory $selectionmade = 6; my @list_of_files=split /\|\|\|/, $helper->{'VARS'}->{'FILES'}; @@ -2721,11 +3035,7 @@ ENDPART if ($urlp=~/\//) { $form{'problem_split'}=$parmhash{'problem_stream_switch'}; $form{'rndseed'}=$rndseed; - if ($urlp =~ m|/home/([^/]+)/public_html|) { - $urlp =~ s|/home/([^/]*)/public_html|/~$1|; - } else { - $urlp =~ s|^$Apache::lonnet::perlvar{'lonDocRoot'}||; - } + $urlp =~ s|^$Apache::lonnet::perlvar{'lonDocRoot'}||; $resources_printed .= $urlp.':'; my $texversion=&ssi_with_retries($urlp, $ssi_retry_count, %form); if(($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || @@ -2746,19 +3056,16 @@ ENDPART $texversion.='\vskip 0 mm \noindent '; $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}'; } } #this chunk is responsible for printing the path to problem - my $newurlp=$urlp; - if ($newurlp=~/~/) {$newurlp=~s|\/~([^\/]+)\/|\/home\/$1\/public_html\/|;} - $newurlp=&path_to_problem($newurlp,$LaTeXwidth); + my $newurlp=&path_to_problem($urlp,$LaTeXwidth); $texversion =~ s/(\\begin{minipage}{\\textwidth})/$1 $newurlp/; if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); @@ -2784,7 +3091,13 @@ ENDPART # Only post process if that has not been turned off e.g. by a raw latex resource. if ($do_postprocessing) { - $result = &page_format_transformation($papersize,$laystyle,$numberofcolumns,$helper->{'VARS'}->{'PRINT_TYPE'},$result,$helper->{VARS}->{'assignment'},$helper->{'VARS'}->{'TABLE_CONTENTS'},$helper->{'VARS'}->{'TABLE_INDEX'},$selectionmade); + $result = &page_format_transformation($papersize, + $laystyle,$numberofcolumns, + $print_type,$result, + $helper->{VARS}->{'assignment'}, + $helper->{'VARS'}->{'TABLE_CONTENTS'}, + $helper->{'VARS'}->{'TABLE_INDEX'}, + $selectionmade); $result = &latex_corrections($number_of_columns,$result,$selectionmade, $helper->{'VARS'}->{'ANSWER_TYPE'}); #if ($numberofcolumns == 1) { @@ -2801,12 +3114,7 @@ ENDPART my $URLback=''; #link to original document if ($helper->{'VARS'}->{'construction'} eq '1') { - #prints resource from the construction space - $URLback='/'.$helper->{'VARS'}->{'filename'}; - if ($URLback=~/([^?]+)/) { - $URLback=$1; - $URLback=~s|^/~|/priv/|; - } + $URLback=$helper->{'VARS'}->{'filename'}; } # # Final adjustment of the font size: @@ -2941,14 +3249,27 @@ 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'}; } + # Fullname may have special latex characters that need \ prefixing: # 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 @@ -2965,6 +3286,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}) { @@ -2974,10 +3296,13 @@ sub print_resources { } $current_output .= &get_extra_vspaces($helper, $curresline); $i++; - if ( !($type eq 'problems' && - ($curresline!~ m/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) ) { + ($curresline!~ m/$LONCAPA::assess_page_re/)) ) { 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)$/) { @@ -2991,6 +3316,7 @@ sub print_resources { $rendered = &print_latex_header().$rendered; } } +; if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { @@ -3002,6 +3328,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(); @@ -3073,9 +3401,23 @@ sub print_resources { } } $remove_latex_header = 'YES'; - } + } 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:/ @@ -3112,8 +3454,6 @@ sub handler { &init_perm(); - - my $helper = printHelper($r); if (!ref($helper)) { return $helper; @@ -3162,6 +3502,11 @@ sub init_perm { $perm{'pfo'}=&Apache::lonnet::allowed('pfo', $env{'request.course.id'}.'/'.$env{'request.course.sec'}); } + $perm{'vgr'}=&Apache::lonnet::allowed('vgr',$env{'request.course.id'}); + if (!$perm{'vgr'}) { + $perm{'vgr'}=&Apache::lonnet::allowed('vgr', + $env{'request.course.id'}.'/'.$env{'request.course.sec'}); + } } sub get_randomly_ordered_warning { @@ -3177,12 +3522,7 @@ sub get_randomly_ordered_warning { my $func = sub { return ($_[0]->is_map() && $_[0]->randomorder); }; my @matches = $navmap->retrieveResources($res, $func,1,1,1); - if (@matches) { - $message = "Some of the items below are in folders set to be randomly ordered. However, when printing the contents of these folders, they will be printed in the original order for all students, not the randomized order."; - } - } - if ($message) { - return ''.$message.''; + } } else { $message = "Retrieval of information about ordering of resources failed."; @@ -3272,8 +3612,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'}) { @@ -3309,6 +3649,8 @@ sub printHelper { my ($map, $id, $url); my $subdir; my $is_published=0; # True when printing from resource space. + my $res_printable = 1; # By default the current resource is printable. + my $userCanPrint = ($perm{'pav'} || $perm{'pfo'}); # Get the resource name from construction space if ($helper->{VARS}->{'construction'}) { @@ -3323,7 +3665,12 @@ sub printHelper { ($map, $id, $url) = &Apache::lonnet::decode_symb($symb); $helper->{VARS}->{'postdata'} = &Apache::lonenc::check_encrypt(&Apache::lonnet::clutter($url)); + my $navmap = Apache::lonnavmaps::navmap->new(); + my $res = $navmap->getBySymb($symb); + $res_printable = $res->resprintable() || $userCanPrint; #printability in course context } else { + # Resource space. + $url = $helper->{VARS}->{'postdata'}; $is_published=1; # From resource space. } @@ -3333,6 +3680,8 @@ sub printHelper { $resourceTitle = substr($postdata, rindex($postdata, '/') + 1); } $subdir = &Apache::lonnet::filelocation("", $url); + + } if (!$helper->{VARS}->{'curseed'} && $env{'form.curseed'}) { $helper->{VARS}->{'curseed'}=$env{'form.curseed'}; @@ -3362,18 +3711,29 @@ sub printHelper { my $printChoices = []; my $paramHash; - if ($resourceTitle) { + # If there is a current resource and it is printable + # Give that as a choice. + + if ($resourceTitle && $res_printable) { push @{$printChoices}, ["$resourceTitle (".&mt('the resource you just saw on the screen').")", 'current_document', 'PAGESIZE']; } + # Useful filter strings - my $isProblem = '($res->is_problem()||$res->contains_problem||$res->is_practice()) '; + + my $isPrintable = ' && $res->resprintable()'; + + my $isProblem = '(($res->is_problem()||$res->contains_problem() ||$res->is_practice()))'; + $isProblem .= $isPrintable unless $userCanPrint; $isProblem .= ' && !$res->randomout()' if !$userCanSeeHidden; - my $isProblemOrMap = '$res->is_problem() || $res->contains_problem() || $res->is_sequence() || $res->is_practice()'; - my $isNotMap = '!$res->is_sequence()'; + my $isProblemOrMap = '($res->is_problem() || $res->contains_problem() || $res->is_sequence() || $res->is_practice())'; + $isProblemOrMap .= $isPrintable unless $userCanPrint; + my $isNotMap = '(!$res->is_sequence())'; + $isNotMap .= $isPrintable unless $userCanPrint; $isNotMap .= ' && !$res->randomout()' if !$userCanSeeHidden; my $isMap = '$res->is_map()'; - my $symbFilter = '$res->shown_symb()'; + $isMap .= $isPrintable unless $userCanPrint; + my $symbFilter = '$res->shown_symb() '; my $urlValue = '$res->link()'; $helper->declareVar('SEQUENCE'); @@ -3453,6 +3813,34 @@ sub printHelper { if (($helper->{'VAR'}->{'construction'} ne '1' ) && $helper->{VARS}->{'postdata'} && $helper->{VARS}->{'assignment'}) { + + # BZ 5209 - Print incomplete problems from sequence: + # the exact form of this depends on whether or not we are privileged or a mere + # plebe of s student: + + my $printSelector = 'map_incomplete_problems_seq'; + my $nextState = 'CHOOSE_INCOMPLETE_SEQ'; + my $textSuffix = ''; + + if ($userCanPrint) { + $printSelector = 'map_incomplete_problems_people_seq'; + $nextState = 'CHOOSE_INCOMPLETE_PEOPLE_SEQ'; + $textSuffix = ' for selected students'; + my $helperStates = + &create_incomplete_folder_selstud_helper($helper, $map); + &Apache::lonxml::xmlparse($r, 'helper', $helperStates); + } else { + my $helperStates = &create_incomplete_folder_helper($helper, $map); # Create needed states for student. + &Apache::lonxml::xmlparse($r, 'helper', $helperStates); + } + + push(@{$printChoices}, + [&mt('Selected [_1]Incomplete Problems[_2] from folder [_3]' . $textSuffix, + '', '', + ''. $sequenceTitle . ''), + $printSelector, + $nextState]); + # Allow problems from sequence push @{$printChoices}, [&mt('Selected [_1]Problems[_2] from folder [_3]','','',''.$sequenceTitle.''), @@ -3487,9 +3875,21 @@ sub printHelper { # If the user has pfo (print for others) allow them to print all # problems and resources in the entire course, optionally for selected students my $post_data = $helper->{VARS}->{'postdata'}; + if ($perm{'pfo'} && !$is_published && ($post_data=~/\/res\// || $post_data =~/\/(syllabus|smppg|aboutme|bulletinboard)$/)) { + # BZ 5209 - incomplete problems from entire course: + + push(@{$printChoices}, + [&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. + + &Apache::lonxml::xmlparse($r, 'helper', $helperFragment); + + # Selected problems/resources from entire course: + push @{$printChoices}, [&mtn('Selected Problems from entire course'), 'all_problems', 'ALL_PROBLEMS']; push @{$printChoices}, [&mtn('Selected Resources from entire course'), 'all_resources', 'ALL_RESOURCES']; push @{$printChoices}, [&mtn('Selected Problems from entire course for selected people'), 'all_problems_students', 'ALL_PROBLEMS_STUDENTS']; @@ -3555,7 +3955,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. @@ -3574,27 +3974,10 @@ ALL_PROBLEMS $map, $isProblem, '', $symbFilter, $start_new_option); - $resource_selector .= < -
How should the results be printed?
- - Start each student\'s assignment on a new page/column (add a pagefeed after each assignment) - Add one empty page/column after each student\'s assignment - Add two empty pages/column after each student\'s assignment - Add three empty pages/column after each student\'s assignment - - PAGESIZE -
How do you want assignments split into PDF files?
- - All assignments in a single PDF file - Each PDF contains exactly one section - Each PDF contains exactly one assignment - - Specify the number of assignments per PDF: - - -RESOURCE_SELECTOR - $resource_selector .= &generate_resource_chooser('CHOOSE_STUDENTS_PAGE', + $resource_selector .= &generate_format_selector($helper, + 'How should results be printed?', + 'PRINT_FORMATTING'). + &generate_resource_chooser('CHOOSE_STUDENTS_PAGE', 'Select Problem(s) to print', "multichoice='1' addstatus='1' closeallpages ='1'", 'RESOURCES', @@ -3704,6 +4087,9 @@ RESOURCE_SELECTOR if ($helper->{VARS}->{'assignment'}) { + + # Assignment printing: + push @{$printChoices}, [&mt('Selected [_1]Resources[_2] from folder [_3] for [_4]selected people[_5]','','',''.$sequenceTitle.'','',''), 'resources_for_students', 'CHOOSE_STUDENTS1']; push @{$printChoices}, [&mt('Selected [_1]Resources[_2] from folder [_3] for [_4]CODEd assignments[_5]','','',''.$sequenceTitle.'','',''), 'resources_for_anon', 'CHOOSE_ANON2']; } @@ -3722,28 +4108,11 @@ RESOURCE_SELECTOR $start_new_option - - - NUMBER_PER_PDF -
How should the results be printed?
- - Start each student\'s assignment on a new page/column (add a pagefeed after each assignment) - Add one empty page/column after each student\'s assignment - Add two empty pages/column after each student\'s assignment - Add three empty pages/column after each student\'s assignment - - PAGESIZE -
How do you want assignments split into PDF files?
- - All assignments in a single PDF file - Each PDF contains exactly one section - Each PDF contains exactly one assignment - - Specify the number of assignments per PDF: - -
RESOURCE_SELECTOR + $resource_selector .= &generate_format_selector($helper, + 'Format of the print job', + 'PRINT_FORMATTING'); &Apache::lonxml::xmlparse($r, 'helper', < @@ -3784,7 +4153,7 @@ CHOOSE_STUDENTS1 - Bubble sheet type: + Bubblesheet type: $codechoice @@ -3901,7 +4270,7 @@ CHOOSE_FROM_ANY_SEQUENCE my $startedTable = 0; # have we started an HTML table yet? (need # to close it later) - if (($perm{'pav'} and &Apache::lonnet::allowed('vgr',$env{'request.course.id'})) or + if (($perm{'pav'} and $perm{'vgr'}) or ($helper->{VARS}->{'construction'} eq '1')) { &addMessage('
' .'

'.&mt('Print Options').'

' @@ -4148,10 +4517,12 @@ PROBTYPE return $helper; } - $r->print($helper->display()); + my $footer; if ($helper->{STATE} eq 'START') { - &recently_generated($r); + my $prtspool=$r->dir_config('lonPrtDir'); + $footer = &recently_generated($prtspool); } + $r->print($helper->display($footer)); &Apache::lonhelper::unregisterHelperTags(); return OK;