--- loncom/interface/lonprintout.pm 2006/08/28 11:11:49 1.483 +++ loncom/interface/lonprintout.pm 2007/10/11 22:49:49 1.510 @@ -2,7 +2,7 @@ # The LearningOnline Network # Printout # -# $Id: lonprintout.pm,v 1.483 2006/08/28 11:11:49 foxr Exp $ +# $Id: lonprintout.pm,v 1.510 2007/10/11 22:49:49 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -23,7 +23,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt -# # http://www.lon-capa.org/ # # @@ -39,17 +38,84 @@ use Apache::grades; use Apache::edit; use Apache::File(); use Apache::lonnavmaps; -use Apache::lonratedt; +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; +# 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; + + +} + +# +# 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. # @@ -60,17 +126,54 @@ my $resources_printed; # %n - Student name. # sub format_page_header { - my ($format, $assignment, $course, $student) = @_; + 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 { - $format =~ s/%a/$assignment/g; - $format =~ s/%c/$course/g; - $format =~ s/%n/$student/g; + # 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!!! + + } @@ -94,7 +197,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; @@ -409,7 +512,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; @@ -616,6 +719,20 @@ 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; return $result; } @@ -624,12 +741,12 @@ 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','-0.55 in', '-0.83 in','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' => { @@ -684,12 +801,12 @@ my %page_formats= }, 'a4' => { 'book' => { - '1' => ['17.6 cm','27.2 cm','-0.55 in','-0.83 in','-0.5 in'], - '2' => [ '9.1 cm','27.2 cm','-0.55 in','-0.83 in','-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','-0.55 in','-0.83 in','0 in'], - '2' => ['3.9 in','7.7 in','-0.55 in','-0.83 in','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' => { @@ -750,7 +867,11 @@ sub page_format_transformation { 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'); } @@ -761,7 +882,7 @@ sub page_format_transformation { my $courseidinfo = &get_course(); if (defined($courseidinfo)) { $courseidinfo=' - '.$courseidinfo } my $header_text = $parmhash{'print_header_format'}; - $header_text = &format_page_header($header_text, $assignment, + $header_text = &format_page_header($textwidth, $header_text, $assignment, $courseidinfo, $name); my $topmargintoinsert = ''; if ($topmargin ne '0') {$topmargintoinsert='\setlength{\topmargin}{'.$topmargin.'}';} @@ -1084,12 +1205,12 @@ sub print_construction_sequence { if ($helper->{'VARS'}->{'curseed'}) { $rndseed=$helper->{'VARS'}->{'curseed'}; } - my $errtext=&Apache::lonratedt::mapread($currentURL); + my $errtext=&LONCAPA::map::mapread($currentURL); # # These make this all support recursing for subsequences. # - my @order = @Apache::lonratedt::order; - my @resources = @Apache::lonratedt::resources; + my @order = @LONCAPA::map::order; + my @resources = @LONCAPA::map::resources; for (my $member=0;$member<=$#order;$member++) { $resources[$order[$member]]=~/^([^:]*):([^:]*):/; my $urlp=$2; @@ -1170,6 +1291,7 @@ sub output_data { my ($r,$helper,$rparmhash) = @_; my %parmhash = %$rparmhash; $resources_printed = ''; + my $do_postprocessing = 1; my $js = < var editbrowser; @@ -1249,6 +1371,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, ... @@ -1272,12 +1402,6 @@ 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'}; @@ -1326,7 +1450,7 @@ ENDPART $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}'; } @@ -1360,6 +1484,14 @@ ENDPART $resources_printed .= $currentURL.':'; my $texversion=&Apache::lonnet::ssi($currentURL,%form); $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); + $do_postprocessing = 0; # Don't massage the result. + } else { $result.=&unsupported($currentURL,$helper->{'VARS'}->{'LATEX_TYPE'}, $helper->{'VARS'}->{'symb'}); @@ -1467,7 +1599,7 @@ ENDPART if (defined($courseidinfo)) { $courseidinfo=' - '.$courseidinfo } $prevassignment=$assignment; my $header_text = $parmhash{'print_header_format'}; - $header_text = &format_page_header($header_text, + $header_text = &format_page_header($textwidth, $header_text, $assignment, $courseidinfo, $name); @@ -1764,15 +1896,20 @@ 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'}); - #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'} /; - #} + #} + } #-- writing .tex file in prtspool my $temp_file; @@ -1832,10 +1969,7 @@ ENDPART } my $URLback=''; #link to original document - if ($helper->{'VARS'}->{'construction'} ne '1') { - #prints published resource - $URLback=&escape('/adm/flip?postdata=return:'); - } else { + if ($helper->{'VARS'}->{'construction'} eq '1') { #prints resource from the construction space $URLback='/'.$helper->{'VARS'}->{'filename'}; if ($URLback=~/([^?]+)/) { @@ -1898,9 +2032,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: @@ -2005,7 +2139,7 @@ sub print_resources { if ($usersection ne '') {$courseidinfo.=' - Sec. '.$usersection} my $currentassignment=&Apache::lonxml::latex_special_symbols($helper->{VARS}->{'assignment'},'header'); my $header_line = - &format_page_header($parmhash{'print_header_format'}, + &format_page_header($LaTeXwidth, $parmhash{'print_header_format'}, $currentassignment, $courseidinfo, $fullname); my $header_start = ($columns_in_format == 1) ? '\lhead' : '\fancyhead[LO]'; @@ -2085,6 +2219,28 @@ sub init_perm { } } +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; @@ -2311,8 +2467,8 @@ HELPERFRAGMENT if ($perm{'pfo'} && !$is_published && ($helper->{VARS}->{'postdata'}=~/\/res\// || $helper->{VARS}->{'postdata'}=~/\/(syllabus|smppg|aboutme|bulletinboard)$/)) { - push @{$printChoices}, ['Selected Problems from entire course', 'all_problems', 'ALL_PROBLEMS']; - push @{$printChoices}, ['Selected Resources from entire course', 'all_resources', 'ALL_RESOURCES']; + push @{$printChoices}, [&mtn('Selected Problems from entire course'), 'all_problems', 'ALL_PROBLEMS']; + push @{$printChoices}, [&mtn('Selected Resources from entire course'), 'all_resources', 'ALL_RESOURCES']; &Apache::lonxml::xmlparse($r, 'helper', < Problems from folder [_1] for CODEd assignments",$sequenceTitle), 'problems_for_anon', 'CHOOSE_ANON1']; } + my $randomly_ordered_warning = + &get_randomly_ordered_warning($helper,$map); + # resource_selector will hold a few states that: # - Allow resources to be selected for printing. # - Determine pagination between assignments. @@ -2351,6 +2510,8 @@ ALL_PROBLEMS # my $resource_selector=< + $randomly_ordered_warning + PRINT_FORMATTING
Select resources for the assignment
- Select sort order + Select sorting order of printout Sort by section then student Sort by students across sections. @@ -2470,7 +2631,7 @@ CHOOSE_STUDENTS - Names to store the CODEs under for later: + Names to save the CODEs under for later: @@ -2518,6 +2679,8 @@ CHOOSE_ANON1 $resource_selector=< + $randomly_ordered_warning + PRINT_FORMATTING
Select resources for the assignment
- Names to store the CODEs under for later: + Names to save the CODEs under for later: @@ -2657,7 +2820,7 @@ CHOOSE_FROM_SUBDIR # Allow the user to select any sequence in the course, feed it to # another resource selector for that sequence if (!$helper->{VARS}->{'construction'} && !$is_published) { - push @$printChoices, ["Selected Resources from selected folder in course", + push @$printChoices, [&mtn("Selected Resources from selected folder in course"), 'select_sequences', 'CHOOSE_SEQUENCE']; my $escapedSequenceName = $helper->{VARS}->{'SEQUENCE'}; #Escape apostrophes and backslashes for Perl @@ -2703,7 +2866,10 @@ CHOOSE_FROM_ANY_SEQUENCE if (($perm{'pav'} and &Apache::lonnet::allowed('vgr',$env{'request.course.id'})) or ($helper->{VARS}->{'construction'} eq '1')) { - addMessage("
Print: "); + addMessage("
". + ': "); $paramHash = Apache::lonhelper::getParamHash(); $paramHash->{'variable'} = 'ANSWER_TYPE'; $helper->declareVar('ANSWER_TYPE'); @@ -2719,10 +2885,16 @@ CHOOSE_FROM_ANY_SEQUENCE if ($perm{'pav'}) { if (!$startedTable) { - addMessage("
LaTeX mode: "); + addMessage("
"); if (not $helper->{VARS}->{'construction'}) { - addMessage(""); - addMessage(" RNDSEED &Apache::lonxml::xmlparse($r, 'helper', $xmlfrag); - $helper->{'VARS'}->{'style_file'}=$env{'form.style_file_value'}; - } } @@ -2901,6 +3092,8 @@ sub render { my $PageLayout=&mt('Page layout'); my $NumberOfColumns=&mt('Number of columns'); my $PaperType=&mt('Paper type'); + my $landscape=&mt('Landscape'); + my $portrait=&mt('Portrait'); $result .= < @@ -2912,8 +3105,8 @@ sub render {
". + ': "); $startedTable = 1; } else { - addMessage("
LaTeX mode: "); + addMessage("
". + ': "); } $paramHash = Apache::lonhelper::getParamHash(); $paramHash->{'variable'} = 'LATEX_TYPE'; @@ -2738,7 +2910,10 @@ CHOOSE_FROM_ANY_SEQUENCE } Apache::lonhelper::dropdown->new(); - addMessage("
Print Table of Contents: "); + addMessage("
". + ': "); $paramHash = Apache::lonhelper::getParamHash(); $paramHash->{'variable'} = 'TABLE_CONTENTS'; $helper->declareVar('TABLE_CONTENTS'); @@ -2749,7 +2924,10 @@ CHOOSE_FROM_ANY_SEQUENCE addMessage("
Print Index: "); + addMessage("
". + ': "); $paramHash = Apache::lonhelper::getParamHash(); $paramHash->{'variable'} = 'TABLE_INDEX'; $helper->declareVar('TABLE_INDEX'); @@ -2758,7 +2936,10 @@ CHOOSE_FROM_ANY_SEQUENCE ['Yes', 'yes'] ]; Apache::lonhelper::dropdown->new(); addMessage("
Print Discussions: "); + addMessage("
". + ': "); $paramHash = Apache::lonhelper::getParamHash(); $paramHash->{'variable'} = 'PRINT_DISCUSSIONS'; $helper->declareVar('PRINT_DISCUSSIONS'); @@ -2779,24 +2960,34 @@ CHOOSE_FROM_ANY_SEQUENCE } if ($helper->{'VARS'}->{'construction'}) { - my $stylevalue=$env{'construct.style'}; + my $stylevalue='$Apache::lonnet::env{"construct.style"}'; + my $randseedtext=&mt("Use random seed"); + my $stylefiletext=&mt("Use style file"); + my $selectfiletext=&mt("Select style file"); + my $xmlfrag .= <<"RNDSEED"; -
Use random seed: +
+ : + return $helper->{VARS}->{'curseed'}; -
Use style file: -   Select style file
+
+ : + + + + return $stylevalue; + +   $selectfiletext
- Show all foils? + Show all foils
-
- +
+
- + - + - +
Width:$text{'width'}
Height:$text{'height'}
Left margin:$text{'margin'}