--- loncom/interface/lonprintout.pm 2006/08/22 14:43:49 1.481
+++ loncom/interface/lonprintout.pm 2007/04/20 20:13:58 1.498
@@ -2,7 +2,7 @@
# The LearningOnline Network
# Printout
#
-# $Id: lonprintout.pm,v 1.481 2006/08/22 14:43:49 albertel Exp $
+# $Id: lonprintout.pm,v 1.498 2007/04/20 20:13:58 foxr 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,90 @@ 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);
+ #
+ # fetch if needed:
+ #
+ if (! -e $filename) {
+ my $repcopy_result = &Apache::lonnet::repcopy($filename);
+
+ if ($repcopy_result ne 'ok') {
+ return "File open failed for $filename"; # This will bomb the print.
+ }
+ }
+ my $contents = &Apache::lonnet::readfile($filename);
+
+ 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 +132,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 +203,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 +518,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 +725,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 +747,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 +807,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' => {
@@ -761,7 +884,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.'}';}
@@ -812,6 +935,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);
@@ -1082,12 +1207,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;
@@ -1358,6 +1483,13 @@ 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);
+
} else {
$result.=&unsupported($currentURL,$helper->{'VARS'}->{'LATEX_TYPE'},
$helper->{'VARS'}->{'symb'});
@@ -1465,7 +1597,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);
@@ -1896,9 +2028,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:
@@ -2003,7 +2135,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]';
@@ -2124,6 +2256,7 @@ 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.
@@ -2135,6 +2268,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"})) {
@@ -2149,9 +2284,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";
@@ -2159,6 +2292,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'};
@@ -2186,6 +2322,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'}) {
@@ -2194,9 +2331,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'};
@@ -2217,11 +2360,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.
@@ -2262,7 +2400,7 @@ sub printHelper {
"' variable='FINISHPAGE' />";
}
- if (($helper->{'VARS'}->{'construction'} ne '1') &&
+ if (($helper->{'VARS'}->{'construction'} ne '1' ) &&
$helper->{VARS}->{'postdata'} &&
$helper->{VARS}->{'assignment'}) {
@@ -2300,7 +2438,7 @@ HELPERFRAGMENT
# If the user has pfo (print for otheres) allow them to print all
# problems and resources in the entier course, optionally for selected students
- if ($perm{'pfo'} &&
+ 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'];
@@ -2328,7 +2466,7 @@ HELPERFRAGMENT
ALL_PROBLEMS
if ($helper->{VARS}->{'assignment'}) {
- push @{$printChoices}, [&mt("Selected Problems from folder [_1] for selected students",$sequenceTitle), 'problems_for_students', 'CHOOSE_STUDENTS'];
+ push @{$printChoices}, [&mt("Selected Problems from folder [_1] for selected people",$sequenceTitle), 'problems_for_students', 'CHOOSE_STUDENTS'];
push @{$printChoices}, [&mt("Selected Problems from folder [_1] for CODEd assignments",$sequenceTitle), 'problems_for_anon', 'CHOOSE_ANON1'];
}
@@ -2375,7 +2513,7 @@ RESOURCE_SELECTOR
&Apache::lonxml::xmlparse($r, 'helper', <
- Select sort order
+ Select sorting order of printoutSort by section then studentSort by students across sections.
@@ -2503,7 +2641,7 @@ CHOOSE_ANON1
if ($helper->{VARS}->{'assignment'}) {
- push @{$printChoices}, [&mt("Selected Resources from folder [_1] for selected students",$sequenceTitle), 'resources_for_students', 'CHOOSE_STUDENTS1'];
+ push @{$printChoices}, [&mt("Selected Resources from folder [_1] for selected people",$sequenceTitle), 'resources_for_students', 'CHOOSE_STUDENTS1'];
push @{$printChoices}, [&mt("Selected Resources from folder [_1] for CODEd assignments",$sequenceTitle), 'resources_for_anon', 'CHOOSE_ANON2'];
}
@@ -2613,12 +2751,21 @@ CHOOSE_ANON2
}
# FIXME: That RE should come from a library somewhere.
- if ((((&Apache::lonnet::allowed('bre',$subdir) eq 'F') and ($helper->{VARS}->{'postdata'}=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)/)) or defined $helper->{'VARS'}->{'construction'}) and $perm{'pav'} and $subdir ne $Apache::lonnet::perlvar{'lonDocRoot'}.'/res/') {
- push @{$printChoices}, [&mt("Selected Problems from current subdirectory [_1]",$subdir), 'problems_from_directory', 'CHOOSE_FROM_SUBDIR'];
+ if (($perm{'pav'}
+ && $subdir ne $Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'
+ && (defined($helper->{'VARS'}->{'construction'})
+ ||
+ (&Apache::lonnet::allowed('bre',$subdir) eq 'F'
+ &&
+ $helper->{VARS}->{'postdata'}=~/\.(problem|exam|quiz|assess|survey|form|library|page|xml|html|htm|xhtml|xhtm)/)
+ ))
+ && $helper->{VARS}->{'assignment'} eq ""
+ ) {
- my $f = '$filename';
+ my $pretty_dir = &Apache::lonnet::hreflocation($subdir);
+ push @{$printChoices}, [&mt("Selected Problems from current subdirectory [_1]",$pretty_dir), 'problems_from_directory', 'CHOOSE_FROM_SUBDIR'];
my $xmlfrag = <
+ PAGESIZE
@@ -2639,7 +2786,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'}) {
+ if (!$helper->{VARS}->{'construction'} && !$is_published) {
push @$printChoices, ["Selected Resources from selected folder in course",
'select_sequences', 'CHOOSE_SEQUENCE'];
my $escapedSequenceName = $helper->{VARS}->{'SEQUENCE'};
@@ -2686,7 +2833,10 @@ CHOOSE_FROM_ANY_SEQUENCE
if (($perm{'pav'} and &Apache::lonnet::allowed('vgr',$env{'request.course.id'})) or
($helper->{VARS}->{'construction'} eq '1')) {
- addMessage("