[system] / branches / rel-2-4-dev / webwork-modperl / lib / WeBWorK / ContentGenerator / Instructor / SetMaker.pm Repository:
ViewVC logotype

View of /branches/rel-2-4-dev/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3583 - (download) (as text) (annotate)
Sun Aug 28 20:54:51 2005 UTC (7 years, 8 months ago) by jj
Original Path: trunk/webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm
File size: 45888 byte(s)
Allow use of an activity log which logs every click, stored on a
per-course basis.  It is turned off by default.  It can be turned
on/off for individual courses.  The three pieces here:

  global.conf.dist: adds a place to define the log file.  Here an
    empty value signals to not do this logging.

  ContentGenerator.pm: check to see if the log file is defined (and
    (non-trivial), and if so, write a log entry.  We check if it is
    defined at this point to both save some time, and because if we
    get to writeCourseLog and the log isn't defined, we get a pink
    screen.

    The bulk of the text of the log entry is performed by a new method
    prepare_activity_entry.  By default, this gives the url, and a list
    of all the cgi parameters (except for key and passwd).  This method
    can be overridden by individual modules.  The default format may
    change.  It may take some fine tuning to see what is best.

    Also, this is one of the first functions called by go.  We may want
    it to go after the action has taken place if we want instructor
    modules to be able to report results of their work through this log.

  SetMaker.pm: gives an example of overriding prepare_activity_entry.
    SetMaker has lots (and lots and lots) of data stored in cgi
    parameters.  We probably don't want to log that.  We might want to
    log a little more in SetMaker than we do here (target set), but
    this gives a start.

    1 ################################################################################
    2 # WeBWorK Online Homework Delivery System
    3 # Copyright © 2000-2003 The WeBWorK Project, http://openwebwork.sf.net/
    4 # $CVSHeader: webwork-modperl/lib/WeBWorK/ContentGenerator/Instructor/SetMaker.pm,v 1.53 2005/08/22 02:40:26 jj Exp $
    5 #
    6 # This program is free software; you can redistribute it and/or modify it under
    7 # the terms of either: (a) the GNU General Public License as published by the
    8 # Free Software Foundation; either version 2, or (at your option) any later
    9 # version, or (b) the "Artistic License" which comes with this package.
   10 #
   11 # This program is distributed in the hope that it will be useful, but WITHOUT
   12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
   13 # FOR A PARTICULAR PURPOSE.  See either the GNU General Public License or the
   14 # Artistic License for more details.
   15 ################################################################################
   16 
   17 
   18 package WeBWorK::ContentGenerator::Instructor::SetMaker;
   19 use base qw(WeBWorK::ContentGenerator::Instructor);
   20 
   21 =head1 NAME
   22 
   23 WeBWorK::ContentGenerator::Instructor::SetMaker - Make problem sets.
   24 
   25 =cut
   26 
   27 use strict;
   28 use warnings;
   29 
   30 use CGI::Pretty qw();
   31 use WeBWorK::Debug;
   32 use WeBWorK::Form;
   33 use WeBWorK::Utils qw(readDirectory max sortByName);
   34 use WeBWorK::Utils::Tasks qw(renderProblems);
   35 use File::Find;
   36 
   37 require WeBWorK::Utils::ListingDB;
   38 
   39 use constant MAX_SHOW_DEFAULT => 20;
   40 use constant NO_LOCAL_SET_STRING => 'No sets in this course yet';
   41 use constant SELECT_SET_STRING => 'Select a Set from this Course';
   42 use constant SELECT_LOCAL_STRING => 'Select a Problem Collection';
   43 use constant MY_PROBLEMS => '  My Problems  ';
   44 use constant MAIN_PROBLEMS => '  Main Problems  ';
   45 use constant CREATE_SET_BUTTON => 'Create New Set';
   46 use constant ALL_CHAPTERS => 'All Chapters';
   47 use constant ALL_SUBJECTS => 'All Subjects';
   48 use constant ALL_SECTIONS => 'All Sections';
   49 use constant ALL_TEXTBOOKS => 'All Textbooks';
   50 
   51 use constant LIB2_DATA => {
   52   'dbchapter' => {name => 'library_chapters', all => 'All Chapters'},
   53   'dbsection' =>  {name => 'library_sections', all =>'All Sections' },
   54   'dbsubject' =>  {name => 'library_subjects', all => 'All Subjects' },
   55   'textbook' =>  {name => 'library_textbook', all =>  'All Textbooks'},
   56   'textchapter' => {name => 'library_textchapter', all => 'All Chapters'},
   57   'textsection' => {name => 'library_textsection', all => 'All Sections'},
   58   'keywords' =>  {name => 'library_keywords', all => '' },
   59   };
   60 
   61 ## Flags for operations on files
   62 
   63 use constant ADDED => 1;
   64 use constant HIDDEN => (1 << 1);
   65 use constant SUCCESS => (1 << 2);
   66 
   67 ##  for additional problib buttons
   68 my %problib;  ## filled in in global.conf
   69 my %ignoredir = (
   70   '.' => 1, '..' => 1, 'Library' => 1,
   71   'headers' => 1, 'macros' => 1, 'email' => 1,
   72 );
   73 
   74 sub prepare_activity_entry {
   75   my $self=shift;
   76   my $r = $self->r;
   77   my $user = $self->r->param('user') || 'NO_USER';
   78   return("In SetMaker as user $user");
   79 }
   80 
   81 ## This is for searching the disk for directories containing pg files.
   82 ## to make the recursion work, this returns an array where the first
   83 ## item is the number of pg files in the directory.  The second is a
   84 ## list of directories which contain pg files.
   85 ##
   86 ## If a directory contains only one pg file and at least one other
   87 ## file, the directory is considered to be part of the parent
   88 ## directory (it is probably in a separate directory only because
   89 ## it has auxiliarly files that want to be kept together with the
   90 ## pg file).
   91 ##
   92 ## If a directory has a file named "=library-ignore", it is never
   93 ## included in the directory menu.  If a directory contains a file
   94 ## called "=library-combine-up", then its pg are included with those
   95 ## in the parent directory (and the directory does not appear in the
   96 ## menu).  If it has a file called "=library-no-combine" then it is
   97 ## always listed as a separate directory even if it contains only one
   98 ## pg file.
   99 
  100 sub get_library_sets {
  101   my $top = shift; my $dir =  shift;
  102   # ignore directories that give us an error
  103   my @lis = eval { readDirectory($dir) };
  104   if ($@) {
  105     warn $@;
  106     return (0);
  107   }
  108   return (0) if grep /^=library-ignore$/, @lis;
  109 
  110   my @pgdirs;
  111 
  112   my $pgcount = scalar(grep { m/\.pg$/ and (not m/(Header|-text)\.pg$/) and -f "$dir/$_"} @lis);
  113   my $others = scalar(grep { (!m/\.pg$/ || m/(Header|-text)\.pg$/) &&
  114                               !m/(\.(tmp|bak)|~)$/ && -f "$dir/$_" } @lis);
  115 
  116   my @dirs = grep {!$ignoredir{$_} and -d "$dir/$_"} @lis;
  117   if ($top == 1) {@dirs = grep {!$problib{$_}} @dirs}
  118   foreach my $subdir (@dirs) {
  119     my @results = get_library_sets(0, "$dir/$subdir");
  120     $pgcount += shift @results; push(@pgdirs,@results);
  121   }
  122 
  123   return ($pgcount, @pgdirs) if $top || $pgcount == 0 || grep /^=library-combine-up$/, @lis;
  124   return (0,@pgdirs,$dir) if $pgcount > 1 || $others == 0 || grep /^=library-no-combine$/, @lis;
  125   return ($pgcount, @pgdirs);
  126 }
  127 
  128 sub get_library_pgs {
  129   my $top = shift; my $base = shift; my $dir =  shift;
  130   my @lis = readDirectory("$base/$dir");
  131   return () if grep /^=library-ignore$/, @lis;
  132   return () if !$top && grep /^=library-no-combine$/, @lis;
  133 
  134   my @pgs = grep { m/\.pg$/ and (not m/(Header|-text)\.pg$/) and -f "$base/$dir/$_"} @lis;
  135   my $others = scalar(grep { (!m/\.pg$/ || m/(Header|-text)\.pg$/) &&
  136                               !m/(\.(tmp|bak)|~)$/ && -f "$base/$dir/$_" } @lis);
  137 
  138   my @dirs = grep {!$ignoredir{$_} and -d "$base/$dir/$_"} @lis;
  139   if ($top == 1) {@dirs = grep {!$problib{$_}} @dirs}
  140   foreach my $subdir (@dirs) {push(@pgs, get_library_pgs(0,"$base/$dir",$subdir))}
  141 
  142   return () unless $top || (scalar(@pgs) == 1 && $others) || grep /^=library-combine-up$/, @lis;
  143   return (map {"$dir/$_"} @pgs);
  144 }
  145 
  146 sub list_pg_files {
  147   my ($templates,$dir) = @_;
  148   my $top = ($dir eq '.')? 1 : 2;
  149   my @pgs = get_library_pgs($top,$templates,$dir);
  150   return sortByName(undef,@pgs);
  151 }
  152 
  153 ## Search for set definition files
  154 
  155 sub get_set_defs {
  156   my $topdir = shift;
  157   my @found_set_defs;
  158   # get_set_defs_wanted is a closure over @found_set_defs
  159   my $get_set_defs_wanted = sub {
  160     my $fn = $_;
  161     my $fdir = $File::Find::dir;
  162     return() if($fn !~ /^set.*\.def$/);
  163     #return() if(not -T $fn);
  164     push @found_set_defs, "$fdir/$fn";
  165   };
  166   find({ wanted => $get_set_defs_wanted, follow_fast=>1}, $topdir);
  167   map { $_ =~ s|^$topdir/?|| } @found_set_defs;
  168   return @found_set_defs;
  169 }
  170 
  171 ## Try to make reading of set defs more flexible.  Additional strategies
  172 ## for fixing a path can be added here.
  173 
  174 sub munge_pg_file_path {
  175   my $self = shift;
  176   my $pg_path = shift;
  177   my $path_to_set_def = shift;
  178   my $end_path = $pg_path;
  179   # if the path is ok, don't fix it
  180   return($pg_path) if(-e $self->r->ce->{courseDirs}{templates}."/$pg_path");
  181   # if we have followed a link into a self contained course to get
  182   # to the set.def file, we need to insert the start of the path to
  183   # the set.def file
  184   $end_path = "$path_to_set_def/$pg_path";
  185   return($end_path) if(-e $self->r->ce->{courseDirs}{templates}."/$end_path");
  186   # if we got this far, this path is bad, but we let it produce
  187   # an error so the user knows there is a troublesome path in the
  188   # set.def file.
  189   return($pg_path);
  190 }
  191 
  192 ## Read a set definition file.  This could be abstracted since it happens
  193 ## elsewhere.  Here we don't have to process so much of the file.
  194 
  195 sub read_set_def {
  196   my $self = shift;
  197   my $r = $self->r;
  198   my $filePathOrig = shift;
  199   my $filePath = $r->ce->{courseDirs}{templates}."/$filePathOrig";
  200   $filePathOrig =~ s/set.*\.def$//;
  201   $filePathOrig =~ s|/$||;
  202   $filePathOrig = "." if ($filePathOrig !~ /\S/);
  203   my @pg_files = ();
  204   my ($line, $got_to_pgs, $name, @rest) = ("", 0, "");
  205   if ( open (SETFILENAME, "$filePath") )    {
  206     while($line = <SETFILENAME>) {
  207       chomp($line);
  208       $line =~ s|(#.*)||; # don't read past comments
  209       if($got_to_pgs) {
  210         unless ($line =~ /\S/) {next;} # skip blank lines
  211         ($name,@rest) = split (/\s*,\s*/,$line);
  212         $name =~ s/\s*//g;
  213         push @pg_files, $name;
  214       } else {
  215         $got_to_pgs = 1 if ($line =~ /problemList\s*=/);
  216       }
  217     }
  218   } else {
  219     $self->addbadmessage("Cannot open $filePath");
  220   }
  221   # This is where we would potentially munge the pg file paths
  222   # One possibility
  223   @pg_files = map { $self->munge_pg_file_path($_, $filePathOrig) } @pg_files;
  224   return(@pg_files);
  225 }
  226 
  227 ## go through past page getting a list of identifiers for the problems
  228 ## and whether or not they are selected, and whether or not they should
  229 ## be hidden
  230 
  231 sub get_past_problem_files {
  232   my $r = shift;
  233   my @found=();
  234   my $count =1;
  235   while (defined($r->param("filetrial$count"))) {
  236     my $val = 0;
  237     $val |= ADDED if($r->param("trial$count"));
  238     $val |= HIDDEN if($r->param("hideme$count"));
  239     push @found, [$r->param("filetrial$count"), $val];
  240     $count++;
  241   }
  242   return(\@found);
  243 }
  244 
  245 #### For adding new problems
  246 
  247 sub add_selected {
  248   my $self = shift;
  249   my $db = shift;
  250   my $setName = shift;
  251   my @past_problems = @{$self->{past_problems}};
  252   my @selected = @past_problems;
  253   my (@path, $file, $selected, $freeProblemID);
  254   $freeProblemID = max($db->listGlobalProblems($setName)) + 1;
  255   my $addedcount=0;
  256 
  257   for $selected (@selected) {
  258     if($selected->[1] & ADDED) {
  259       $file = $selected->[0];
  260       my $problemRecord = $self->addProblemToSet(setName => $setName,
  261         sourceFile => $file, problemID => $freeProblemID);
  262       $freeProblemID++;
  263       $self->assignProblemToAllSetUsers($problemRecord);
  264       $selected->[1] |= SUCCESS;
  265       $addedcount++;
  266     }
  267   }
  268   return($addedcount);
  269 }
  270 
  271 
  272 ############# List of sets of problems in templates directory
  273 
  274 sub get_problem_directories {
  275   my $ce = shift;
  276   my $lib = shift;
  277   my $source = $ce->{courseDirs}{templates};
  278   my $main = MY_PROBLEMS; my $isTop = 1;
  279   if ($lib) {$source .= "/$lib"; $main = MAIN_PROBLEMS; $isTop = 2}
  280   my @all_problem_directories = get_library_sets($isTop, $source);
  281   my $includetop = shift @all_problem_directories;
  282   my $j;
  283   for ($j=0; $j<scalar(@all_problem_directories); $j++) {
  284     $all_problem_directories[$j] =~ s|^$ce->{courseDirs}->{templates}/?||;
  285   }
  286   @all_problem_directories = sortByName(undef, @all_problem_directories);
  287   unshift @all_problem_directories, $main if($includetop);
  288   return (\@all_problem_directories);
  289 }
  290 
  291 ############# Everyone has a view problems line.  Abstract it
  292 sub view_problems_line {
  293   my $internal_name = shift;
  294   my $label = shift;
  295   my $r = shift; # so we can get parameter values
  296   my $result = CGI::submit(-name=>"$internal_name", -value=>$label);
  297 
  298   my %display_modes = %{WeBWorK::PG::DISPLAY_MODES()};
  299   my @active_modes = grep { exists $display_modes{$_} }
  300     @{$r->ce->{pg}->{displayModes}};
  301   push @active_modes, 'None';
  302   # We have our own displayMode since its value may be None, which is illegal
  303   # in other modules.
  304   my $mydisplayMode = $r->param('mydisplayMode') || $r->ce->{pg}->{options}->{displayMode};
  305   $result .= '&nbsp;Display&nbsp;Mode:&nbsp;'.CGI::popup_menu(-name=> 'mydisplayMode',
  306                                                               -values=>\@active_modes,
  307                                                               -default=> $mydisplayMode);
  308   # Now we give a choice of the number of problems to show
  309   my $defaultMax = $r->param('max_shown') || MAX_SHOW_DEFAULT;
  310   $result .= '&nbsp;Max. Shown:&nbsp'.
  311     CGI::popup_menu(-name=> 'max_shown',
  312                     -values=>[5,10,15,20,25,30,50,'All'],
  313                     -default=> $defaultMax);
  314 
  315   return($result);
  316 }
  317 
  318 
  319 ### The browsing panel has three versions
  320 #####  Version 1 is local problems
  321 sub browse_local_panel {
  322   my $self = shift;
  323   my $library_selected = shift;
  324   my $lib = shift || ''; $lib =~ s/^browse_//;
  325   my $name = ($lib eq '')? 'Local' : $problib{$lib};
  326 
  327   my $list_of_prob_dirs= get_problem_directories($self->r->ce,$lib);
  328   if(scalar(@$list_of_prob_dirs) == 0) {
  329     $library_selected = "Found no directories containing problems";
  330     unshift @{$list_of_prob_dirs}, $library_selected;
  331   } else {
  332     my $default_value = SELECT_LOCAL_STRING;
  333     if (not $library_selected or $library_selected eq $default_value) {
  334       unshift @{$list_of_prob_dirs},  $default_value;
  335       $library_selected = $default_value;
  336     }
  337   }
  338   my $view_problem_line = view_problems_line('view_local_set', 'View Problems', $self->r);
  339   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "$name Problems: ",
  340     CGI::popup_menu(-name=> 'library_sets',
  341                     -values=>$list_of_prob_dirs,
  342                     -default=> $library_selected),
  343     CGI::br(),
  344     $view_problem_line,
  345   ));
  346 }
  347 
  348 #####  Version 2 is local problem sets
  349 sub browse_mysets_panel {
  350   my $self = shift;
  351   my $library_selected = shift;
  352   my $list_of_local_sets = shift;
  353   my $default_value = "Select a Homework Set";
  354 
  355   if(scalar(@$list_of_local_sets) == 0) {
  356     $list_of_local_sets = [NO_LOCAL_SET_STRING];
  357   } elsif (not $library_selected or $library_selected eq $default_value) {
  358     unshift @{$list_of_local_sets},  $default_value;
  359     $library_selected = $default_value;
  360   }
  361 
  362   my $view_problem_line = view_problems_line('view_mysets_set', 'View Problems', $self->r);
  363   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ",
  364     CGI::popup_menu(-name=> 'library_sets',
  365                     -values=>$list_of_local_sets,
  366                     -default=> $library_selected),
  367     CGI::br(),
  368     $view_problem_line
  369   ));
  370 }
  371 
  372 #####  Version 3 is the problem library
  373 #
  374 # This comes in 3 forms, problem library version 1, and for version 2 there
  375 # is the basic, and the advanced interfaces.  This function checks what we are
  376 # supposed to do, or aborts if the problem library has not been installed.
  377 
  378 sub browse_library_panel {
  379   my $self=shift;
  380   my $r = $self->r;
  381   my $ce = $r->ce;
  382 
  383   # See if the problem library is installed
  384   my $libraryRoot = $r->{ce}->{problemLibrary}->{root};
  385 
  386   unless($libraryRoot) {
  387     print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"},
  388       "The problem library has not been installed.")));
  389     return;
  390   }
  391   # Test if the Library directory link exists.  If not, try to make it
  392   unless(-d "$ce->{courseDirs}->{templates}/Library") {
  393     unless(symlink($libraryRoot, "$ce->{courseDirs}->{templates}/Library")) {
  394       my $msg =  <<"HERE";
  395 You are missing the directory <code>templates/Library</code>, which is needed
  396 for the Problem Library to function.  It should be a link pointing to
  397 <code>$libraryRoot</code>, which you set in <code>conf/global.conf</code>.
  398 I tried to make the link for you, but that failed.  Check the permissions
  399 in your <code>templates</code> directory.
  400 HERE
  401       $self->addbadmessage($msg);
  402     }
  403   }
  404 
  405   # Now check what version we are supposed to use
  406   my $libraryVersion = $r->{ce}->{problemLibrary}->{version} || 1;
  407   if($libraryVersion == 1) {
  408     return $self->browse_library_panel1;
  409   } elsif($libraryVersion == 2) {
  410     return $self->browse_library_panel2 if($self->{library_basic}==1);
  411     return $self->browse_library_panel2adv;
  412   } else {
  413     print CGI::Tr(CGI::td(CGI::div({class=>'ResultsWithError', align=>"center"},
  414       "The problem library version is set to an illegal value.")));
  415     return;
  416   }
  417 }
  418 
  419 sub browse_library_panel1 {
  420   my $self = shift;
  421   my $r = $self->r;
  422   my $ce = $r->ce;
  423 
  424   my @chaps = WeBWorK::Utils::ListingDB::getAllChapters($r->{ce});
  425   unshift @chaps, LIB2_DATA->{dbchapter}{all};
  426   my $chapter_selected = $r->param('library_chapters') || LIB2_DATA->{dbchapter}->{all};
  427 
  428   my @sects=();
  429   if ($chapter_selected ne LIB2_DATA->{dbchapter}{all}) {
  430     @sects = WeBWorK::Utils::ListingDB::getAllSections($r->{ce}, $chapter_selected);
  431   }
  432 
  433   unshift @sects, ALL_SECTIONS;
  434   my $section_selected =  $r->param('library_sections') || LIB2_DATA->{dbsection}{all};
  435 
  436   my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r);
  437 
  438   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"},
  439     CGI::start_table(),
  440       CGI::Tr(
  441         CGI::td(["Chapter:",
  442           CGI::popup_menu(-name=> 'library_chapters',
  443                           -values=>\@chaps,
  444                           -default=> $chapter_selected,
  445                           -onchange=>"submit();return true"
  446           ),
  447           CGI::submit(-name=>"lib_select_chapter", -value=>"Update Section List")])),
  448       CGI::Tr(
  449         CGI::td("Section:"),
  450         CGI::td({-colspan=>2},
  451           CGI::popup_menu(-name=> 'library_sections',
  452                           -values=>\@sects,
  453                           -default=> $section_selected
  454       ))),
  455 
  456       CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)),
  457       CGI::end_table(),
  458     ));
  459 }
  460 
  461 sub browse_library_panel2 {
  462   my $self = shift;
  463   my $r = $self->r;
  464   my $ce = $r->ce;
  465 
  466   my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r);
  467   unshift @subjs, LIB2_DATA->{dbsubject}{all};
  468 
  469   my @chaps = WeBWorK::Utils::ListingDB::getAllDBchapters($r);
  470   unshift @chaps, LIB2_DATA->{dbchapter}{all};
  471 
  472   my @sects=();
  473   @sects = WeBWorK::Utils::ListingDB::getAllDBsections($r);
  474   unshift @sects, LIB2_DATA->{dbsection}{all};
  475 
  476   my $subject_selected = $r->param('library_subjects') || LIB2_DATA->{dbsubject}{all};
  477   my $chapter_selected = $r->param('library_chapters') || LIB2_DATA->{dbchapter}{all};
  478   my $section_selected =  $r->param('library_sections') || LIB2_DATA->{dbsection}{all};
  479 
  480   my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r);
  481 
  482   my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r);
  483   if($count_line==0) {
  484     $count_line = "There are no matching pg files";
  485   } else {
  486     $count_line = "There are $count_line matching WeBWorK problem files";
  487   }
  488 
  489   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"},
  490     CGI::hidden(-name=>"library_is_basic", -default=>[1]),
  491     CGI::start_table({-width=>"100%"}),
  492     CGI::Tr(
  493       CGI::td(["Subject:",
  494         CGI::popup_menu(-name=> 'library_subjects',
  495                       -values=>\@subjs,
  496                       -default=> $subject_selected,
  497                        -onchange=>"submit();return true"
  498         )]),
  499       CGI::td({-colspan=>2, -align=>"right"},
  500         CGI::submit(-name=>"lib_select_subject", -value=>"Update Chapter/Section Lists"))
  501     ),
  502     CGI::Tr(
  503       CGI::td(["Chapter:",
  504         CGI::popup_menu(-name=> 'library_chapters',
  505                       -values=>\@chaps,
  506                       -default=> $chapter_selected,
  507                        -onchange=>"submit();return true"
  508         )]),
  509       CGI::td({-colspan=>2, -align=>"right"},
  510           CGI::submit(-name=>"library_advanced", -value=>"Advanced Search"))
  511     ),
  512     CGI::Tr(
  513       CGI::td(["Section:",
  514       CGI::popup_menu(-name=> 'library_sections',
  515                   -values=>\@sects,
  516                   -default=> $section_selected,
  517               -onchange=>"submit();return true"
  518         )]),
  519      ),
  520      CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)),
  521      CGI::Tr(CGI::td({-colspan=>3, -align=>"center"}, $count_line)),
  522      CGI::end_table(),
  523    ));
  524 
  525 }
  526 
  527 sub browse_library_panel2adv {
  528   my $self = shift;
  529   my $r = $self->r;
  530   my $ce = $r->ce;
  531   my $right_button_style = "width: 18ex";
  532 
  533   my @subjs = WeBWorK::Utils::ListingDB::getAllDBsubjects($r);
  534   if(! grep { $_ eq $r->param('library_subjects') } @subjs) {
  535     $r->param('library_subjects', '');
  536   }
  537   unshift @subjs, LIB2_DATA->{dbsubject}{all};
  538 
  539   my @chaps = WeBWorK::Utils::ListingDB::getAllDBchapters($r);
  540   if(! grep { $_ eq $r->param('library_chapters') } @chaps) {
  541     $r->param('library_chapters', '');
  542   }
  543   unshift @chaps, LIB2_DATA->{dbchapter}{all};
  544 
  545   my @sects = WeBWorK::Utils::ListingDB::getAllDBsections($r);
  546   if(! grep { $_ eq $r->param('library_sections') } @sects) {
  547     $r->param('library_sections', '');
  548   }
  549   unshift @sects, LIB2_DATA->{dbsection}{all};
  550 
  551   my $texts = WeBWorK::Utils::ListingDB::getDBTextbooks($r);
  552   my @textarray = map { $_->[0] }  @{$texts};
  553   my %textlabels = ();
  554   for my $ta (@{$texts}) {
  555     $textlabels{$ta->[0]} = $ta->[1]." by ".$ta->[2]." (edition ".$ta->[3].")";
  556   }
  557   if(! grep { $_ eq $r->param('library_textbook') } @textarray) {
  558     $r->param('library_textbook', '');
  559   }
  560   unshift @textarray, LIB2_DATA->{textbook}{all};
  561   my $atb = LIB2_DATA->{textbook}{all}; $textlabels{$atb} = LIB2_DATA->{textbook}{all};
  562 
  563   my $textchap_ref = WeBWorK::Utils::ListingDB::getDBTextbooks($r, 'textchapter');
  564   my @textchaps = map { $_->[0] } @{$textchap_ref};
  565   if(! grep { $_ eq $r->param('library_textchapter') } @textchaps) {
  566     $r->param('library_textchapter', '');
  567   }
  568   unshift @textchaps, LIB2_DATA->{textchapter}{all};
  569 
  570   my $textsec_ref = WeBWorK::Utils::ListingDB::getDBTextbooks($r, 'textsection');
  571   my @textsecs = map { $_->[0] } @{$textsec_ref};
  572   if(! grep { $_ eq $r->param('library_textsection') } @textsecs) {
  573     $r->param('library_textsection', '');
  574   }
  575   unshift @textsecs, LIB2_DATA->{textsection}{all};
  576 
  577   my %selected = ();
  578   for my $j (qw( dbsection dbchapter dbsubject textbook textchapter textsection )) {
  579     $selected{$j} = $r->param(LIB2_DATA->{$j}{name}) || LIB2_DATA->{$j}{all};
  580   }
  581 
  582   my $text_popup = CGI::popup_menu(-name => 'library_textbook',
  583                    -values =>\@textarray,
  584                    -labels => \%textlabels,
  585                    -default=>$selected{textbook},
  586                    -onchange=>"submit();return true");
  587 
  588 
  589   my $library_keywords = $r->param('library_keywords') || '';
  590 
  591   my $view_problem_line = view_problems_line('lib_view', 'View Problems', $self->r);
  592 
  593   my $count_line = WeBWorK::Utils::ListingDB::countDBListings($r);
  594   if($count_line==0) {
  595     $count_line = "There are no matching pg files";
  596   } else {
  597     $count_line = "There are $count_line matching WeBWorK problem files";
  598   }
  599 
  600   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"},
  601     CGI::hidden(-name=>"library_is_basic", -default=>[2]),
  602     CGI::start_table({-width=>"100%"}),
  603     # Html done by hand since it is temporary
  604     CGI::Tr(CGI::td({-colspan=>4, -align=>"center"}, 'All Selected Constraints Joined by "And"')),
  605     CGI::Tr(
  606       CGI::td(["Subject:",
  607         CGI::popup_menu(-name=> 'library_subjects',
  608                       -values=>\@subjs,
  609                       -default=> $selected{dbsubject},
  610                        -onchange=>"submit();return true"
  611         )]),
  612       CGI::td({-colspan=>2, -align=>"right"},
  613         CGI::submit(-name=>"lib_select_subject", -value=>"Update Menus",
  614           -style=> $right_button_style))),
  615     CGI::Tr(
  616       CGI::td(["Chapter:",
  617         CGI::popup_menu(-name=> 'library_chapters',
  618                       -values=>\@chaps,
  619                       -default=> $selected{dbchapter},
  620                        -onchange=>"submit();return true"
  621         )]),
  622       CGI::td({-colspan=>2, -align=>"right"},
  623           CGI::submit(-name=>"library_reset", -value=>"Reset",
  624           -style=>$right_button_style))
  625     ),
  626     CGI::Tr(
  627       CGI::td(["Section:",
  628       CGI::popup_menu(-name=> 'library_sections',
  629                   -values=>\@sects,
  630                   -default=> $selected{dbsection},
  631               -onchange=>"submit();return true"
  632         )]),
  633       CGI::td({-colspan=>2, -align=>"right"},
  634           CGI::submit(-name=>"library_basic", -value=>"Basic Search",
  635           -style=>$right_button_style))
  636      ),
  637      CGI::Tr(
  638       CGI::td(["Textbook:", $text_popup]),
  639      ),
  640      CGI::Tr(
  641       CGI::td(["Text chapter:",
  642       CGI::popup_menu(-name=> 'library_textchapter',
  643                   -values=>\@textchaps,
  644                   -default=> $selected{textchapter},
  645               -onchange=>"submit();return true"
  646         )]),
  647      ),
  648      CGI::Tr(
  649       CGI::td(["Text section:",
  650       CGI::popup_menu(-name=> 'library_textsection',
  651                   -values=>\@textsecs,
  652                   -default=> $selected{textsection},
  653               -onchange=>"submit();return true"
  654         )]),
  655      ),
  656      CGI::Tr(CGI::td("Keywords:"),CGI::td({-colspan=>2},
  657        CGI::textfield(-name=>"library_keywords",
  658               -default=>$library_keywords,
  659               -override=>1,
  660               -size=>40))),
  661      CGI::Tr(CGI::td({-colspan=>3}, $view_problem_line)),
  662      CGI::Tr(CGI::td({-colspan=>3, -align=>"center"}, $count_line)),
  663      CGI::end_table(),
  664    ));
  665 
  666 }
  667 
  668 
  669 #####  Version 4 is the set definition file panel
  670 
  671 sub browse_setdef_panel {
  672   my $self = shift;
  673   my $r = $self->r;
  674   my $ce = $r->ce;
  675   my $library_selected = shift;
  676   my $default_value = "Select a Set Definition File";
  677   my @list_of_set_defs = get_set_defs($ce->{courseDirs}{templates});
  678   if(scalar(@list_of_set_defs) == 0) {
  679     @list_of_set_defs = (NO_LOCAL_SET_STRING);
  680   } elsif (not $library_selected or $library_selected eq $default_value) {
  681     unshift @list_of_set_defs, $default_value;
  682     $library_selected = $default_value;
  683   }
  684   my $view_problem_line = view_problems_line('view_setdef_set', 'View Problems', $self->r);
  685   my $popupetc = CGI::popup_menu(-name=> 'library_sets',
  686                                 -values=>\@list_of_set_defs,
  687                                 -default=> $library_selected).
  688     CGI::br().  $view_problem_line;
  689   if($list_of_set_defs[0] eq NO_LOCAL_SET_STRING) {
  690     $popupetc = "there are no set definition files in this course to look at."
  691   }
  692   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Browse from: ",
  693     $popupetc
  694   ));
  695 }
  696 
  697 sub make_top_row {
  698   my $self = shift;
  699   my $r = $self->r;
  700   my $ce = $r->ce;
  701   my %data = @_;
  702 
  703   my $list_of_local_sets = $data{all_db_sets};
  704   my $have_local_sets = scalar(@$list_of_local_sets);
  705   my $browse_which = $data{browse_which};
  706   my $library_selected = $r->param('library_sets');
  707   my $set_selected = $r->param('local_sets');
  708 
  709   my ($dis1, $dis2, $dis3, $dis4) = ("","","", "");
  710   $dis1 =  '-disabled' if($browse_which eq 'browse_library');
  711   $dis2 =  '-disabled' if($browse_which eq 'browse_local');
  712   $dis3 =  '-disabled' if($browse_which eq 'browse_mysets');
  713   $dis4 =  '-disabled' if($browse_which eq 'browse_setdefs');
  714 
  715   ##  Make buttons for additional problem libraries
  716   my $libs = '';
  717   foreach my $lib (sort(keys(%problib))) {
  718     $libs .= ' '. CGI::submit(-name=>"browse_$lib", -value=>$problib{$lib},
  719                                  ($browse_which eq "browse_$lib")? '-disabled': '')
  720       if (-d "$ce->{courseDirs}{templates}/$lib");
  721   }
  722   $libs = CGI::br()."or Problems from".$libs if $libs ne '';
  723 
  724   my $these_widths = "width: 23ex";
  725 
  726   if($have_local_sets ==0) {
  727     $list_of_local_sets = [NO_LOCAL_SET_STRING];
  728   } elsif (not $set_selected or $set_selected eq SELECT_SET_STRING) {
  729     unshift @{$list_of_local_sets}, SELECT_SET_STRING;
  730     $set_selected = SELECT_SET_STRING;
  731   }
  732   my $myjs = 'document.mainform.selfassign.value=confirm("Should I assign the new set to you now?\nUse OK for yes and Cancel for no.");true;';
  733 
  734   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"left"}, "Add problems to ",
  735     CGI::b("Target Set: "),
  736     CGI::popup_menu(-name=> 'local_sets',
  737             -values=>$list_of_local_sets,
  738             -default=> $set_selected),
  739     CGI::submit(-name=>"edit_local", -value=>"Edit Target Set"),
  740     CGI::hidden(-name=>"selfassign", -default=>[0]).
  741     CGI::br(),
  742     CGI::br(),
  743     CGI::submit(-name=>"new_local_set", -value=>"Create a New Set in This Course:",
  744     -onclick=>$myjs
  745     ),
  746     "  ",
  747     CGI::textfield(-name=>"new_set_name",
  748              -default=>"Name for new set here",
  749              -override=>1, -size=>30),
  750   ));
  751 
  752   print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  753 
  754   # Tidy this list up since it is used in two different places
  755   if ($list_of_local_sets->[0] eq SELECT_SET_STRING) {
  756     shift @{$list_of_local_sets};
  757   }
  758 
  759   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"},
  760     "Browse ",
  761     CGI::submit(-name=>"browse_library", -value=>"Problem Library", -style=>$these_widths, $dis1),
  762     CGI::submit(-name=>"browse_local", -value=>"Local Problems", -style=>$these_widths, $dis2),
  763     CGI::submit(-name=>"browse_mysets", -value=>"From This Course", -style=>$these_widths, $dis3),
  764     CGI::submit(-name=>"browse_setdefs", -value=>"Set Definition Files", -style=>$these_widths, $dis4),
  765     $libs,
  766   ));
  767 
  768   #print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  769   print CGI::hr();
  770 
  771   if ($browse_which eq 'browse_local') {
  772     $self->browse_local_panel($library_selected);
  773   } elsif ($browse_which eq 'browse_mysets') {
  774     $self->browse_mysets_panel($library_selected, $list_of_local_sets);
  775   } elsif ($browse_which eq 'browse_library') {
  776     $self->browse_library_panel();
  777   } elsif ($browse_which eq 'browse_setdefs') {
  778     $self->browse_setdef_panel($library_selected);
  779   } else { ## handle other problem libraries
  780     $self->browse_local_panel($library_selected,$browse_which);
  781   }
  782 
  783   print CGI::Tr(CGI::td({-bgcolor=>"black"}));
  784 
  785   print CGI::Tr(CGI::td({-class=>"InfoPanel", -align=>"center"},
  786     CGI::start_table({-border=>"0"}),
  787     CGI::Tr( CGI::td({ -align=>"center"},
  788       CGI::submit(-name=>"select_all", -style=>$these_widths,
  789                   -value=>"Mark All For Adding"),
  790       CGI::submit(-name=>"select_none", -style=>$these_widths,
  791                   -value=>"Clear All Marks"),
  792     )),
  793     CGI::Tr(CGI::td(
  794       CGI::submit(-name=>"update", -style=>$these_widths. "; font-weight:bold",
  795                   -value=>"Update Set"),
  796     CGI::submit(-name=>"rerandomize",
  797                 -style=>$these_widths,
  798                 -value=>"Rerandomize"),
  799     CGI::submit(-name=>"cleardisplay",
  800                 -style=>$these_widths,
  801                 -value=>"Clear Problem Display")
  802   )),
  803   CGI::end_table()));
  804 }
  805 
  806 sub make_data_row {
  807   my $self = shift;
  808   my $sourceFileName = shift;
  809   my $pg = shift;
  810   my $cnt = shift;
  811   my $mark = shift || 0;
  812 
  813   $sourceFileName =~ s|^./||; # clean up top ugliness
  814 
  815   my $urlpath = $self->r->urlpath;
  816   my $problem_output = $pg->{flags}->{error_flag} ?
  817     CGI::div({class=>"ResultsWithError"}, CGI::em("This problem produced an error"))
  818     : CGI::div({class=>"RenderSolo"}, $pg->{body_text});
  819   $problem_output .= $pg->{flags}->{comment} if($pg->{flags}->{comment});
  820 
  821 
  822   #if($self->{r}->param('browse_which') ne 'browse_library') {
  823   my $problem_seed = $self->{r}->param('problem_seed') || 0;
  824   my $edit_link = CGI::a({href=>$self->systemLink(
  825      $urlpath->newFromModule("WeBWorK::ContentGenerator::Instructor::PGProblemEditor",
  826         courseID =>$urlpath->arg("courseID"),
  827         setID=>"Undefined_Set",
  828         problemID=>"1"),
  829       params=>{sourceFilePath => "$sourceFileName", problemSeed=> $problem_seed}
  830       )}, "Edit it" );
  831 
  832   my $displayMode = $self->r->param("mydisplayMode");
  833   $displayMode = $self->r->ce->{pg}->{options}->{displayMode}
  834     if not defined $displayMode or $displayMode eq "None";
  835   my $try_link = CGI::a({href=>$self->systemLink(
  836     $urlpath->newFromModule("WeBWorK::ContentGenerator::Problem",
  837       courseID =>$urlpath->arg("courseID"),
  838       setID=>"Undefined_Set",
  839       problemID=>"1"),
  840     params =>{
  841       effectiveUser => scalar($self->r->param('user')),
  842       editMode => "SetMaker",
  843       problemSeed=> $problem_seed,
  844       sourceFilePath => "$sourceFileName",
  845       displayMode => $displayMode,
  846     }
  847   )}, "Try it");
  848 
  849   my %add_box_data = ( -name=>"trial$cnt",-value=>1,-label=>"Add this problem to the target set on the next update");
  850   if($mark & SUCCESS) {
  851     $add_box_data{ -label } .= " (just added this problem)";
  852   } elsif($mark & ADDED) {
  853     $add_box_data{ -checked } = 1;
  854   }
  855 
  856   print CGI::Tr({-align=>"left"}, CGI::td(
  857     CGI::div({-style=>"background-color: #DDDDDD; margin: 0px auto"},
  858       CGI::span({-style=>"float:left ; text-align: left"},"File name: $sourceFileName "),
  859       CGI::span({-style=>"float:right ; text-align: right"}, $edit_link, " ", $try_link)
  860     ), CGI::br(),
  861     CGI::checkbox(-name=>"hideme$cnt",-value=>1,-label=>"Don't show this problem on the next update"),
  862     CGI::br(),
  863     CGI::checkbox((%add_box_data)),
  864     CGI::hidden(-name=>"filetrial$cnt", -default=>[$sourceFileName]).
  865     CGI::p($problem_output),
  866   ));
  867 }
  868 
  869 sub clear_default {
  870   my $r = shift;
  871   my $param = shift;
  872   my $default = shift;
  873   my $newvalue = $r->param($param) || '';
  874   $newvalue = '' if($newvalue eq $default);
  875   $r->param($param, $newvalue);
  876 }
  877 
  878 sub pre_header_initialize {
  879   my ($self) = @_;
  880   my $r = $self->r;
  881   ## For all cases, lets set some things
  882   $self->{error}=0;
  883   my $ce = $r->ce;
  884   my $db = $r->db;
  885   my $maxShown = $r->param('max_shown') || MAX_SHOW_DEFAULT;
  886   $maxShown = 10000000 if($maxShown eq 'All'); # let's hope there aren't more
  887   my $library_basic = $r->param('library_is_basic') || 1;
  888 
  889   ## Fix some parameters
  890   clear_default($r,'library_subjects', ALL_SUBJECTS);
  891   clear_default($r,'library_chapters', ALL_CHAPTERS);
  892   clear_default($r,'library_sections', ALL_SECTIONS);
  893   clear_default($r,'library_textbook', ALL_TEXTBOOKS);
  894 
  895   ##  These directories will have individual buttons
  896   %problib = %{$ce->{courseFiles}{problibs}} if $ce->{courseFiles}{problibs};
  897 
  898   my $userName = $r->param('user');
  899   my $user = $db->getUser($userName); # checked
  900   die "record for user $userName (real user) does not exist."
  901     unless defined $user;
  902   my $authz = $r->authz;
  903   unless ($authz->hasPermissions($userName, "modify_problem_sets")) {
  904     return(""); # Error message already produced in the body
  905   }
  906 
  907   ## Now one action we have to deal with here
  908   if ($r->param('edit_local')) {
  909     my $urlpath = $r->urlpath;
  910     my $db = $r->db;
  911     my $checkset = $db->getGlobalSet($r->param('local_sets'));
  912     if (not defined($checkset)) {
  913       $self->{error} = 1;
  914       $self->addbadmessage('You need to select a "Target Set" before you can edit it.');
  915     } else {
  916       my $page = $urlpath->newFromModule('WeBWorK::ContentGenerator::Instructor::ProblemSetDetail', setID=>$r->param('local_sets'), courseID=>$urlpath->arg("courseID"));
  917       my $url = $self->systemLink($page);
  918       $self->reply_with_redirect($url);
  919     }
  920   }
  921 
  922   ## Next, lots of set up so that errors can be reported with message()
  923 
  924   ############# List of problems we have already printed
  925 
  926   $self->{past_problems} = get_past_problem_files($r);
  927   # if we don't end up reusing problems, this will be wiped out
  928   # if we do redisplay the same problems, we must adjust this accordingly
  929   my @past_marks = map {$_->[1]} @{$self->{past_problems}};
  930   my $none_shown = scalar(@{$self->{past_problems}})==0;
  931   my @pg_files=();
  932   my $use_previous_problems = 1;
  933   my $first_shown = $r->param('first_shown') || 0;
  934   my $last_shown = $r->param('last_shown');
  935   if (not defined($last_shown)) {
  936     $last_shown = -1;
  937   }
  938   my @all_past_list = (); # these are include requested, but not shown
  939   my $j = 0;
  940   while (defined($r->param("all_past_list$j"))) {
  941     push @all_past_list, $r->param("all_past_list$j");
  942     $j++;
  943   }
  944 
  945   ############# Default of which problem selector to display
  946 
  947   my $browse_which = $r->param('browse_which') || 'browse_local';
  948 
  949   my $problem_seed = $r->param('problem_seed') || 0;
  950   $r->param('problem_seed', $problem_seed); # if it wasn't defined before
  951 
  952   ## check for problem lib buttons
  953   my $browse_lib = '';
  954   foreach my $lib (keys %problib) {
  955     if ($r->param("browse_$lib")) {
  956       $browse_lib = "browse_$lib";
  957       last;
  958     }
  959   }
  960 
  961   ########### Start the logic through if elsif elsif ...
  962 
  963   ##### Asked to browse certain problems
  964   if ($browse_lib ne '') {
  965     $browse_which = $browse_lib;
  966     $r->param('library_sets', "");
  967     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  968   } elsif ($r->param('browse_library')) {
  969     $browse_which = 'browse_library';
  970     $r->param('library_sets', "");
  971     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  972   } elsif ($r->param('browse_local')) {
  973     $browse_which = 'browse_local';
  974     $r->param('library_sets', "");
  975     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  976   } elsif ($r->param('browse_mysets')) {
  977     $browse_which = 'browse_mysets';
  978     $r->param('library_sets', "");
  979     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  980   } elsif ($r->param('browse_setdefs')) {
  981     $browse_which = 'browse_setdefs';
  982     $r->param('library_sets', "");
  983     $use_previous_problems = 0; @pg_files = (); ## clear old problems
  984 
  985     ##### Change the seed value
  986 
  987   } elsif ($r->param('rerandomize')) {
  988     $problem_seed++;
  989     $r->param('problem_seed', $problem_seed);
  990     $self->addbadmessage('Changing the problem seed for display, but there are no problems showing.') if $none_shown;
  991 
  992     ##### Clear the display
  993 
  994   } elsif ($r->param('cleardisplay')) {
  995     @pg_files = ();
  996     $use_previous_problems=0;
  997     $self->addbadmessage('The display was already cleared.') if $none_shown;
  998 
  999     ##### View problems selected from the local list
 1000 
 1001   } elsif ($r->param('view_local_set')) {
 1002 
 1003     my $set_to_display = $r->param('library_sets');
 1004     if (not defined($set_to_display) or $set_to_display eq SELECT_LOCAL_STRING or $set_to_display eq "Found no directories containing problems") {
 1005       $self->addbadmessage('You need to select a set to view.');
 1006     } else {
 1007       $set_to_display = '.' if $set_to_display eq MY_PROBLEMS;
 1008       $set_to_display = substr($browse_which,7) if $set_to_display eq MAIN_PROBLEMS;
 1009       @pg_files = list_pg_files($ce->{courseDirs}->{templates},
 1010         "$set_to_display");
 1011       $use_previous_problems=0;
 1012     }
 1013 
 1014     ##### View problems selected from the a set in this course
 1015 
 1016   } elsif ($r->param('view_mysets_set')) {
 1017 
 1018     my $set_to_display = $r->param('library_sets');
 1019     if (not defined($set_to_display)
 1020         or $set_to_display eq "Select a Homework Set"
 1021         or $set_to_display eq NO_LOCAL_SET_STRING) {
 1022       $self->addbadmessage("You need to select a set from this course to view.");
 1023     } else {
 1024       my @problemList = $db->listGlobalProblems($set_to_display);
 1025       my $problem;
 1026       @pg_files=();
 1027       for $problem (@problemList) {
 1028         my $problemRecord = $db->getGlobalProblem($set_to_display, $problem); # checked
 1029         die "global $problem for set $set_to_display not found." unless
 1030           $problemRecord;
 1031         push @pg_files, $problemRecord->source_file;
 1032 
 1033       }
 1034       $use_previous_problems=0;
 1035     }
 1036 
 1037     ##### View from the library database
 1038 
 1039   } elsif ($r->param('lib_view')) {
 1040 
 1041     @pg_files=();
 1042     my @dbsearch = WeBWorK::Utils::ListingDB::getSectionListings($r);
 1043     my ($result, $tolibpath);
 1044     for $result (@dbsearch) {
 1045       $tolibpath = "Library/$result->{path}/$result->{filename}";
 1046 
 1047       ## Too clunky!!!!
 1048       push @pg_files, $tolibpath;
 1049     }
 1050     $use_previous_problems=0;
 1051 
 1052     ##### View a set from a set*.def
 1053 
 1054   } elsif ($r->param('view_setdef_set')) {
 1055 
 1056     my $set_to_display = $r->param('library_sets');
 1057     if (not defined($set_to_display)
 1058         or $set_to_display eq "Select a Set Definition File"
 1059         or $set_to_display eq NO_LOCAL_SET_STRING) {
 1060       $self->addbadmessage("You need to select a set from this course to view.");
 1061     } else {
 1062       @pg_files= $self->read_set_def($set_to_display);
 1063     }
 1064     $use_previous_problems=0;
 1065 
 1066     ##### Edit the current local problem set
 1067 
 1068   } elsif ($r->param('edit_local')) { ## Jump to set edit page
 1069 
 1070     ; # already handled
 1071 
 1072 
 1073     ##### Make a new local problem set
 1074 
 1075   } elsif ($r->param('new_local_set')) {
 1076     if ($r->param('new_set_name') !~ /^[\w .-]*$/) {
 1077       $self->addbadmessage("The name ".$r->param('new_set_name')." is not a valid set name.  Use only letters, digits, -, _, and .");
 1078     } else {
 1079       my $newSetName = $r->param('new_set_name');
 1080       # if we want to munge the input set name, do it here
 1081       $newSetName =~ s/\s/_/g;
 1082       $r->param('local_sets',$newSetName);
 1083       my $newSetRecord   = $db->getGlobalSet($newSetName);
 1084       if (defined($newSetRecord)) {
 1085   $self->addbadmessage("The set name $newSetName is already in use.  Pick a different name if you would like to start a new set.");
 1086       } else {      # Do it!
 1087         $newSetRecord = $db->{set}->{record}->new();
 1088         $newSetRecord->set_id($newSetName);
 1089         $newSetRecord->set_header("");
 1090         $newSetRecord->hardcopy_header("");
 1091         $newSetRecord->open_date(time()+60*60*24*7); # in one week
 1092         $newSetRecord->due_date(time()+60*60*24*7*2); # in two weeks
 1093         $newSetRecord->answer_date(time()+60*60*24*7*3); # in three weeks
 1094         eval {$db->addGlobalSet($newSetRecord)};
 1095         if ($@) {
 1096           $self->addbadmessage("Problem creating set $newSetName<br> $@");
 1097         } else {
 1098           $self->addgoodmessage("Set $newSetName has been created.");
 1099           my $selfassign = $r->param('selfassign') || "";
 1100           $selfassign = "" if($selfassign =~ /false/i); # deal with javascript false
 1101           if($selfassign) {
 1102             $self->assignSetToUser($userName, $newSetRecord);
 1103             $self->addgoodmessage("Set $newSetName was assigned to $userName.");
 1104           }
 1105         }
 1106       }
 1107     }
 1108 
 1109     ##### Add selected problems to the current local set
 1110 
 1111   } elsif ($r->param('update')) {
 1112     ## first handle problems to be added before we hide them
 1113     my($localSet, @selected);
 1114 
 1115     @pg_files = grep {($_->[1] & ADDED) != 0 } @{$self->{past_problems}};
 1116     @selected = map {$_->[0]} @pg_files;
 1117 
 1118     my @action_files = grep {$_->[1] > 0 } @{$self->{past_problems}};
 1119     # There are now good reasons to do an update without selecting anything.
 1120     #if(scalar(@action_files) == 0) {
 1121     #  $self->addbadmessage('Update requested, but no problems were marked.');
 1122     #}
 1123 
 1124     if (scalar(@selected)>0) {  # if some are to be added, they need a place to go
 1125       $localSet = $r->param('local_sets');
 1126       if (not defined($localSet) or
 1127           $localSet eq SELECT_SET_STRING or
 1128     $localSet eq NO_LOCAL_SET_STRING) {
 1129   $self->addbadmessage('You are trying to add problems to something, but you did not select a "Target Set" name as a target.');
 1130       } else {
 1131   my $newSetRecord  = $db->getGlobalSet($localSet);
 1132   if (not defined($newSetRecord)) {
 1133     $self->addbadmessage("You are trying to add problems to $localSet, but that set does not seem to exist!  I bet you used your \"Back\" button.");
 1134   } else {
 1135     my $addcount = add_selected($self, $db, $localSet);
 1136     if($addcount > 0) {
 1137       $self->addgoodmessage("Added $addcount problem".(($addcount>1)?'s':'').
 1138         " to $localSet.");
 1139     }
 1140   }
 1141       }
 1142     }
 1143     ## now handle problems to be hidden
 1144 
 1145     ## only keep the ones which are not hidden
 1146     @pg_files = grep {($_->[1] & HIDDEN) ==0 } @{$self->{past_problems}};
 1147     @past_marks = map {$_->[1]} @pg_files;
 1148     @pg_files = map {$_->[0]} @pg_files;
 1149     @all_past_list = (@all_past_list[0..($first_shown-1)],
 1150           @pg_files,
 1151           @all_past_list[($last_shown+1)..(scalar(@all_past_list)-1)]);
 1152     $last_shown = $first_shown+$maxShown -1;
 1153     $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list));
 1154 
 1155   } elsif ($r->param('next_page')) {
 1156     $first_shown = $last_shown+1;
 1157     $last_shown = $first_shown+$maxShown-1;
 1158     $last_shown = (scalar(@all_past_list)-1) if($last_shown>=scalar(@all_past_list));
 1159     @past_marks = ();
 1160   } elsif ($r->param('prev_page')) {
 1161     $last_shown = $first_shown-1;
 1162     $first_shown = $last_shown - $maxShown+1;
 1163 
 1164     $first_shown = 0 if($first_shown<0);
 1165     @past_marks = ();
 1166 
 1167   } elsif ($r->param('select_all')) {
 1168     @past_marks = map {1} @past_marks;
 1169   } elsif ($r->param('library_basic')) {
 1170     $library_basic = 1;
 1171     for my $jj (qw(textchapter textsection textbook)) {
 1172       $r->param('library_'.$jj,'');
 1173     }
 1174   } elsif ($r->param('library_advanced')) {
 1175     $library_basic = 2;
 1176   } elsif ($r->param('library_reset')) {
 1177     for my $jj (qw(chapters sections subjects textbook keywords)) {
 1178       $r->param('library_'.$jj,'');
 1179     }
 1180   } elsif ($r->param('select_none')) {
 1181     @past_marks = ();
 1182 
 1183     ##### No action requested, probably our first time here
 1184 
 1185   } else {
 1186     #my $c = $r->connection;
 1187     #print "Debug info: ". $r->get_remote_host ."<p>".  $c->remote_ip ;
 1188     ;
 1189   }       ##### end of the if elsif ...
 1190 
 1191 
 1192   ############# List of local sets
 1193 
 1194   my @all_db_sets = $db->listGlobalSets;
 1195   @all_db_sets = sortByName(undef, @all_db_sets);
 1196 
 1197   if ($use_previous_problems) {
 1198     @pg_files = @all_past_list;
 1199   } else {
 1200     $first_shown = 0;
 1201     $last_shown = scalar(@pg_files)<$maxShown ? scalar(@pg_files) : $maxShown;
 1202     $last_shown--;    # to make it an array index
 1203     @past_marks = ();
 1204   }
 1205   ############# Now store data in self for retreival by body
 1206   $self->{first_shown} = $first_shown;
 1207   $self->{last_shown} = $last_shown;
 1208   $self->{browse_which} = $browse_which;
 1209   $self->{problem_seed} = $problem_seed;
 1210   $self->{pg_files} = \@pg_files;
 1211   $self->{past_marks} = \@past_marks;
 1212   $self->{all_db_sets} = \@all_db_sets;
 1213   $self->{library_basic} = $library_basic;
 1214 }
 1215 
 1216 
 1217 sub title {
 1218   return "Library Browser";
 1219 }
 1220 
 1221 # hide view options panel since it distracts from SetMaker's built-in view options
 1222 sub options {
 1223   return "";
 1224 }
 1225 
 1226 sub body {
 1227   my ($self) = @_;
 1228 
 1229   my $r = $self->r;
 1230   my $ce = $r->ce;    # course environment
 1231   my $db = $r->db;    # database
 1232   my $j;      # garden variety counter
 1233 
 1234   my $userName = $r->param('user');
 1235 
 1236   my $user = $db->getUser($userName); # checked
 1237   die "record for user $userName (real user) does not exist."
 1238     unless defined $user;
 1239 
 1240   ### Check that this is a professor
 1241   my $authz = $r->authz;
 1242   unless ($authz->hasPermissions($userName, "modify_problem_sets")) {
 1243     print "User $userName returned " .
 1244       $authz->hasPermissions($user, "modify_problem_sets") .
 1245   " for permission";
 1246     return(CGI::div({class=>'ResultsWithError'},
 1247     CGI::em("You are not authorized to access the Instructor tools.")));
 1248   }
 1249 
 1250   ##########  Extract information computed in pre_header_initialize
 1251 
 1252   my $first_shown = $self->{first_shown};
 1253   my $last_shown = $self->{last_shown};
 1254   my $browse_which = $self->{browse_which};
 1255   my $problem_seed = $self->{problem_seed};
 1256   my @pg_files = @{$self->{pg_files}};
 1257   my @all_db_sets = @{$self->{all_db_sets}};
 1258 
 1259   my @pg_html=($last_shown>=$first_shown) ?
 1260     renderProblems(r=> $r,
 1261                    user => $user,
 1262                    problem_list => [@pg_files[$first_shown..$last_shown]],
 1263                    displayMode => $r->param('mydisplayMode')) : ();
 1264 
 1265   ##########  Top part
 1266   print CGI::startform({-method=>"POST", -action=>$r->uri, -name=>'mainform'}),
 1267     $self->hidden_authen_fields,
 1268       '<div align="center">',
 1269   CGI::start_table({-border=>2});
 1270   $self->make_top_row('all_db_sets'=>\@all_db_sets,
 1271          'browse_which'=> $browse_which);
 1272   print CGI::hidden(-name=>'browse_which', -default=>[$browse_which]),
 1273     CGI::hidden(-name=>'problem_seed', -default=>[$problem_seed]);
 1274   for ($j = 0 ; $j < scalar(@pg_files) ; $j++) {
 1275     print CGI::hidden(-name=>"all_past_list$j", -default=>$pg_files[$j]);
 1276   }
 1277 
 1278   print CGI::hidden(-name=>'first_shown', -default=>[$first_shown]);
 1279   print CGI::hidden(-name=>'last_shown', -default=>[$last_shown]);
 1280 
 1281 
 1282   ########## Now print problems
 1283   my $jj;
 1284   for ($jj=0; $jj<scalar(@pg_html); $jj++) {
 1285     $pg_files[$jj] =~ s|^$ce->{courseDirs}->{templates}/?||;
 1286     $self->make_data_row($pg_files[$jj+$first_shown], $pg_html[$jj], $jj+1, $self->{past_marks}->[$jj]);
 1287   }
 1288 
 1289   ########## Finish things off
 1290   print CGI::end_table();
 1291   print '</div>';
 1292   #  if($first_shown>0 or (1+$last_shown)<scalar(@pg_files)) {
 1293   my ($next_button, $prev_button) = ("", "");
 1294   if ($first_shown > 0) {
 1295     $prev_button = CGI::submit(-name=>"prev_page", -style=>"width:15ex",
 1296              -value=>"Previous page");
 1297   }
 1298   if ((1+$last_shown)<scalar(@pg_files)) {
 1299     $next_button = CGI::submit(-name=>"next_page", -style=>"width:15ex",
 1300              -value=>"Next page");
 1301   }
 1302   if (scalar(@pg_files)>0) {
 1303     print CGI::p(($first_shown+1)."-".($last_shown+1)." of ".scalar(@pg_files).
 1304      " shown.", $prev_button, " ", $next_button);
 1305   }
 1306   #  }
 1307   print CGI::endform(), "\n";
 1308 
 1309   return "";
 1310 }
 1311 
 1312 =head1 AUTHOR
 1313 
 1314 Written by John Jones, jj (at) asu.edu.
 1315 
 1316 =cut
 1317 
 1318 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9