--- loncom/interface/lonprintout.pm 2006/07/03 10:25:07 1.453 +++ loncom/interface/lonprintout.pm 2008/09/21 21:25:21 1.536.2.1 @@ -1,7 +1,7 @@ # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.453 2006/07/03 10:25:07 foxr Exp $ +# $Id: lonprintout.pm,v 1.536.2.1 2008/09/21 21:25:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -22,7 +22,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt -# # http://www.lon-capa.org/ # # @@ -38,14 +37,254 @@ use Apache::grades; use Apache::edit; use Apache::File(); use Apache::lonnavmaps; -use Apache::lonratedt; +use Apache::admannotations; +use Apache::lonenc; +use Apache::entities; + +use HTTP::Response; + +use LONCAPA::map(); use POSIX qw(strftime); use Apache::lonlocal; use Carp; -use lib '/home/httpd/lib/perl/'; use LONCAPA; my %perm; +my %parmhash; +my $resources_printed; + +# Global variables that describe errors in ssi calls detected by ssi_with_retries. +# + +my $ssi_error; # True if there was an ssi error. +my $ssi_last_error_resource; # The resource URI that could not be fetched. +my $ssi_last_error; # The error text from the server. (e.g. 500 Server timed out). + +# +# Our ssi max retry count. +# + +my $ssi_retry_count = 5; # Some arbitrary value. + + + +# Fetch the contents of a resource, uninterpreted. +# This is used here to fetch a latex file to be included +# verbatim into the printout< +# NOTE: Ask Guy if there is a lonnet function similar to this? +# +# Parameters: +# URL of the file +# +sub fetch_raw_resource { + my ($url) = @_; + + my $filename = &Apache::lonnet::filelocation("", $url); + my $contents = &Apache::lonnet::getfile($filename); + + if ($contents == -1) { + return "File open failed for $filename"; # This will bomb the print. + } + return $contents; + + +} + +# Fetch the annotations associated with a URL and +# put a centered 'annotations:' title. +# This is all suppressed if the annotations are empty. +# +sub annotate { + my ($symb) = @_; + + my $annotation_text = &Apache::admannotations::get_annotation($symb, 1); + + + my $result = ""; + + if (length($annotation_text) > 0) { + $result .= '\\hspace*{\\fill} \\\\[\\baselineskip] \textbf{Annotations:} \\\\ '; + $result .= "\n"; + $result .= &Apache::lonxml::latex_special_symbols($annotation_text,""); # Escape latex. + $result .= "\n\n"; + } + return $result; +} + + +# +# ssi_with_retries - Does the server side include of a resource. +# if the ssi call returns an error we'll retry it up to +# the number of times requested by the caller. +# If we still have a proble, no text is appended to the +# output and we set some global variables. +# to indicate to the caller an SSI error occurred. +# All of this is supposed to deal with the issues described +# in LonCAPA BZ 5631 see: +# http://bugs.lon-capa.org/show_bug.cgi?id=5631 +# by informing the user that this happened. +# +# Parameters: +# resource - The resource to include. This is passed directly, without +# interpretation to lonnet::ssi. +# form - The form hash parameters that guide the interpretation of the resource +# +# retries - Number of retries allowed before giving up completely. +# Returns: +# On success, returns the rendered resource identified by the resource parameter. +# Side Effects: +# The following global variables can be set: +# ssi_error - If an unrecoverable error occurred this becomes true. +# It is up to the caller to initialize this to false +# if desired. +# ssi_last_error_resource - If an unrecoverable error occurred, this is the value +# of the resource that could not be rendered by the ssi +# call. +# ssi_last_error - The error string fetched from the ssi response +# in the event of an error. +# +sub ssi_with_retries { + my ($resource, $retries, %form) = @_; + + + my ($content, $response) = &Apache::loncommon::ssi_with_retries($resource, $retries, %form); + if (!$response->is_success) { + $ssi_error = 1; + $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; + +} + +sub get_student_view_with_retries { + my ($curresline,$retries,$username,$userdomain,$courseid,$target,$moreenv)=@_; + + my ($content, $response) = &Apache::loncommon::get_student_view_with_retries($curresline,$retries,$username,$userdomain,$courseid,$target,$moreenv); + if (!$response->is_success) { + $ssi_error = 1; + $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; + +} + +# +# printf_style_subst item format_string repl +# +# Does printf style substitution for a format string that +# can have %[n]item in it.. wherever, %[n]item occurs, +# rep is substituted in format_string. Note that +# [n] is an optional integer length. If provided, +# repl is truncated to at most [n] characters prior to +# substitution. +# +sub printf_style_subst { + my ($item, $format_string, $repl) = @_; + my $result = ""; + while ($format_string =~ /(%)(\d*)\Q$item\E/g ) { + my $fmt = $1; + my $size = $2; + my $subst = $repl; + if ($size ne "") { + $subst = substr($subst, 0, $size); + + # Here's a nice edge case.. supose the end of the + # substring is a \. In that case may have just + # chopped off a TeX escape... in that case, we append + # " " for the trailing character, and let the field + # spill over a bit (sigh). + # We don't just chop off the last character in order to deal + # with one last pathology, and that would be if substr had + # trimmed us to e.g. \\\ + + + if ($subst =~ /\\$/) { + $subst .= " "; + } + } + my $item_pos = pos($format_string); + $result .= substr($format_string, 0, $item_pos - length($size) -2) . $subst; + $format_string = substr($format_string, pos($format_string)); + } + + # Put the residual format string into the result: + + $result .= $format_string; + + return $result; +} + + +# Format a header according to a format. +# + +# Substitutions: +# %a - Assignment name. +# %c - Course name. +# %n - Student name. +# +sub format_page_header { + my ($width, $format, $assignment, $course, $student) = @_; + + $width = &recalcto_mm($width); # Get width in mm. + # Default format? + + if ($format eq '') { + # For the default format, we may need to truncate + # elements.. To do this we need to get the page width. + # we assume that each character is about 2mm in width. + # (correct for the header text size??). We ignore + # any formatting (e.g. boldfacing in this). + # + # - Allow the student/course to be one line. + # but only truncate the course. + # - Allow the assignment to be 2 lines (wrapped). + # + my $chars_per_line = $width/2; # Character/textline. + + + my $firstline = "$student $course"; + if (length($firstline) > $chars_per_line) { + my $lastchar = $chars_per_line - length($student) - 1; + if ($lastchar > 0) { + $course = substr($course, 0, $lastchar); + } else { # Nothing left of course: + $course = ''; + } + } + if (length($assignment) > $chars_per_line) { + $assignment = substr($assignment, 0, $chars_per_line); + } + + $format = "\\textbf{$student} $course \\hfill \\thepage \\\\ \\textit{$assignment}"; + + } else { + # An open question is how to handle long user formatted page headers... + # A possible future is to support e.g. %na so that the user can control + # the truncation of the elements that can appear in the header. + # + $format = &printf_style_subst("a", $format, $assignment); + $format = &printf_style_subst("c", $format, $course); + $format = &printf_style_subst("n", $format, $student); + + # If the user put %'s in the format string, they must be escaped + # to \% else LaTeX will think they are comments and terminate + # the line.. which is bad!!! + + + } + + + return $format; + +} # # Convert a numeric code to letters @@ -63,7 +302,7 @@ sub num_to_letters { sub letters_to_num { my ($letters) = @_; my @letters = split('', uc($letters)); - my %substitution; + my %substitution; my $digit = 0; foreach my $letter ('A'..'J') { $substitution{$letter} = $digit; @@ -265,12 +504,19 @@ sub adjust_number_to_print { # Unmodified. } else { # Error!!!! - + croak "bad SPLIT_PDFS: $split_pdf in lonprintout::adjust_number_to_print"; + } } + sub character_chart { + my $result = shift; + return &Apache::entities::replace_entities($result); +} + +sub old_character_chart { my $result = shift; $result =~ s/&\#0?0?(7|9);//g; $result =~ s/&\#0?(10|13);//g; @@ -378,7 +624,7 @@ sub character_chart { $result =~ s/&\#147;/\`\`/g; $result =~ s/&\#148;/\'\'/g; $result =~ s/&\#149;/\\ensuremath\{\\bullet\}/g; - $result =~ s/&\#150;/--/g; + $result =~ s/&(\#150|\#8211);/--/g; $result =~ s/&\#151;/---/g; $result =~ s/&\#152;/\\ensuremath\{\\sim\}/g; $result =~ s/&\#153;/\\texttrademark /g; @@ -392,7 +638,7 @@ sub character_chart { $result =~ s/&(\#165|yen);/\\textyen /g; $result =~ s/&(\#166|brvbar);/\\textbrokenbar /g; $result =~ s/&(\#167|sect);/\\textsection /g; - $result =~ s/&(\#168|uml);/\\texthighdieresis /g; + $result =~ s/&(\#168|uml);/\\"\{\} /g; $result =~ s/&(\#169|copy);/\\copyright /g; $result =~ s/&(\#170|ordf);/\\textordfeminine /g; $result =~ s/&(\#172|not);/\\ensuremath\{\\neg\}/g; @@ -403,7 +649,7 @@ sub character_chart { $result =~ s/&(\#177|plusmn);/\\ensuremath\{\\pm\}/g; $result =~ s/&(\#178|sup2);/\\ensuremath\{^2\}/g; $result =~ s/&(\#179|sup3);/\\ensuremath\{^3\}/g; - $result =~ s/&(\#180|acute);/\\textacute /g; + $result =~ s/&(\#180|acute);/\\'\{\} /g; $result =~ s/&(\#181|micro);/\\ensuremath\{\\mu\}/g; $result =~ s/&(\#182|para);/\\P/g; $result =~ s/&(\#183|middot);/\\ensuremath\{\\cdot\}/g; @@ -585,6 +831,28 @@ sub character_chart { $result =~ s/&(clubs|\#9827);/\\ensuremath\{\\clubsuit\}/g; $result =~ s/&(hearts|\#9829);/\\ensuremath\{\\heartsuit\}/g; $result =~ s/&(diams|\#9830);/\\ensuremath\{\\diamondsuit\}/g; +# Chemically useful 'things' contributed by Hon Kie (bug 4652). + + $result =~ s/&\#8636;/\\ensuremath\{\\leftharpoonup\}/g; + $result =~ s/&\#8637;/\\ensuremath\{\\leftharpoondown\}/g; + $result =~ s/&\#8640;/\\ensuremath\{\\rightharpoonup\}/g; + $result =~ s/&\#8641;/\\ensuremath\{\\rightharpoondown\}/g; + $result =~ s/&\#8652;/\\ensuremath\{\\rightleftharpoons\}/g; + $result =~ s/&\#8605;/\\ensuremath\{\\leadsto\}/g; + $result =~ s/&\#8617;/\\ensuremath\{\\hookleftarrow\}/g; + $result =~ s/&\#8618;/\\ensuremath\{\\hookrightarrow\}/g; + $result =~ s/&\#8614;/\\ensuremath\{\\mapsto\}/g; + $result =~ s/&\#8599;/\\ensuremath\{\\nearrow\}/g; + $result =~ s/&\#8600;/\\ensuremath\{\\searrow\}/g; + $result =~ s/&\#8601;/\\ensuremath\{\\swarrow\}/g; + $result =~ s/&\#8598;/\\ensuremath\{\\nwarrow\}/g; + + # Left/right quotations: + + $result =~ s/&(ldquo|#8220);/\`\`/g; + $result =~ s/&(rdquo|#8221);/\'\'/g; + + return $result; } @@ -593,18 +861,18 @@ sub character_chart { my %page_formats= ('letter' => { 'book' => { - '1' => [ '7.1 in','9.8 in', '-0.57 in','-0.57 in','0.7 cm'], - '2' => ['3.66 in','9.8 in', '-0.57 in','-0.57 in','0.7 cm'] + '1' => [ '7.1 in','9.8 in', '-0.57 in','-0.57 in','0.275 in'], + '2' => ['3.66 in','9.8 in', '-0.57 in','-0.57 in','0.275 in'] }, 'album' => { - '1' => [ '8.8 in', '6.8 in','-40 pt in', '-60 pt','1 cm'], - '2' => [ '4.4 in', '6.8 in','-0.5 in', '-1.5 in','3.5 in'] + '1' => [ '8.8 in', '6.8 in','-0.55 in', '-0.55 in','0.394 in'], + '2' => [ '4.8 in', '6.8 in','-0.5 in', '-1.0 in','3.5 in'] }, }, 'legal' => { 'book' => { '1' => ['7.1 in','13 in',,'-0.57 in','-0.57 in','-0.5 in'], - '2' => ['3.16 in','13 in','-0.57 in','-0.57 in','-0.5 in'] + '2' => ['3.66 in','13 in','-0.57 in','-0.57 in','-0.5 in'] }, 'album' => { '1' => ['12 in','7.1 in',,'-0.57 in','-0.57 in','-0.5 in'], @@ -653,12 +921,12 @@ my %page_formats= }, 'a4' => { 'book' => { - '1' => ['176 mm','272 mm','-40 pt in','-60 pt','-0.5 in'], - '2' => [ '91 mm','272 mm','-40 pt in','-60 pt','-0.5 in'] + '1' => ['17.6 cm','27.2 cm','-1.397 cm','-2.11 cm','-1.27 cm'], + '2' => [ '9.1 cm','27.2 cm','-1.397 cm','-2.11 cm','-1.27 cm'] }, 'album' => { - '1' => ['8.5 in','7.7 in','-40 pt in','-60 pt','0 in'], - '2' => ['3.9 in','7.7 in','-40 pt in','-60 pt','0 in'] + '1' => ['21.59 cm','19.558 cm','-1.397cm','-2.11 cm','0 cm'], + '2' => ['9.91 cm','19.558 cm','-1.397 cm','-2.11 cm','0 cm'] }, }, 'a5' => { @@ -717,22 +985,32 @@ sub get_course { sub page_format_transformation { my ($papersize,$layout,$numberofcolumns,$choice,$text,$assignment,$tableofcontents,$indexlist,$selectionmade) = @_; my ($textwidth,$textheight,$oddoffset,$evenoffset,$topmargin); + if ($selectionmade eq '4') { - $assignment='Problems from the Whole Course'; + if ($choice eq 'all_problems') { + $assignment='Problems from the Whole Course'; + } else { + $assignment='Resources from the Whole Course'; + } } else { $assignment=&Apache::lonxml::latex_special_symbols($assignment,'header'); } ($textwidth,$textheight,$oddoffset,$evenoffset,$topmargin) = &page_format($papersize,$layout,$numberofcolumns,$topmargin); + + my $name = &get_name(); my $courseidinfo = &get_course(); if (defined($courseidinfo)) { $courseidinfo=' - '.$courseidinfo } + my $header_text = $parmhash{'print_header_format'}; + $header_text = &format_page_header($textwidth, $header_text, $assignment, + $courseidinfo, $name); my $topmargintoinsert = ''; if ($topmargin ne '0') {$topmargintoinsert='\setlength{\topmargin}{'.$topmargin.'}';} my $fancypagestatement=''; if ($numberofcolumns eq '2') { - $fancypagestatement="\\fancyhead{}\\fancyhead[LO]{\\textbf{$name} $courseidinfo \\hfill \\thepage \\\\ \\textit{$assignment}}"; + $fancypagestatement="\\fancyhead{}\\fancyhead[LO]{$header_text}"; } else { - $fancypagestatement="\\rhead{}\\chead{}\\lhead{\\textbf{$name} $courseidinfo \\hfill \\thepage \\\\ \\textit{$assignment}}"; + $fancypagestatement="\\rhead{}\\chead{}\\lhead{$header_text}"; } if ($layout eq 'album') { $text =~ s/\\begin{document}/\\setlength{\\oddsidemargin}{$oddoffset}\\setlength{\\evensidemargin}{$evenoffset}$topmargintoinsert\n\\setlength{\\textwidth}{$textwidth}\\setlength{\\textheight}{$textheight}\\setlength{\\textfloatsep}{8pt plus 2\.0pt minus 4\.0pt}\n\\newlength{\\minipagewidth}\\setlength{\\minipagewidth}{\\textwidth\/\$number_of_columns-0\.2cm}\\usepackage{fancyhdr}\\addtolength{\\headheight}{\\baselineskip}\n\\pagestyle{fancy}$fancypagestatement\\begin{document}\\voffset=-0\.8 cm\\setcounter{page}{1}\n /; @@ -775,6 +1053,8 @@ sub details_for_menu { if (!$postdata) { $postdata=$helper->{VARS}{'postdata'}; } my $name_of_resource = &Apache::lonnet::gettitle($postdata); my $symbolic = &Apache::lonnet::symbread($postdata); + return if ( $symbolic eq ''); + my ($map,$id,$resource)=&Apache::lonnet::decode_symb($symbolic); $map=&Apache::lonnet::clutter($map); my $name_of_sequence = &Apache::lonnet::gettitle($map); @@ -790,16 +1070,21 @@ sub details_for_menu { return ($name_of_resource,$name_of_sequence,$name_of_map); } +sub copyright_line { + return '\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\vspace*{-2 mm}\newline\noindent{\tiny Printed from LON-CAPA\copyright MSU{\hfill} Licensed under GNU General Public License } '; +} +my $end_of_student = "\n".'\special{ps:ENDOFSTUDENTSTAMP}'."\n"; sub latex_corrections { my ($number_of_columns,$result,$selectionmade,$answer_mode) = @_; # $result =~ s/\\includegraphics{/\\includegraphics\[width=\\minipagewidth\]{/g; - $result =~ s/\$number_of_columns/$number_of_columns/g; + my $copyright = ©right_line(); if ($selectionmade eq '1' || $answer_mode eq 'only') { - $result =~ s/(\\end{document})/\\strut\\vskip 0 mm\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill}\\newline\\noindent\\tiny Printed from LON-CAPA\\copyright MSU{\\hfill} Licensed under GNU General Public License $1/; + $result =~ s/(\\end{document})/\\strut\\vskip 0 mm $copyright $end_of_student $1/; } else { - $result =~ s/(\\end{document})/\\strut\\vspace\*{-4 mm}\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill}\\newline\\noindent\\tiny Printed from LON-CAPA\\copyright MSU{\\hfill} Licensed under GNU General Public License $1/; + $result =~ s/(\\end{document})/\\strut\\vspace\*{-4 mm}\\newline $copyright $end_of_student $1/; } + $result =~ s/\$number_of_columns/$number_of_columns/g; $result =~ s/(\\end{longtable}\s*)(\\strut\\newline\\noindent\\makebox\[\\textwidth\/$number_of_columns\]\[b\]{\\hrulefill})/$2$1/g; $result =~ s/(\\end{longtable}\s*)\\strut\\newline/$1/g; #-- LaTeX corrections @@ -856,7 +1141,7 @@ sub IndexCreation { sub print_latex_header { my $mode=shift; - my $output='\documentclass[letterpaper,twoside]{article}'; + my $output='\documentclass[letterpaper,twoside]{article}\raggedbottom'; if (($mode eq 'batchmode') || (!$perm{'pav'})) { $output.='\batchmode'; } @@ -866,6 +1151,16 @@ sub print_latex_header { '\usepackage[dvips]{graphicx}\usepackage{epsfig}'."\n". '\usepackage{wrapfig}'. '\usepackage{picins}\usepackage{calc}'."\n". + '\usepackage[T1]{fontenc}'."\n". + '\usepackage[postscript]{ucs}'."\n". + '\usepackage[utf8x]{inputenc}'."\n". + '\usepackage{pifont}' . "\n". + '\usepackage{latexsym}'."\n". + '\usepackage{amsmath}'. + '\usepackage{amssymb}'. + '\usepackage{amsfonts}'. + '\usepackage{amsthm}'. + '\usepackage{amscd}'. '\newenvironment{choicelist}{\begin{list}{}{\setlength{\rightmargin}{0in}'."\n". '\setlength{\leftmargin}{0.13in}\setlength{\topsep}{0.05in}'."\n". '\setlength{\itemsep}{0.022in}\setlength{\parsep}{0in}'."\n". @@ -1020,10 +1315,114 @@ sub get_page_breaks { return %page_breaks; } +# Output a sequence (recursively if neeed) +# from construction space. +# Parameters: +# url = URL of the sequence to print. +# helper - Reference to the helper hash. +# form - Copy of the format hash. +# LaTeXWidth +# Returns: +# Text to add to the printout. +# NOTE if the first element of the outermost sequence +# is itself a sequence, the outermost caller may need to +# prefix the latex with the page headers stuff. +# +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); + # + # 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; + if ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { + my $texversion=''; + if ($helper->{'VARS'}->{'ANSWER_TYPE'} ne 'only') { + $form{'problem_split'}=$parmhash{'problem_stream_switch'}; + $form{'suppress_tries'}=$parmhash{'suppress_tries'}; + $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; + $form{'rndseed'}=$rndseed; + $resources_printed .=$urlp.':'; + $texversion=&ssi_with_retries($urlp, $ssi_retry_count, %form); + } + if((($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || + ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) && + ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) { + # Don't permanently modify %$form... + my %answerform = %form; + $answerform{'grade_target'}='answer'; + $answerform{'answer_output_mode'}='tex'; + $answerform{'rndseed'}=$rndseed; + $answerform{'problem_split'}=$parmhash{'problem_stream_switch'}; + if ($urlp=~/\/res\//) {$env{'request.state'}='published';} + $resources_printed .= $urlp.':'; + my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); + if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { + $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; + } else { + # If necessary, encapsulate answer in minipage: + + $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); + my $title = &Apache::lonnet::gettitle($helper->{'VARS'}->{'symb'}); + $title = &Apache::lonxml::latex_special_symbols($title); + my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; + $body.=&path_to_problem($urlp,$LaTeXwidth); + $body.='\vskip 1 mm '.$answer.'\end{document}'; + $body = &encapsulate_minipage($body); + $texversion.=$body; + } + } + $texversion = &latex_header_footer_remove($texversion); + + if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { + $texversion=&IndexCreation($texversion,$urlp); + } + if ($helper->{'VARS'}->{'CONSTR_RESOURSE_URL'} eq 'yes') { + $texversion=~s/(\\addcontentsline\{toc\}\{subsection\}\{[^\}]*\})/$1 URL: \\verb|$urlp| \\strut\\\\\\strut /; + } + $result.=$texversion; + + } elsif ($urlp=~/\.(sequence|page)$/) { + + # header: + + $result.='\strut\newline\noindent Sequence/page '.$urlp.'\strut\newline\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\newline\noindent '; + + # 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, + $helper, %form, + $LaTeXwidth); + } + } + } + if ($helper->{VARS}->{'construction'} eq '1') {$result=~s/(\\begin{document})/$1 \\fbox\{RANDOM SEED IS $rndseed\} /;} + return $result; +} + sub output_data { my ($r,$helper,$rparmhash) = @_; my %parmhash = %$rparmhash; - my $resources_printed = ''; + $ssi_error = 0; # This will be set nonzero by failing ssi's. + $resources_printed = ''; + my $do_postprocessing = 1; my $js = < var editbrowser; @@ -1051,6 +1450,8 @@ sub output_data { ENDPART + + my $start_page = &Apache::loncommon::start_page('Preparing Printout',$js); my $msg = &mt('Please stand by while processing your print request, this may take some time ...'); @@ -1084,6 +1485,7 @@ ENDPART my @print_array=(); my @student_names=(); + # Common settings for the %form has: # In some cases these settings get overriddent by specific cases, but the # settings are common enough to make it worthwhile factoring them out @@ -1103,6 +1505,14 @@ ENDPART if ($helper->{'VARS'}->{'showallfoils'} eq "1") { $form{'showallfoils'} = $helper->{'VARS'}->{'showallfoils'}; } + + if ($helper->{'VARS'}->{'style_file'}=~/\w/) { + &Apache::lonnet::appenv({'construct.style' => + $helper->{'VARS'}->{'style_file'}}); + } elsif ($env{'construct.style'}) { + &Apache::lonnet::delenv('construct\\.style'); + } + if ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'current_document') { #-- single document - problem, page, html, xml, ... @@ -1113,6 +1523,7 @@ ENDPART $currentURL=$helper->{'VARS'}->{'postdata'}; $cleanURL=&Apache::lonenc::check_decrypt($currentURL); } else { + #prints resource from the construction space $currentURL='/'.$helper->{'VARS'}->{'filename'}; if ($currentURL=~/([^?]+)/) {$currentURL=$1;} @@ -1126,29 +1537,29 @@ ENDPART if ($helper->{'VARS'}->{'ANSWER_TYPE'} ne 'only') { my %moreenv; $moreenv{'request.filename'}=$cleanURL; - if ($helper->{'VARS'}->{'style_file'}=~/\w/) { - $moreenv{'construct.style'}=$helper->{'VARS'}->{'style_file'}; - my $dom = $env{'user.domain'}; - my $user = $env{'user.name'}; - my $put_result = &Apache::lonnet::put('environment',{'construct.style'=>$helper->{'VARS'}->{'style_file'}},$dom,$user); - } if ($helper->{'VARS'}->{'probstatus'} eq 'exam') {$form{'problemtype'}='exam';} $form{'problem_split'}=$parmhash{'problem_stream_switch'}; $form{'suppress_tries'}=$parmhash{'suppress_tries'}; $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; $form{'print_discussions'}=$helper->{'VARS'}->{'PRINT_DISCUSSIONS'}; - if ($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') {$form{'problem_split'}='yes';} + $form{'print_annotations'}=$helper->{'VARS'}->{'PRINT_ANNOTATIONS'}; + if (($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') || + ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes')) { + $form{'problem_split'}='yes'; + } if ($helper->{'VARS'}->{'curseed'}) { $rndseed=$helper->{'VARS'}->{'curseed'}; } $form{'rndseed'}=$rndseed; - &Apache::lonnet::appenv(%moreenv); + &Apache::lonnet::appenv(\%moreenv); &Apache::lonxml::clear_problem_counter(); $resources_printed .= $currentURL.':'; - $texversion.=&Apache::lonnet::ssi($currentURL,%form); + $texversion.=&ssi_with_retries($currentURL,$ssi_retry_count, %form); + # Add annotations if required: + &Apache::lonxml::clear_problem_counter(); &Apache::lonnet::delenv('request.filename'); @@ -1166,23 +1577,40 @@ ENDPART $form{'problemtype'}='exam'; } $resources_printed .= $currentURL.':'; - my $answer=&Apache::lonnet::ssi($currentURL,%form); + my $answer=&ssi_with_retries($currentURL,$ssi_retry_count, %form); + + if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; } else { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); if ($helper->{'VARS'}->{'construction'} ne '1') { - $texversion.='\vskip 0 mm \noindent\textbf{'.&Apache::lonnet::gettitle($helper->{'VARS'}->{'symb'}).'}\vskip 0 mm '; + my $title = &Apache::lonnet::gettitle($helper->{'VARS'}->{'symb'}); + $title = &Apache::lonxml::latex_special_symbols($title); + $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.=&path_to_problem($URLpath,$LaTeXwidth); } $texversion.='\vskip 1 mm '.$answer.'\end{document}'; } + + + + } + # Print annotations. + + + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $annotation .= &annotate($currentURL); + $texversion =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + } + + if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { $texversion=&IndexCreation($texversion,$currentURL); } @@ -1197,76 +1625,38 @@ ENDPART } elsif ($cleanURL!~m|^/adm/| && $currentURL=~/\.sequence$/ && $helper->{'VARS'}->{'construction'} eq '1') { #printing content of sequence from the construction space - my $flag_latex_header_remove = 'NO'; - my $rndseed=time; - if ($helper->{'VARS'}->{'curseed'}) { - $rndseed=$helper->{'VARS'}->{'curseed'}; - } $currentURL=~s|\/~([^\/]+)\/|\/home\/$1\/public_html\/|; - my $errtext=&Apache::lonratedt::mapread($currentURL); - for (my $member=0;$member<=$#Apache::lonratedt::order;$member++) { - $Apache::lonratedt::resources[$Apache::lonratedt::order[$member]]=~/^([^:]*):([^:]*):/; - my $urlp=$2; - if ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm)$/) { - my $texversion=''; - if ($helper->{'VARS'}->{'ANSWER_TYPE'} ne 'only') { - $form{'problem_split'}=$parmhash{'problem_stream_switch'}; - $form{'suppress_tries'}=$parmhash{'suppress_tries'}; - $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; - $form{'rndseed'}=$rndseed; - $resources_printed .=$urlp.':'; - $texversion=&Apache::lonnet::ssi($urlp,%form); - } - if((($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || - ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) && - ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page)$/)) { - # Don't permanently modify %$form... - my %answerform = %form; - $answerform{'grade_target'}='answer'; - $answerform{'answer_output_mode'}='tex'; - $answerform{'rndseed'}=$rndseed; - $answerform{'problem_split'}=$parmhash{'problem_stream_switch'}; - if ($urlp=~/\/res\//) {$env{'request.state'}='published';} - $resources_printed .= $urlp.':'; - my $answer=&Apache::lonnet::ssi($urlp,%answerform); - if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { - $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; - } else { - # If necessary, encapsulate answer in minipage: - - $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); - my $body ='\vskip 0 mm \noindent\textbf{'.&Apache::lonnet::gettitle($helper->{'VARS'}->{'symb'}).'}\vskip 0 mm '; - $body.=&path_to_problem($urlp,$LaTeXwidth); - $body.='\vskip 1 mm '.$answer.'\end{document}'; - $body = &encapsulate_minipage($body); - $texversion.=$body; - } - } - if ($flag_latex_header_remove ne 'NO') { - $texversion = &latex_header_footer_remove($texversion); - } else { - $texversion =~ s/\\end{document}//; - } - if ($helper->{'VARS'}->{'TABLE_INDEX'} eq 'yes') { - $texversion=&IndexCreation($texversion,$urlp); - } - if ($helper->{'VARS'}->{'CONSTR_RESOURSE_URpL'} eq 'yes') { - $texversion=~s/(\\addcontentsline\{toc\}\{subsection\}\{[^\}]*\})/$1 URL: \\verb|$urlp| \\strut\\\\\\strut /; - } - $result.=$texversion; - $flag_latex_header_remove = 'YES'; - } elsif ($urlp=~/\.(sequence|page)$/) { - $result.='\strut\newline\noindent Sequence/page '.$urlp.'\strut\newline\noindent\makebox[\textwidth/$number_of_columns][b]{\hrulefill}\newline\noindent '; - } - } - if ($helper->{VARS}->{'construction'} eq '1') {$result=~s/(\\begin{document})/$1 \\fbox\{RANDOM SEED IS $rndseed\} /;} - $result .= '\end{document}'; - } elsif ($cleanURL=~/\/(smppg|grppg|syllabus|aboutme|bulletinboard)$/) { + $result .= &print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); + $result .= &print_construction_sequence($currentURL, $helper, %form, + $LaTeXwidth); + $result .= '\end{document}'; + if (!($result =~ /\\begin\{document\}/)) { + $result = &print_latex_header() . $result; + } + # End construction space sequence. + } elsif ($cleanURL=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; if ($currentURL=~/\/syllabus$/) {$currentURL=~s/\/res//;} $resources_printed .= $currentURL.':'; - my $texversion=&Apache::lonnet::ssi($currentURL,%form); + my $texversion=&ssi_with_retries($currentURL, $ssi_retry_count, %form); + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $annotation = &annotate($currentURL); + $texversion =~ s/(\\end{document})/$annotation$1/; + } $result .= $texversion; + } elsif ($cleanURL =~/.tex$/) { + # For this sort of print of a single LaTeX file, + # We can just print the LaTeX file as it is uninterpreted in any way: + # + + $result = &fetch_raw_resource($currentURL); + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $annotation = &annotate($currentURL); + $result =~ s/(\\end{document})/$annotation$1/; + } + + $do_postprocessing = 0; # Don't massage the result. + } else { $result.=&unsupported($currentURL,$helper->{'VARS'}->{'LATEX_TYPE'}, $helper->{'VARS'}->{'symb'}); @@ -1275,13 +1665,17 @@ ENDPART ($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')) { + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'select_sequences') + ) { + + #-- produce an output string if ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems') { $selectionmade = 2; } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'map_problems_pages') { $selectionmade = 3; - } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems') { + } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems') + ) { $selectionmade = 4; } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_resources') { #BUGBUG $selectionmade = 4; @@ -1292,7 +1686,11 @@ ENDPART $form{'suppress_tries'}=$parmhash{'suppress_tries'}; $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; $form{'print_discussions'}=$helper->{'VARS'}->{'PRINT_DISCUSSIONS'}; - if ($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') {$form{'problem_split'}='yes';} + $form{'print_annotations'} = $helper->{'VARS'}->{'PRINT_ANNOTATIONS'}; + if (($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') || + ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') ) { + $form{'problem_split'}='yes'; + } my $flag_latex_header_remove = 'NO'; my $flag_page_in_sequence = 'NO'; my @master_seq=split /\|\|\|/, $helper->{'VARS'}->{'RESOURCES'}; @@ -1303,6 +1701,9 @@ ENDPART my $pbreakresources = keys %page_breaks; for (my $i=0;$i<=$#master_seq;$i++) { + &Apache::lonenc::reset_enc(); + + # Note due to document structure, not allowed to put \newpage # prior to the first resource @@ -1311,20 +1712,21 @@ ENDPART $result.="\\newpage\n"; } } - my ($sequence,undef,$urlp)=&Apache::lonnet::decode_symb($master_seq[$i]); + my ($sequence,$middle_thingy,$urlp)=&Apache::lonnet::decode_symb($master_seq[$i]); $urlp=&Apache::lonnet::clutter($urlp); $form{'symb'}=$master_seq[$i]; + my $assignment=&Apache::lonxml::latex_special_symbols(&Apache::lonnet::gettitle($sequence),'header'); #title of the assignment which contains this problem + if ($selectionmade==7) {$helper->{VARS}->{'assignment'}=$assignment;} if ($i==0) {$prevassignment=$assignment;} my $texversion=''; if ($urlp!~m|^/adm/| && $urlp=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)$/) { $resources_printed .= $urlp.':'; - &Apache::lonxml::remember_problem_counter(); - $texversion.=&Apache::lonnet::ssi($urlp,%form); + $texversion.=&ssi_with_retries($urlp, $ssi_retry_count, %form); if ($urlp=~/\.page$/) { ($texversion,my $number_of_columns_page) = &page_cleanup($texversion); if ($number_of_columns_page > $number_of_columns) {$number_of_columns=$number_of_columns_page;} @@ -1341,14 +1743,16 @@ ENDPART $resources_printed .= $urlp.':'; &Apache::lonxml::restore_problem_counter(); - my $answer=&Apache::lonnet::ssi($urlp,%answerform); + my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; } else { if ($urlp=~/\.(problem|exam|quiz|assess|survey|form|library)$/) { $texversion=&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); - my $body ='\vskip 0 mm \noindent\textbf{'.&Apache::lonnet::gettitle($master_seq[$i]).'}\vskip 0 mm '; + my $title = &Apache::lonnet::gettitle($master_seq[$i]); + $title = &Apache::lonxml::latex_special_symbols($title); + my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; $body .= &path_to_problem ($urlp,$LaTeXwidth); $body .='\vskip 1 mm '.$answer; $body = &encapsulate_minipage($body); @@ -1357,7 +1761,13 @@ ENDPART $texversion=''; } } + } + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $annotation .= &annotate($urlp); + $texversion =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + } + if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { @@ -1371,19 +1781,29 @@ ENDPART my $courseidinfo = &get_course(); if (defined($courseidinfo)) { $courseidinfo=' - '.$courseidinfo } $prevassignment=$assignment; + my $header_text = $parmhash{'print_header_format'}; + $header_text = &format_page_header($textwidth, $header_text, + $assignment, + $courseidinfo, + $name); if ($numberofcolumns eq '1') { - $result .='\newpage \noindent\parbox{\minipagewidth}{\noindent\\lhead{\\textit{\\textbf{'.$name.'}}'.$courseidinfo.' \\hfill \\thepage \\\\ \\textit{'.$assignment.'}}} \vskip 5 mm '; + $result .='\newpage \noindent\parbox{\minipagewidth}{\noindent\\lhead{'.$header_text.'}} \vskip 5 mm '; } else { - $result .='\newpage \noindent\parbox{\minipagewidth}{\noindent\\fancyhead[LO]{\\textit{\\textbf{'.$name.'}}'.$courseidinfo.' \\hfill \\thepage \\\\ \\textit{'.$assignment.'}}} \vskip 5 mm '; + $result .='\newpage \noindent\parbox{\minipagewidth}{\noindent\\fancyhead[LO]{'.$header_text.'}} \vskip 5 mm '; } } $result .= $texversion; $flag_latex_header_remove = 'YES'; - } elsif ($urlp=~/\/(smppg|grppg|syllabus|aboutme|bulletinboard)$/) { + } elsif ($urlp=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { $form{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; if ($urlp=~/\/syllabus$/) {$urlp=~s/\/res//;} $resources_printed .= $urlp.':'; - my $texversion=&Apache::lonnet::ssi($urlp,%form); + my $texversion=&ssi_with_retries($urlp, $ssi_retry_count, %form); + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $annotation = &annotate($urlp); + $texversion =~ s/(\\end{document)/$annotation$1/; + } + if ($flag_latex_header_remove ne 'NO') { $texversion = &latex_header_footer_remove($texversion); } else { @@ -1410,12 +1830,14 @@ ENDPART } $result .= '\end{document}'; } elsif (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students') || + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems_students') || ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_students')){ #-- prints assignments for whole class or for selected students my $type; - if ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students') { + if (($helper->{'VARS'}->{'PRINT_TYPE'} eq 'problems_for_students') || + ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'all_problems_students') ) { $selectionmade=5; $type='problems'; } elsif ($helper->{'VARS'}->{'PRINT_TYPE'} eq 'resources_for_students') { @@ -1459,9 +1881,13 @@ ENDPART $moreenv{'instructor_comments'}='hide'; $moreenv{'textwidth'}=&get_textwidth($helper,$LaTeXwidth); $moreenv{'print_discussions'}=$helper->{'VARS'}->{'PRINT_DISCUSSIONS'}; + $moreenv{'print_annotations'} = $helper->{'VARS'}->{'PRINT_ANNOTATIONS'}; $moreenv{'problem_split'} = $parmhash{'problem_stream_switch'}; $moreenv{'suppress_tries'} = $parmhash{'suppress_tries'}; - if ($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') {$moreenv{'problem_split'}='yes';} + if (($helper->{'VARS'}->{'PRINT_DISCUSSIONS'} eq 'yes') || + ($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 $student_counter=-1; my $i = 0; @@ -1601,6 +2027,9 @@ ENDPART $rndseed=$helper->{'VARS'}->{'curseed'}; } for (my $i=0;$i<=$#list_of_files;$i++) { + + &Apache::lonenc::reset_enc(); + my $urlp = $list_of_files[$i]; $urlp=~s|//|/|; if ($urlp=~/\//) { @@ -1612,7 +2041,7 @@ ENDPART $urlp =~ s|^$Apache::lonnet::perlvar{'lonDocRoot'}||; } $resources_printed .= $urlp.':'; - my $texversion=&Apache::lonnet::ssi($urlp,%form); + my $texversion=&ssi_with_retries($urlp, $ssi_retry_count, %form); if(($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) { # Don't permanently pervert %form: @@ -1622,7 +2051,7 @@ ENDPART $answerform{'latex_type'}=$helper->{'VARS'}->{'LATEX_TYPE'}; $answerform{'rndseed'}=$rndseed; $resources_printed .= $urlp.':'; - my $answer=&Apache::lonnet::ssi($urlp,%answerform); + my $answer=&ssi_with_retries($urlp, $ssi_retry_count, %answerform); if ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') { $texversion=~s/(\\keephidden{ENDOFPROBLEM})/$answer$1/; } else { @@ -1639,7 +2068,8 @@ ENDPART $texversion.='\vskip 1 mm '.$answer.'\end{document}'; } } - #this chunck is responsible for printing the path to problem + #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); @@ -1664,20 +2094,33 @@ ENDPART $result .= '\end{document}'; } #-------------------------------------------------------- corrections for the different page formats - $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 = &latex_corrections($number_of_columns,$result,$selectionmade, - $helper->{'VARS'}->{'ANSWER_TYPE'}); - for (my $i=1;$i<=$#print_array;$i++) { - $print_array[$i] = - &latex_corrections($number_of_columns,$print_array[$i], - $selectionmade, - $helper->{'VARS'}->{'ANSWER_TYPE'}); - } - if ($numberofcolumns == 1) { + + # 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 = &latex_corrections($number_of_columns,$result,$selectionmade, + $helper->{'VARS'}->{'ANSWER_TYPE'}); + #if ($numberofcolumns == 1) { $result =~ s/\\textwidth\s*=\s*-?\d*\.?\d*\s*(cm|mm|in)/\\textwidth= $helper->{'VARS'}->{'pagesize.width'} $helper->{'VARS'}->{'pagesize.widthunit'} /; $result =~ s/\\textheight\s*=?\s*-?\d*\.?\d*\s*(cm|mm|in)/\\textheight $helper->{'VARS'}->{'pagesize.height'} $helper->{'VARS'}->{'pagesize.heightunit'} /; $result =~ s/\\evensidemargin\s*=\s*-?\d*\.?\d*\s*(cm|mm|in)/\\evensidemargin= $helper->{'VARS'}->{'pagesize.lmargin'} $helper->{'VARS'}->{'pagesize.lmarginunit'} /; $result =~ s/\\oddsidemargin\s*=\s*-?\d*\.?\d*\s*(cm|mm|in)/\\oddsidemargin= $helper->{'VARS'}->{'pagesize.lmargin'} $helper->{'VARS'}->{'pagesize.lmarginunit'} /; + #} + } + + # Set URLback if this is a construction space print so we can provide + # a link to the resource being edited. + # + + 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/|; + } } #-- writing .tex file in prtspool @@ -1685,92 +2128,100 @@ ENDPART my $identifier = &Apache::loncommon::get_cgi_id(); my $filename = "/home/httpd/prtspool/$env{'user.name'}_$env{'user.domain'}_printout_$identifier.tex"; if (!($#print_array>0)) { - unless ($temp_file = Apache::File->new('>'.$filename)) { - $r->log_error("Couldn't open $filename for output $!"); - return SERVER_ERROR; - } - print $temp_file $result; - my $begin=index($result,'\begin{document}',0); - my $inc=substr($result,0,$begin+16); + unless ($temp_file = Apache::File->new('>'.$filename)) { + $r->log_error("Couldn't open $filename for output $!"); + return SERVER_ERROR; + } + print $temp_file $result; + my $begin=index($result,'\begin{document}',0); + my $inc=substr($result,0,$begin+16); } else { - my $begin=index($result,'\begin{document}',0); - my $inc=substr($result,0,$begin+16); - for (my $i=0;$i<=$#print_array;$i++) { - if ($i==0) { - $print_array[$i]=$result; - } else { - my $anobegin=index($print_array[$i],'\setcounter{page}',0); - substr($print_array[$i],0,$anobegin)=''; - $print_array[$i]=$inc.$print_array[$i].'\end{document}'; - } - my $temp_file; - my $newfilename=$filename; - my $num=$i+1; - $newfilename =~s/\.tex$//; - $newfilename=sprintf("%s_%03d.tex",$newfilename, $num); - unless ($temp_file = Apache::File->new('>'.$newfilename)) { - $r->log_error("Couldn't open $newfilename for output $!"); - return SERVER_ERROR; - } - print $temp_file $print_array[$i]; - } + my $begin=index($result,'\begin{document}',0); + my $inc=substr($result,0,$begin+16); + for (my $i=0;$i<=$#print_array;$i++) { + if ($i==0) { + $print_array[$i]=$result; + } else { + $print_array[$i].='\end{document}'; + $print_array[$i] = + &latex_corrections($number_of_columns,$print_array[$i], + $selectionmade, + $helper->{'VARS'}->{'ANSWER_TYPE'}); + + my $anobegin=index($print_array[$i],'\setcounter{page}',0); + substr($print_array[$i],0,$anobegin)=''; + $print_array[$i]=$inc.$print_array[$i]; + } + my $temp_file; + my $newfilename=$filename; + my $num=$i+1; + $newfilename =~s/\.tex$//; + $newfilename=sprintf("%s_%03d.tex",$newfilename, $num); + unless ($temp_file = Apache::File->new('>'.$newfilename)) { + $r->log_error("Couldn't open $newfilename for output $!"); + return SERVER_ERROR; + } + print $temp_file $print_array[$i]; + } } my $student_names=''; if ($#print_array>0) { - for (my $i=0;$i<=$#print_array;$i++) { - $student_names.=$student_names[$i].'_ENDPERSON_'; + for (my $i=0;$i<=$#print_array;$i++) { + $student_names.=$student_names[$i].'_ENDPERSON_'; } } else { if ($#student_names>-1) { - $student_names=$student_names[0].'_ENDPERSON_'; + $student_names=$student_names[0].'_ENDPERSON_'; } else { - my $fullname = &get_name($env{'user.name'},$env{'user.domain'}); - $student_names=join(':',$env{'user.name'},$env{'user.domain'}, - $env{'request.course.sec'},$fullname). - '_ENDPERSON_'.'_END_'; - } - } - - my $URLback=''; #link to original document - if ($helper->{'VARS'}->{'construction'} ne '1') { - #prints published resource - $URLback=&escape('/adm/flip?postdata=return:'); - } else { - #prints resource from the construction space - $URLback='/'.$helper->{'VARS'}->{'filename'}; - if ($URLback=~/([^?]+)/) { - $URLback=$1; - $URLback=~s|^/~|/priv/|; + my $fullname = &get_name($env{'user.name'},$env{'user.domain'}); + $student_names=join(':',$env{'user.name'},$env{'user.domain'}, + $env{'request.course.sec'},$fullname). + '_ENDPERSON_'.'_END_'; } - } - # logic for now is too complex to trace if this has been defined - # yet. - my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - &Apache::lonnet::appenv('cgi.'.$identifier.'.file' => $filename, - 'cgi.'.$identifier.'.layout' => $laystyle, - 'cgi.'.$identifier.'.numcol' => $numberofcolumns, - 'cgi.'.$identifier.'.paper' => $papersize, - 'cgi.'.$identifier.'.selection' => $selectionmade, - 'cgi.'.$identifier.'.tableofcontents' => $helper->{'VARS'}->{'TABLE_CONTENTS'}, - 'cgi.'.$identifier.'.tableofindex' => $helper->{'VARS'}->{'TABLE_INDEX'}, - 'cgi.'.$identifier.'.role' => $perm{'pav'}, - 'cgi.'.$identifier.'.numberoffiles' => $#print_array, - 'cgi.'.$identifier.'.studentnames' => $student_names, - 'cgi.'.$identifier.'.backref' => $URLback,); - &Apache::lonnet::appenv("cgi.$identifier.user" => $env{'user.name'}, - "cgi.$identifier.domain" => $env{'user.domain'}, - "cgi.$identifier.courseid" => $cnum, - "cgi.$identifier.coursedom" => $cdom, - "cgi.$identifier.resources" => $resources_printed); - + } + + # logic for now is too complex to trace if this has been defined + # yet. + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + &Apache::lonnet::appenv({'cgi.'.$identifier.'.file' => $filename, + 'cgi.'.$identifier.'.layout' => $laystyle, + 'cgi.'.$identifier.'.numcol' => $numberofcolumns, + 'cgi.'.$identifier.'.paper' => $papersize, + 'cgi.'.$identifier.'.selection' => $selectionmade, + 'cgi.'.$identifier.'.tableofcontents' => $helper->{'VARS'}->{'TABLE_CONTENTS'}, + 'cgi.'.$identifier.'.tableofindex' => $helper->{'VARS'}->{'TABLE_INDEX'}, + 'cgi.'.$identifier.'.role' => $perm{'pav'}, + 'cgi.'.$identifier.'.numberoffiles' => $#print_array, + 'cgi.'.$identifier.'.studentnames' => $student_names, + 'cgi.'.$identifier.'.backref' => $URLback,}); + &Apache::lonnet::appenv({"cgi.$identifier.user" => $env{'user.name'}, + "cgi.$identifier.domain" => $env{'user.domain'}, + "cgi.$identifier.courseid" => $cnum, + "cgi.$identifier.coursedom" => $cdom, + "cgi.$identifier.resources" => $resources_printed}); + my $end_page = &Apache::loncommon::end_page(); - $r->print(<print('

'.&mt('An unrecoverable network error occurred:').'

'. + &mt('At least one of the resources you chose to print could not be rendered due to an unrecoverable error when communicating with a server:'). + '
'.$ssi_last_error_resource.'
'.$ssi_last_error. + '

'.&mt('You can continue using the link provided below, but make sure to carefully inspect your output file! The errors will be marked in the file.').'
'. + &mt('You may be able to reprint the individual resources for which this error occurred, as the issue may be temporary.'). + '
'.&mt('If the error persists, please contact the [_1] for assistance.',$helpurl).'

'. + &mt('We apologize for the inconvenience.').'

'. + ''.$continue_text.''.$end_page); + } else { + $r->print(< -Continue +$continue_text $end_page FINALEND + } # endif ssi errors. } @@ -1798,9 +2249,9 @@ sub print_resources { my $printed = ''; my ($username,$userdomain,$usersection) = split /:/,$person; my $fullname = &get_name($username,$userdomain); - my $namepostfix; + my $namepostfix = "\\\\"; # Both anon and not anon should get the same vspace. if ($person =~ 'anon') { - $namepostfix="\\\\Name: "; + $namepostfix .="Name: "; $fullname = "CODE - ".$moreenv->{'CODE'}; } # Fullname may have special latex characters that need \ prefixing: @@ -1812,8 +2263,7 @@ sub print_resources { &Apache::lonxml::clear_problem_counter(); my %page_breaks = &get_page_breaks($helper); - my @format_array = split(/\|/,$helper->{'VARS'}->{'FORMAT'}); - my $columns_in_format = $format_array[1]; + my $columns_in_format = (split(/\|/,$helper->{'VARS'}->{'FORMAT'}))[1]; # # end each student with a # Special that allows the post processor to even out the page @@ -1825,6 +2275,7 @@ sub print_resources { # postscript. Each ENDOFSTUDENTSTAMP will go on a line by itself. # + foreach my $curresline (@{$master_seq}) { if (defined $page_breaks{$curresline}) { if($i != 0) { @@ -1832,6 +2283,7 @@ sub print_resources { } } $i++; + if ( !($type eq 'problems' && ($curresline!~ m/\.(problem|exam|quiz|assess|survey|form|library)$/)) ) { my ($map,$id,$res_url) = &Apache::lonnet::decode_symb($curresline); @@ -1842,7 +2294,7 @@ sub print_resources { &Apache::lonxml::remember_problem_counter(); - my $rendered = &Apache::loncommon::get_student_view($curresline,$username,$userdomain,$env{'request.course.id'},'tex',$moreenv); + my $rendered = &get_student_view_with_retries($curresline,$ssi_retry_count,$username,$userdomain,$env{'request.course.id'},'tex',$moreenv); if(($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'no') || ($helper->{'VARS'}->{'ANSWER_TYPE'} eq 'only')) { @@ -1861,23 +2313,35 @@ sub print_resources { my $header =&print_latex_header($helper->{'VARS'}->{'LATEX_TYPE'}); - my $body ='\vskip 0 mm \noindent\textbf{'.&Apache::lonnet::gettitle($curresline).'}\vskip 0 mm '; - $body .=&path_to_problem($res_url,$LaTeXwidth); + my $title = &Apache::lonnet::gettitle($curresline); + $title = &Apache::lonxml::latex_special_symbols($title); + my $body ='\vskip 0 mm \noindent\textbf{'.$title.'}\vskip 0 mm '; + $body .=&path_to_problem($res_url,$LaTeXwidth); $body .='\vskip 1 mm '.$ansrendered; $body = &encapsulate_minipage($body); $rendered = $header.$body; } } + + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $url = &Apache::lonnet::clutter($res_url); + my $annotation = &annotate($url); + $rendered =~ s/(\\keephidden{ENDOFPROBLEM})/$annotation$1/; + } if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { $rendered =~ s/\\end{document}//; } $current_output .= $rendered; - } elsif ($res_url=~/\/(smppg|grppg|syllabus|aboutme|bulletinboard)$/) { + } elsif ($res_url=~/\/(smppg|syllabus|aboutme|bulletinboard)$/) { $printed .= $curresline.':'; - my $rendered = &Apache::loncommon::get_student_view($curresline,$username,$userdomain,$env{'request.course.id'},'tex',$moreenv); - + my $rendered = &get_student_view_with_retries($curresline,$ssi_retry_count,$username,$userdomain,$env{'request.course.id'},'tex',$moreenv); + if ($helper->{'VARS'}->{'PRINT_ANNOTATIONS'} eq 'yes') { + my $url = &Apache::lonnet::clutter($res_url); + my $annotation = &annotate($url); + $annotation =~ s/(\\end{document})/$annotation$1/; + } if ($remove_latex_header eq 'YES') { $rendered = &latex_header_footer_remove($rendered); } else { @@ -1903,26 +2367,27 @@ sub print_resources { if (defined($courseidinfo)) { $courseidinfo=' - '.$courseidinfo } if ($usersection ne '') {$courseidinfo.=' - Sec. '.$usersection} my $currentassignment=&Apache::lonxml::latex_special_symbols($helper->{VARS}->{'assignment'},'header'); - if ($current_output=~/\\documentclass/) { - if ($columns_in_format == 1) { - $current_output =~ s/\\begin{document}/\\setlength{\\topmargin}{1cm} \\begin{document}\\noindent\\parbox{\\minipagewidth}{\\noindent\\lhead{\\textit{\\textbf{$fullname}}$courseidinfo \\hfill \\thepage \\\\ \\textit{$currentassignment}$namepostfix}}\\vskip 5 mm /; - } else { - $current_output =~ s/\\begin{document}/\\setlength{\\topmargin}{1cm} \\begin{document}\\noindent\\parbox{\\minipagewidth}{\\noindent\\fancyhead[LO]{\\textit{\\textbf{$fullname}}$courseidinfo \\hfill \\thepage \\\\ \\textit{$currentassignment}$namepostfix}}\\vskip 5 mm /; + my $header_line = + &format_page_header($LaTeXwidth, $parmhash{'print_header_format'}, + $currentassignment, $courseidinfo, $fullname); + my $header_start = ($columns_in_format == 1) ? '\lhead' + : '\fancyhead[LO]'; + $header_line = $header_start.'{'.$header_line.'}'; - } + if ($current_output=~/\\documentclass/) { + $current_output =~ s/\\begin{document}/\\setlength{\\topmargin}{1cm} \\begin{document}\\noindent\\parbox{\\minipagewidth}{\\noindent$header_line$namepostfix}\\vskip 5 mm /; } else { - my $blankpages = ''; - for (my $j=0;$j<$helper->{'VARS'}->{'EMPTY_PAGES'};$j++) {$blankpages.='\clearpage\strut\clearpage';} - if ($columns_in_format == 1) { - $current_output = '\strut\vspace*{-6 mm}\\newline\\noindent\\makebox[\\textwidth/$number_of_columns][b]{\\hrulefill}\vspace*{-2 mm}\\newline\\noindent{\\tiny Printed from LON-CAPA\\copyright MSU{\\hfill} Licensed under GNU General Public License }\\newpage '.$blankpages.'\setcounter{page}{1}\noindent\parbox{\minipagewidth}{\noindent\\lhead{\\textit{\\textbf{'.$fullname.'}}'.$courseidinfo.' \\hfill \\thepage \\\\ \\textit{'.$currentassignment.'}'.$namepostfix.'}} \vskip 5 mm '.$current_output; - } else { - $current_output = '\strut\vspace*{-6 mm}\\newline\\noindent\\makebox[\\textwidth/$number_of_columns][b]{\\hrulefill}\vspace*{-2 mm}\\newline\\noindent{\\tiny Printed from LON-CAPA\\copyright MSU{\\hfill} Licensed under GNU General Public License }\\newpage '.$blankpages.'\setcounter{page}{1}\noindent\parbox{\minipagewidth}{\noindent\\fancyhead[LO]{\\textit{\\textbf{'.$fullname.'}}'.$courseidinfo.' \\hfill \\thepage \\\\ \\textit{'.$currentassignment.'}'.$namepostfix.'}} \vskip 5 mm '.$current_output; - } + my $blankpages = + '\clearpage\strut\clearpage'x$helper->{'VARS'}->{'EMPTY_PAGES'}; + + $current_output = '\strut\vspace*{-6 mm}\\newline'. + ©right_line().' \newpage '.$blankpages.$end_of_student. + '\setcounter{page}{1}\noindent\parbox{\minipagewidth}{\noindent'. + $header_line.$namepostfix.'} \vskip 5 mm '.$current_output; } # # Close the student bracketing. # - $current_output .= "\n\\special{ps:ENDOFSTUDENTSTAMP}\n"; return ($current_output,$fullname, $printed); } @@ -1941,7 +2406,7 @@ sub handler { } - my %parmhash=&Apache::lonnet::coursedescription($env{'request.course.id'}); + %parmhash=&Apache::lonnet::coursedescription($env{'request.course.id'}); @@ -1954,6 +2419,8 @@ sub handler { if(-e $conversion_queuefile) { unlink $conversion_queuefile; } + + &output_data($r,$helper,\%parmhash); return OK; } @@ -1976,13 +2443,35 @@ sub init_perm { $perm{'pav'}=&Apache::lonnet::allowed('pav', $env{'request.course.id'}.'/'.$env{'request.course.sec'}); } - $perm{'pfo'}=&Apache::lonnet::allowed('pav',$env{'request.course.id'}); + $perm{'pfo'}=&Apache::lonnet::allowed('pfo',$env{'request.course.id'}); if (!$perm{'pfo'}) { $perm{'pfo'}=&Apache::lonnet::allowed('pfo', $env{'request.course.id'}.'/'.$env{'request.course.sec'}); } } +sub get_randomly_ordered_warning { + my ($helper,$map) = @_; + + my $message; + + my $postdata = $env{'form.postdata'} || $helper->{VARS}{'postdata'}; + my $navmap = Apache::lonnavmaps::navmap->new(); + my $res = $navmap->getResourceByUrl($map); + if ($res) { + 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.''; + } + return; +} + sub printHelper { my $r = shift; @@ -2024,6 +2513,11 @@ sub printHelper { $helper->declareVar('FINISHPAGE'); $helper->declareVar('PRINT_TYPE'); $helper->declareVar("showallfoils"); + $helper->declareVar("STUDENTS"); + + + + # The page breaks can get loaded initially from the course environment: # But we only do this in the initial state so that they are allowed to change. @@ -2035,6 +2529,8 @@ sub printHelper { {'pagebreaks' => 'scalar', 'lastprinttype' => 'scalar'}); + # This will persistently load in the data we want from the + # very first screen. if($helper->{VARS}->{PRINT_TYPE} eq $env{'form.lastprinttype'}) { if (!defined ($env{"form.CURRENT_STATE"})) { @@ -2049,9 +2545,7 @@ sub printHelper { } - - # This will persistently load in the data we want from the - # very first screen. + # Detect whether we're coming from construction space if ($env{'form.postdata'}=~/^(?:http:\/\/[^\/]+\/|\/|)\~([^\/]+)\/(.*)$/) { $helper->{VARS}->{'filename'} = "~$1/$2"; @@ -2059,6 +2553,9 @@ sub printHelper { } else { if ($env{'form.postdata'}) { $helper->{VARS}->{'symb'} = &Apache::lonnet::symbread($env{'form.postdata'}); + if ( $helper->{VARS}->{'symb'} eq '') { + $helper->{VARS}->{'postdata'} = $env{'form.postdata'}; + } } if ($env{'form.symb'}) { $helper->{VARS}->{'symb'} = $env{'form.symb'}; @@ -2086,6 +2583,7 @@ sub printHelper { my $symb = $helper->{VARS}->{'symb'}; my ($map, $id, $url); my $subdir; + my $is_published=0; # True when printing from resource space. # Get the resource name from construction space if ($helper->{VARS}->{'construction'}) { @@ -2094,9 +2592,15 @@ sub printHelper { $subdir = substr($helper->{VARS}->{'filename'}, 0, rindex($helper->{VARS}->{'filename'}, '/') + 1); } else { - ($map, $id, $url) = &Apache::lonnet::decode_symb($symb); - $helper->{VARS}->{'postdata'} = - &Apache::lonenc::check_encrypt(&Apache::lonnet::clutter($url)); + if ($symb ne '') { + ($map, $id, $url) = &Apache::lonnet::decode_symb($symb); + $helper->{VARS}->{'postdata'} = + &Apache::lonenc::check_encrypt(&Apache::lonnet::clutter($url)); + } else { + $url = $helper->{VARS}->{'postdata'}; + $is_published=1; # From resource space. + } + $url = &Apache::lonnet::clutter($url); if (!$resourceTitle) { # if the resource doesn't have a title, use the filename my $postdata = $helper->{VARS}->{'postdata'}; @@ -2108,7 +2612,7 @@ sub printHelper { $helper->{VARS}->{'curseed'}=$env{'form.curseed'}; } if (!$helper->{VARS}->{'probstatus'} && $env{'form.problemtype'}) { - $helper->{VARS}->{'probstatus'}=$env{'form.problemtype'}; + $helper->{VARS}->{'probstatus'}=$env{'form.problemstatus'}; } my $userCanSeeHidden = Apache::lonnavmaps::advancedUser(); @@ -2117,11 +2621,6 @@ sub printHelper { # "Delete everything after the last slash." $subdir =~ s|/[^/]+$||; - if (not $helper->{VARS}->{'construction'}) { - $subdir=$Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$subdir; - } - # "Remove all duplicate slashes." - $subdir =~ s|/+|/|g; # What can be printed is a very dynamic decision based on # lots of factors. So we need to dynamically build this list. @@ -2138,13 +2637,13 @@ sub printHelper { my $paramHash; if ($resourceTitle) { - push @{$printChoices}, ["$resourceTitle (".&mt('what you just saw on the screen').")", 'current_document', 'PAGESIZE']; + 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) '; + my $isProblem = '($res->is_problem()||$res->contains_problem||$res->is_practice()) '; $isProblem .= ' && !$res->randomout()' if !$userCanSeeHidden; - my $isProblemOrMap = '$res->is_problem() || $res->contains_problem() || $res->is_sequence()'; + my $isProblemOrMap = '$res->is_problem() || $res->contains_problem() || $res->is_sequence() || $res->is_practice()'; my $isNotMap = '!$res->is_sequence()'; $isNotMap .= ' && !$res->randomout()' if !$userCanSeeHidden; my $isMap = '$res->is_map()'; @@ -2153,40 +2652,44 @@ sub printHelper { $helper->declareVar('SEQUENCE'); + # If we're in a sequence... + my $start_new_option; + if ($perm{'pav'}) { + $start_new_option = + "