[system] / trunk / webwork2 / lib / WeBWorK / ContentGenerator / Instructor / ProblemSetEditor.pm Repository:
ViewVC logotype

View of /trunk/webwork2/lib/WeBWorK/ContentGenerator/Instructor/ProblemSetEditor.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 959 - (download) (as text) (annotate)
Fri May 30 23:59:35 2003 UTC (9 years, 11 months ago) by malsyned
File size: 20221 byte(s)
The problem set editor now works for 0 users (global only) or 1 user.
Multi-user functionality is coming over the weekend.

To cause the editor to give you the ability to edit a student's record,
add editForStudent=name (where name is the student's login) to the
parameters sent to the ProblemSetEditor content generator.

Note that if you are using the GDBM backend, editing the "default"
professor records is the same as editing the global values, which can
surprise you if you're not ready for it.
-Dennis

    1 package WeBWorK::ContentGenerator::Instructor::ProblemSetEditor;
    2 use base qw(WeBWorK::ContentGenerator::Instructor);
    3 use WeBWorK::Utils qw(readFile formatDateTime parseDateTime);
    4 
    5 =head1 NAME
    6 
    7 WeBWorK::ContentGenerator::Instructor::ProblemSetEditor - Edit a set definition list
    8 
    9 =cut
   10 
   11 use strict;
   12 use warnings;
   13 use CGI qw();
   14 
   15 our $rowheight = 20;  #controls the length of the popup menus.
   16 our $libraryName;  #library directory name
   17 
   18 use constant SET_FIELDS => [qw(open_date due_date answer_date set_header problem_header)];
   19 use constant PROBLEM_FIELDS =>[qw(source_file value max_attempts)];
   20 use constant PROBLEM_USER_FIELDS => [qw(problem_seed status num_correct num_incorrect)];
   21 
   22 sub getSetName {
   23   my ($self, $pathSetName) = @_;
   24   if (ref $pathSetName eq "HASH") {
   25     $pathSetName = undef;
   26   }
   27   return $pathSetName;
   28 }
   29 
   30 sub title {
   31   my ($self, @components) = @_;
   32   return "Problem Set Editor - ".$self->{ce}->{courseName}." : ".$self->getSetName(@components);
   33 }
   34 
   35 sub initialize {
   36   my ($self, @components) = @_;
   37   my $r = $self->{r};
   38   my $db = $self->{db};
   39   my $setName = $self->getSetName(@components);
   40   my $setRecord = $db->getGlobalSet($setName);
   41   my @editForUser = $r->param('editForUser');
   42   # some useful booleans
   43   my $forUsers = scalar(@editForUser);
   44   my $forOneUser = $forUsers == 1;
   45 
   46   my %overrides;
   47   # build a quick lookup table
   48   foreach my $param ($r->param('override')) {
   49     $overrides{$param} = "DUMMY";
   50   }
   51 
   52   # The set form was submitted
   53   if (defined($r->param('submit_set_changes'))) {
   54     foreach (@{SET_FIELDS()}) {
   55       if (defined($r->param($_))) {
   56         if (m/_date$/) {
   57           $setRecord->$_(parseDateTime($r->param($_)));
   58         } else {
   59           $setRecord->$_($r->param($_));
   60         }
   61       }
   62     }
   63     $db->putGlobalSet($setRecord);
   64 
   65     if ($forOneUser) {
   66 
   67       my $userSetRecord = $db->getUserSet($editForUser[0], $setName);
   68       foreach my $field (@{SET_FIELDS()}) {
   69         if (defined $r->param("${field}_override")) {
   70           if (exists $overrides{$field}) {
   71             if ($field =~ m/_date$/) {
   72               $userSetRecord->$field(parseDateTime($r->param("${field}_override")));
   73             } else {
   74               $userSetRecord->$field($r->param("${field}_override"));
   75             }
   76           } else {
   77             $userSetRecord->$field(undef);
   78           }
   79 
   80           $db->putUserSet($userSetRecord);
   81         }
   82       }
   83     }
   84   }
   85   # the Problem form was submitted
   86   elsif (defined($r->param('submit_problem_changes'))) {
   87     my @problemList = $db->listGlobalProblems($setName);
   88     foreach my $problem (@problemList) {
   89       my $problemRecord = $db->getGlobalProblem($setName, $problem);
   90       foreach my $field (@{PROBLEM_FIELDS()}) {
   91         my $paramName = "problem_${problem}_${field}";
   92         if (defined($r->param($paramName))) {
   93           $problemRecord->$field($r->param($paramName));
   94         }
   95       }
   96       $db->putGlobalProblem($problemRecord);
   97 
   98       if ($forOneUser) {
   99         my $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem);
  100         foreach my $field (@{PROBLEM_USER_FIELDS()}) {
  101           my $paramName = "problem_${problem}_${field}";
  102           if (defined($r->param($paramName))) {
  103             $userProblemRecord->$field($r->param($paramName));
  104           }
  105         }
  106         foreach my $field (@{PROBLEM_FIELDS()}) {
  107           my $paramName = "problem_${problem}_${field}";
  108           if (defined($r->param("${paramName}_override"))) {
  109             if (exists $overrides{$paramName}) {
  110               $userProblemRecord->$field($r->param("${paramName}_override"));
  111             } else {
  112               $userProblemRecord->$field(undef);
  113             }
  114 
  115             $db->putUserProblem($userProblemRecord);
  116           }
  117         }
  118 
  119       }
  120     }
  121   }
  122 }
  123 
  124 # One wrinkle here: if $override is undefined, do the global thing, otherwise, it's truth value determines the checkbox.
  125 sub setRowHTML {
  126   my ($description, $fieldName, $fieldValue, $size, $override, $overrideValue) = @_;
  127 
  128   my $attributeHash = {type=>"text", name=>$fieldName, value=>$fieldValue};
  129   $attributeHash->{size} = $size if defined $size;
  130 
  131   my $html = CGI::td({}, [$description, CGI::input($attributeHash)]);
  132 
  133   if (defined $override) {
  134     $attributeHash->{name}="${fieldName}_override";
  135     $attributeHash->{value}=($override ? $overrideValue : "" );
  136 
  137     $html .= CGI::td({}, [
  138       CGI::checkbox({
  139         type=>"checkbox",
  140         name=>"override",
  141         label=>"override with:",
  142         value=>$fieldName,
  143         checked=>($override ? 1 : 0)
  144       }),
  145       CGI::input($attributeHash)
  146     ]);
  147   }
  148 
  149   return $html;
  150 
  151 }
  152 
  153 sub hiddenUserFields {
  154   my @editForUser = @_;
  155   my $return = "";
  156   foreach my $editUser (@editForUser) {
  157     $return .= CGI::input({type=>"hidden", name=>"editForUser", value=>$editUser});
  158   }
  159 
  160   return $return;
  161 }
  162 
  163 sub problemElementHTML {
  164   my ($fieldName, $fieldValue, $size, $override, $overrideValue) = @_;
  165   my $attributeHash = {type=>"text",name=>$fieldName,value=>$fieldValue};
  166   $attributeHash->{size} = $size if defined $size;
  167 
  168   my $html = CGI::input($attributeHash);
  169   if (defined $override) {
  170     $attributeHash->{name} = "${fieldName}_override";
  171     $attributeHash->{value} = ($override ? $overrideValue : "");
  172     $html = "default:".CGI::br().$html.CGI::br()
  173       . CGI::checkbox({
  174         type => "checkbox",
  175         name => "override",
  176         label => "override:",
  177         value => $fieldName,
  178         checked => ($override ? 1 : 0)
  179       })
  180       . CGI::br()
  181       . CGI::input($attributeHash);
  182   }
  183 
  184   return $html;
  185 }
  186 
  187 sub body {
  188   my ($self, @components) = @_;
  189   my $r = $self->{r};
  190   my $db = $self->{db};
  191   my $setName = $self->getSetName(@components);
  192   my $setRecord = $db->getGlobalSet($setName);
  193   my @editForUser = $r->param('editForUser');
  194   # some useful booleans
  195   my $forUsers = scalar(@editForUser);
  196   my $forOneUser = $forUsers == 1;
  197 
  198   ## Set Form ##
  199   my $userSetRecord;
  200   my %overrideArgs;
  201   if ($forOneUser) {
  202     $userSetRecord = $db->getUserSet($editForUser[0], $setName);
  203     foreach my $field (@{SET_FIELDS()}) {
  204       $overrideArgs{$field} = [defined $userSetRecord->$field, ($field =~ /_date$/ ? formatDateTime($userSetRecord->$field) : $userSetRecord->$field)];
  205     }
  206   } else {
  207     foreach my $field (@{SET_FIELDS()}) {
  208       $overrideArgs{$field} = [undef, undef];
  209     }
  210   }
  211 
  212   print CGI::h2({}, "Set Data"), "\n";
  213   print CGI::start_form({method=>"post", action=>$r->uri}), "\n";
  214   print CGI::table({},
  215     CGI::Tr({}, [
  216       setRowHTML("Open Date:", "open_date", formatDateTime($setRecord->open_date), undef, @{$overrideArgs{open_date}})."\n",
  217       setRowHTML("Due Date:", "due_date", formatDateTime($setRecord->due_date), undef, @{$overrideArgs{due_date}})."\n",
  218       setRowHTML("Answer Date:", "answer_date", formatDateTime($setRecord->answer_date), undef, @{$overrideArgs{answer_date}})."\n",
  219       setRowHTML("Set Header:", "set_header", $setRecord->set_header, undef, @{$overrideArgs{set_header}})."\n",
  220       setRowHTML("Problem Header:", "problem_header", $setRecord->problem_header, undef, @{$overrideArgs{problem_header}})."\n"
  221     ])
  222   );
  223 
  224   print hiddenUserFields(@editForUser);
  225   print $self->hidden_authen_fields;
  226   print CGI::input({type=>"submit", name=>"submit_set_changes", value=>"Save Set"});
  227   print CGI::end_form();
  228 
  229   ## Problems Form ##
  230   print CGI::h2({}, "Problems");
  231 
  232   my @problemList = $db->listGlobalProblems($setName);
  233 
  234   print CGI::start_form({method=>"POST", action=>$r->uri});
  235   print CGI::start_table({border=>1, cellpadding=>4});
  236   print CGI::Tr({}, CGI::th({}, [
  237     "Problem",
  238     ($forUsers ? ("Status", "Problem Seed") : ()),
  239     "Source File", "Max. Attempts", "Weight",
  240     ($forUsers ? ("Number Correct", "Number Incorrect") : ())
  241   ]));
  242   foreach my $problem (sort {$a <=> $b} @problemList) {
  243     my $problemRecord = $db->getGlobalProblem($setName, $problem);
  244     my $problemID = $problemRecord->problem_id;
  245     my $userProblemRecord;
  246     my %problemOverrideArgs;
  247 
  248     if ($forOneUser) {
  249       $userProblemRecord = $db->getUserProblem($editForUser[0], $setName, $problem);
  250       foreach my $field (@{PROBLEM_FIELDS()}) {
  251         $problemOverrideArgs{$field} = [defined $userProblemRecord->$field, $userProblemRecord->$field];
  252       }
  253 #   } elsif ($forUsers) {
  254 #     foreach my $field (@{PROBLEM_FIELDS()}) {
  255 #       $problemOverrideArgs{$field} = ["", ""];
  256 #     }
  257     } else {
  258       foreach my $field (@{PROBLEM_FIELDS()}) {
  259         $problemOverrideArgs{$field} = [undef, undef];
  260       }
  261     }
  262 
  263     print CGI::Tr({},
  264       CGI::td({}, [
  265         $problemID,
  266         ($forUsers ? (
  267           problemElementHTML("problem_${problemID}_status", $userProblemRecord->status, "7"),
  268           problemElementHTML("problem_${problemID}_problem_seed", $userProblemRecord->problem_seed, "7"),
  269         ) : ()),
  270         problemElementHTML("problem_${problemID}_source_file", $problemRecord->source_file, "40", @{$problemOverrideArgs{source_file}}),
  271         problemElementHTML("problem_${problemID}_max_attempts",$problemRecord->max_attempts,"7", @{$problemOverrideArgs{max_attempts}}),
  272         problemElementHTML("problem_${problemID}_value",$problemRecord->value,"7", @{$problemOverrideArgs{value}}),
  273         ($forUsers ? (
  274           problemElementHTML("problem_${problemID}_num_correct", $userProblemRecord->num_correct, "7"),
  275           problemElementHTML("problem_${problemID}_num_incorrect", $userProblemRecord->num_incorrect, "7")
  276         ) : ())
  277       ])
  278 
  279     )
  280   }
  281   print CGI::end_table();
  282   print hiddenUserFields(@editForUser);
  283   print $self->hidden_authen_fields;
  284   print CGI::input({type=>"submit", name=>"submit_problem_changes", value=>"Save Problems"});
  285   print CGI::end_form();
  286 
  287   return "";
  288 }
  289 
  290 sub mike_body {
  291   my $self = shift;
  292 
  293   # test area
  294   my $r = $self->{r};
  295   my $db = $self->{db};
  296 
  297   my $user = $r->param('user');
  298   my $key = $db->getKey($user)->key();
  299 
  300 
  301   ################
  302   # Gathering info
  303   # What is needed
  304   #     $setName  -- formerly the name of the set definition file
  305   #     $formURL -- the action URL for the form
  306   #     $libraryName  -- the name of the available library
  307   #     $setDirectory  -- the current library directory
  308   #     $oldSetDirectory -- the previous library directory
  309   # $problemName    -- the name of the library problem (in the previous library directory)
  310   #     $problemList    -- the contents of the textarea form
  311   #     answer dates
  312   my ($setName,$formURL,
  313     $libraryName,$setDirectory,$oldSetDirectory,
  314     $problemName,$problemList,
  315     $openDate,$dueDate,$answerDate) = $self->gatherInfo();
  316 
  317   #########################################################################
  318   # Determine a name for this set
  319   #########################################################################
  320   # Determine the set number, if there is one. Otherwise make setName = "new set".
  321   # FIXME:
  322 # my ($path_info,@components) = $self->gatherInfo();
  323 # my $setName = $components[0];  # get GET  address for set name
  324 
  325   # Override the setName if it is defined in a form.
  326 # $setName = $r->param('setName') if defined($r->param('setName'));
  327 
  328 
  329   #########################################################################
  330   # determine the library set directory
  331   #########################################################################
  332 #   $libraryName = $self->{ce}->{courseDirs}->{templates};
  333 #   my $setDirectory = $r->param('setDirectory');
  334 # my $oldSetDirectory = $r->param('oldSetDirectory');
  335 
  336   #FIXME:
  337   # A user can select a new set AND a problem (in the old set) but the problem won't be in the new set!
  338   # In other words we must prevent the user from changing the problem and the set simultaneously.
  339   # We solve this by defining a hidden variable oldSetDirectory which matches the currently displayed problem list
  340   # the problem entry for the textarea element and the viewProblem url are
  341   # formed using this old version of setDefinition
  342 
  343 
  344 
  345   # Determine  values for strings
  346   #########################################################################
  347   #text area region, adding problems to the list
  348   #########################################################################
  349 
  350   my $textAreaString;
  351   #FIXME:  -- this does not handle multiple problem selections correctly.
  352 #   my $problemName = $r->param('pgProblem');
  353 #   my $problemList = $r->param('problemList');
  354 
  355   # Initialize the textarea string if it is empty or hasn't been defined.
  356   $problemList = $self->gatherProblemList($setName) unless defined($problemList) and $problemList =~/\S/;
  357 
  358   my $problemEntry = $oldSetDirectory.'/'.$problemName.", 1, -1 \r\n";
  359   # add the new problem entry if the address is complete. (still buggy -- how do insure that oldSetDirectory is not empty?
  360   $problemList .= $problemEntry unless $problemEntry =~ m|^/|;  # don't print if oldSetDirectory name is empy (FIXME: -- more checks are needed?)
  361   # format the complete textArea string
  362   $textAreaString = CGI::textarea({"name"=>"problemList", "cols"=>"40", "rows"=>$rowheight, "default"=>$problemList});
  363 
  364   #Determine the headline for the page
  365 
  366 
  367   #FIXME:   Debugging code
  368 #   my $header = "Choose problems from $libraryName directory" .
  369 #     "<p>This form is not yet operational.
  370 #     <p>SetDirectory is $setDirectory.
  371 #     <p>formURL is $formURL
  372 #     <p>path_info  is $path_info";
  373   my $header = '';
  374 
  375 
  376   #########################################################################
  377   # Define the popup strings used for selecting the library set directory, and the problem from that directory
  378   #FIXME:
  379   # he problem of multiple selections needs to be handled properly.
  380   #########################################################################
  381   my $popUpSetDirectoryString = $self->fetchSetDirectories($setDirectory);  #pass default choice as current directory
  382   my $popUpPGProblemString = $self->fetchPGproblems($setDirectory);
  383 
  384 
  385   #########################################################################
  386   # Define a link to view the problem
  387   #FIXME:
  388   # Currently this link used the webwork problem library, which might be out of
  389   # sync with the local library
  390   #########################################################################
  391 
  392 
  393   my $viewProblemLink;
  394   if ( (defined($oldSetDirectory) and defined($problemName)) ) {
  395     $viewProblemLink = "View: "
  396       . CGI::a({
  397           "href"=>"http://webhost.math.rochester.edu/webworkdocs/ww/pgView/$oldSetDirectory/$problemName",
  398           "target"=>"_probwindow"
  399         }, "$oldSetDirectory/$problemName");
  400   } else {
  401     $viewProblemLink = '';
  402 
  403   }
  404   #########################################################################
  405   # Format the page
  406   #########################################################################
  407 
  408   return CGI::p($header)
  409     #CGI::start_form(-action=>"/webwork/mth143/instructor/problemSetEditor/"),
  410     . CGI::start_form(-action=>$formURL)
  411     . CGI::table( {-border=>2},
  412       CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
  413         CGI::th('Editing set : ')
  414         . CGI::td(CGI::textfield(  -name=>'setName',-size=>'20',-value=>$setName,-override=>1))
  415         . CGI::td(CGI::submit(-name=>'submitButton',-value=>'Save'))
  416       )
  417       . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
  418         CGI::td($textAreaString)
  419         . CGI::td($popUpSetDirectoryString)
  420         . CGI::td($popUpPGProblemString)
  421 
  422       )
  423        #(defined($viewProblemLink)) ?
  424        #  CGI::Tr({"align"=>"center","valign"=>"top"}, CGI::th({"colspan"="3"}, $viewProblemLink))
  425        #  : '',
  426       . CGI::Tr( {-align=>'CENTER',-valign=>'TOP'},
  427         CGI::th([$viewProblemLink,
  428           CGI::submit(-name=>'submitButton'  , -value =>'Select set'),
  429           CGI::submit(-name=>'submitButton'  , -value =>'Choose problem')
  430         ])
  431       )
  432       . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
  433         CGI::th(["Open date","Due date", "Answer date"])
  434       )
  435       . CGI::Tr({-align=>'CENTER',-valign=>'TOP'},
  436           CGI::td(CGI::textfield(  -name=>'open_date',   -size=>'20', -value=>$openDate))
  437         . CGI::td(CGI::textfield(-name=>'due_date',    -size=>'20', -value=>$dueDate))
  438         . CGI::td(CGI::textfield(-name=>'answer_date', -size=>'20', -value=>$answerDate))
  439       )
  440       . CGI::Tr({"align"=>"center", "valign"=>"top"},
  441         CGI::td({"colspan"=>"3"}, "View entire set (pdf format) -- not yet implemented")
  442       )
  443     )
  444     . $self->hidden_authen_fields
  445     . CGI::hidden(-name=>'oldSetDirectory', -value=>$setDirectory)
  446     . CGI::end_form()
  447 #   "<p> the parameters passed are "  #FIXME: -- debugging code
  448 #   . join("<BR>", %{$r->param()}) . $self->gatherProblemList($setName)."setName is $setName";
  449   ;
  450 
  451 }
  452 
  453 sub gatherInfo {
  454   #FIXME: This is very much hacked together.  In particular can we pass the key inside the post?
  455   my $self      = shift;
  456   my $ce        =   $self->{ce};
  457   my $r       = $self->{r};
  458   my $path_info     = $r->path_info || "";
  459 
  460   ## Determine the set name
  461   my $remaining_path  = $path_info;
  462   $remaining_path =~ s/^.*problemSetEditor//;
  463   my($junk, $setName, @components) = split "/", $remaining_path;
  464   # Override the setName if it is defined in a form.
  465   $setName = $r->param('setName') if defined($r->param('setName'));
  466   # FIXME:?? -- this insures backward compatibility with the old file naming convention.
  467   $setName = "set$setName" unless $setName =~/^set/;
  468 
  469   # Find the URL for the form
  470   $path_info =~s|problemSetEditor.*$|problemSetEditor/|;   # remove the setName, if any, from the path
  471   my $formURL = "/webwork$path_info";   # . $setName$self->url_authen_args();
  472 
  473   #########################################################################
  474   # determine the library name and set directory
  475   #########################################################################
  476   $libraryName = $ce->{courseDirs}->{templates};
  477   my $setDirectory = $r->param('setDirectory');
  478   my $oldSetDirectory = $r->param('oldSetDirectory');
  479 
  480   # Determine the problem name
  481   #FIXME  -- this does not handle multiple problem selections correctly.
  482   my $problemName = $r->param('pgProblem');
  483   # Determine the text area string (contents of set definition "file")
  484   my $problemList = $r->param('problemList');
  485 
  486   # get answer dates
  487 
  488   my $openDate  = $r->param('open_date');
  489   $openDate   = "" unless defined($openDate);
  490   my $dueDate   = $r->param('due_date');
  491   $dueDate    = "" unless defined($dueDate);
  492   my $answerDate  = $r->param('answer_date');
  493   $answerDate   = "" unless defined($answerDate);
  494 
  495   ($setName,$formURL,$libraryName,$setDirectory,$oldSetDirectory,$problemName,$problemList,$openDate,$dueDate,$answerDate);
  496 }
  497 
  498 sub gatherProblemList {   #workaround for obtaining the definition of a problem set (awaiting implementation of db function)
  499   my $self = shift;
  500   my $setName = shift;
  501   my $output = "";
  502   if ( defined($setName) and $setName ne "" ) {
  503     my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
  504     my $fileName = "$templateDirectory/$setName.def";
  505     my @output =  split("\n",WeBWorK::Utils::readFile($fileName) );
  506     @output = grep  /\.pg/,   @output;     # only get the .pg files
  507     @output = grep  !/Header/, @output;   # eliminate header files
  508     $output = join("\n",@output);
  509   } else {
  510     $output = "No set name |$setName| is defined";
  511   }
  512 
  513 
  514   return  $output
  515 
  516 
  517 
  518 
  519 }
  520 sub fetchSetDirectories {
  521 
  522   my $self = shift;
  523   my $defaultChoice = shift;
  524   my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
  525   opendir SETDEFDIR, $templateDirectory
  526     or return "Can't open directory $templateDirectory";
  527 
  528   my @allFiles = grep !/^\./, readdir SETDEFDIR;
  529   closedir  SETDEFDIR;
  530 
  531   ## filter to find only the set directories
  532   ## -- it is assumed that these directories don't contain a period in their names
  533   ## and that all other files do.  Directories names must also begin with "set".
  534   ## A better plan would be to read only the names of directories, not files.
  535 
  536   ## sort the directories
  537   my @setDefFiles = grep /^set[^\.]*$/, @allFiles;
  538   my @sortedNames = sort @setDefFiles;
  539 
  540   return "$libraryName/" . CGI::br(). CGI::popup_menu(-name=>'setDirectory', -size=>$rowheight,
  541    -values=>\@sortedNames, -default=>$defaultChoice ) .CGI::br() ;
  542 }
  543 
  544 sub fetchPGproblems {
  545 
  546   my $self = shift;
  547   my $setDirectory = shift;
  548 
  549   # Handle default for setDirectory
  550   # FIXME -- this is not bullet proof
  551   $setDirectory = "set0" unless defined($setDirectory);
  552   my $templateDirectory = $self->{ce}->{courseDirs}->{templates};
  553 
  554   ##
  555   opendir SETDEFDIR, "$templateDirectory/$setDirectory"
  556     or return "Can't open directory $templateDirectory/$setDirectory";
  557 
  558   my @allFiles = grep !/^\./, readdir SETDEFDIR;
  559   closedir  SETDEFDIR;
  560 
  561   ## filter to find only pg problems
  562   ## Some problems are themselves in directories (if they have auxiliary
  563   ## .png's for example.  This eventuallity needs to be handled.
  564 
  565   ## sort the directories
  566   my @pgFiles = grep /\.pg$/, @allFiles;
  567   my @sortedNames = sort @pgFiles;
  568 
  569   return "$setDirectory ". CGI::br() .
  570   CGI::popup_menu(-name=>'pgProblem', -size=>$rowheight, -multiple=>undef, -values=>\@sortedNames,  ) .
  571   CGI::br() ;
  572 }
  573 1;

aubreyja at gmail dot com
ViewVC Help
Powered by ViewVC 1.0.9