]> git.mjollnir.org Git - moodle.git/commitdiff
quiz settings: MDL-18485 Improve quiz settings form
authortjhunt <tjhunt>
Tue, 10 Mar 2009 08:39:51 +0000 (08:39 +0000)
committertjhunt <tjhunt>
Tue, 10 Mar 2009 08:39:51 +0000 (08:39 +0000)
* Reorder form fields to group things more logically.
** and on the corresponding admin page too.

* Set some options to be 'Advanced' by default:
** Apply penalties.
** Each attempt builds on the last.
** Decimal places for question grades.
** The five 'Extra restrictions on attempts' settings. (password, etc.)
* Admins can still change this to suit their institiution at Administration > Plugins > Activity modules > Quiz.
* These new defaults are applied if the admin had not previously set any fields to be advanced.

* Disable some filds when they are not applicable:
** Grading method, if num attempts = 1
** Penaly scheme, if adaptive mode = no
** Each attempt builds of last, if num attempts = 1
** Review after quiz closed options, if no close date.
** Delay between 1st and 2nd attempts, if num attempts = 1
** Delay between later attempts, if num attempts < 3

* Convert quiz.timelimit to be in seconds, for consistency, and ready for the new duration field type (MDL 18500).
** Including ensuring that backup and restore is backwards compatible.

* MDL-5537 New setting, questiondecimalpoints, so, for example, you can show the quiz grade as an integer, but have fractional question grades.
** There is a 'Same as overall decimal points' option, which is the default.

* Improve some field labels.

* Make corresponding changes in the help files.

20 files changed:
lang/en_utf8/quiz.php
lib/questionlib.php
mod/quiz/accessrules.php
mod/quiz/attemptlib.php
mod/quiz/backuplib.php
mod/quiz/db/install.xml
mod/quiz/db/upgrade.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/mod_form.php
mod/quiz/report/reportlib.php
mod/quiz/restorelib.php
mod/quiz/restorelibpre15.php
mod/quiz/review.php
mod/quiz/settingstree.php
mod/quiz/simpletest/testaccessrules.php
mod/quiz/simpletest/testlib.php
mod/quiz/simpletest/testlocallib.php
mod/quiz/version.php
mod/quiz/view.php

index 2faa8b71573fef17abf1124f662eddbde6b1cd88..bb4b6a34454fdd2bd5a26ccd89885f91646d926f 100644 (file)
@@ -145,15 +145,19 @@ $string['completedon'] = 'Completed on';
 $string['configadaptive'] = 'If you choose Yes for this option then the student will be allowed multiple responses to a question even within the same attempt at the quiz.';
 $string['configattemptsallowed'] = 'Restriction on the number of attempts students are allowed at the quiz.';
 $string['configdecimaldigits'] = 'Number of digits that should be shown after the decimal point when displaying grades.';
+$string['configdecimalplaces'] = 'Number of digits that should be shown after the decimal point when displaying grades for the quiz.';
+$string['configdecimalplacesquestion'] = 'Number of digits that should be shown after the decimal point when displaying the grade for individual questions.';
 $string['configdelay1'] = 'If you set a time delay, then a student has to wait for that time before they can attempt a quiz after the first attempt.';
 $string['configdelay2'] = 'If you set a time delay here, then a student has to wait for that time before they can attempt their third or later attempts.';
+$string['configdelay1st2nd'] = 'If you set a time delay here, the student cannot start their second attempt until this much time has passed since the end of their first attempt.';
+$string['configdelaylater'] = 'If you set a time delay here, the student cannot start their third, fourth, ... attempt until this much time has passed since the end of their previous attempt.';
 $string['configeachattemptbuildsonthelast'] = 'If multiple attempts are allowed then each new attempt contains the results of the previous attempt.';
 $string['configgrademethod'] = 'When multiple attempts are allowed, which method should be used to calculate the student\'s final grade for the quiz.';
 $string['configintro'] = 'The values you set here define the default values that are used in the settings form when you create a new quiz. You can also configure which quiz settings are considered advanced.';
 $string['configmaximumgrade'] = 'The default grade that the quiz grade is scaled to be out of.';
 $string['confignewpageevery'] = 'When adding questions to the quiz page breaks will automatically be inserted according to the setting you choose here.';
 $string['configpenaltyscheme'] = 'Penalty subtracted for each wrong response in adaptive mode.';
-$string['configpopup'] = 'Use JavaScript tricks to try to restrict copy and paste, etc. during quiz attempts.';
+$string['configpopup'] = 'Force the attempt to open in a popup window, and use JavaScript tricks to try to restrict copy and paste, etc. during quiz attempts.';
 $string['configrequirepassword'] = 'Students must enter this password before they can attempt the quiz.';
 $string['configrequiresubnet'] = 'Students can only attempt the quiz from these computers.';
 $string['configreviewoptions'] = 'These options control what information users can see when they review a quiz attempt or look at the quiz reports.';
@@ -161,6 +165,7 @@ $string['configshowuserpicture'] = 'Show the user\'s picture on screen during at
 $string['configshufflequestions'] = 'If you enable this option, then the order of questions in  the quiz will be randomly shuffled each time a student attempts the quiz.';
 $string['configshufflewithin'] = 'If you enable this option, then the parts making up the individual questions will be randomly shuffled each time a student starts an attempt at this quiz, provided the option is also enabled in the question settings.';
 $string['configtimelimit'] = 'Default time limit for quizzes in minutes. 0 mean no time limit.';
+$string['configtimelimitsec'] = 'Default time limit for quizzes in seconds. 0 mean no time limit.';
 $string['configurerandomquestion'] = 'Configure question';
 $string['confirmclose'] = 'You are about to close this attempt. Once you close the attempt you will no longer be able to change your answers.';
 $string['confirmserverdelete'] = 'Are you sure you want to remove the server <b>$a</b> from the list?';
@@ -195,6 +200,8 @@ $string['datasetdefinitions'] = 'Reusable dataset definitions for category $a';
 $string['datasetnumber'] = 'Number';
 $string['daysavailable'] = 'Days available';
 $string['decimaldigits'] = 'Decimal digits in grades';
+$string['decimalplaces'] = 'Decimal places in grades';
+$string['decimalplacesquestion'] = 'Decimal places in question grades';
 $string['decimalformat'] = 'decimals';
 $string['decimalpoints'] = 'Decimal points';
 $string['decimals'] = 'with $a';
@@ -203,6 +210,8 @@ $string['defaultgrade'] = 'Default question grade';
 $string['defaultinfo'] = 'The default category for questions.';
 $string['delay1'] = 'Time delay between first and second attempt';
 $string['delay2'] = 'Time delay between later attempts';
+$string['delay1st2nd'] = 'Enforced delay between 1st and 2nd attempts';
+$string['delaylater'] = 'Enforced delay between later attempts';
 $string['deleteattemptcheck'] = 'Are you absolutely sure you want to completely delete these attempts?';
 $string['deletequestioncheck'] = 'Are you absolutely sure you want to delete \'$a\'?';
 $string['deletequestionscheck'] = 'Are you absolutely sure you want to delete the following questions?<br /><br />$a';
@@ -284,6 +293,7 @@ $string['exportingquestions'] = 'Questions are being exported to file';
 $string['exportname'] = 'File name';
 $string['exportnameformat'] = '%%Y%%m%%d-%%H%%M';
 $string['exportquestions'] = 'Export questions to file';
+$string['extraattemptrestrictions'] = 'Extra restrictions on attempts';
 $string['false'] = 'False';
 $string['feedback'] = 'Feedback';
 $string['feedbackerrorboundaryformat'] = 'Feedback grade boundaries must be either a percentage or a number. The value you entered in boundary $a is not recognised.';
@@ -376,6 +386,11 @@ $string['itemsource'] = 'Item Source';
 $string['itemsourceformat'] = 'Item Source Format';
 $string['itemtypes'] = 'Remote Question Types';
 $string['lastanswer'] = 'Your last answer was';
+$string['layout'] = 'Layout';
+$string['layoutasshown'] = 'Page layout as shown.';
+$string['layoutasshownwithpages'] = 'Page layout as shown. <small>(Automatic new page every $a questions.)</small>';
+$string['layoutshuffledandpaged'] = 'Questions randomly shuffled with $a questions per page.';
+$string['layoutshuffledsinglepage'] = 'Questions randomly shuffled, all on one page.';
 $string['learnwise'] = 'Learnwise format';
 $string['link'] = 'Link';
 $string['listitems'] = 'Listing of Items in Quiz';
@@ -498,6 +513,7 @@ $string['qtypename'] = 'type, name';
 $string['question'] = 'Question';
 $string['questionbankcontents'] = 'Question Bank contents';
 $string['questionbankmanagement'] = 'Question Bank management';
+$string['questionbehaviour'] = 'Question behaviour';
 $string['questioncats'] = 'Question Categories';
 $string['questiondeleted'] = 'This question has been deleted. Please contact your teacher';
 $string['questioninuse'] = 'The question \'$a->questionname\' is currently being used in: <br />$a->quiznames<br />The question will not be deleted from these quizzes but only from the category list.';
@@ -618,6 +634,7 @@ $string['reviewresponse'] = 'Review response';
 $string['reviewthisattempt'] = 'Review your responses to this attempt';
 $string['rqp'] = 'Remote Question';
 $string['rqps'] = 'Remote Questions';
+$string['sameasoverall'] = 'Same as for overall grades';
 $string['save'] = 'Save';
 $string['saveandedit'] = 'Save changes and edit questions';
 $string['saveattemptfailed'] = 'Failed to save the current quiz attempt.';
@@ -650,6 +667,7 @@ $string['showcorrectanswer'] = 'In feedback, show correct answers?';
 $string['showdetailedmarks'] = 'Show mark details';
 $string['showfeedback'] = 'After answering, show feedback?';
 $string['showhidden'] = 'Also show old questions';
+$string['showinsecurepopup'] = 'Use a \'secure\' popup window for attempts';
 $string['shownoattempts'] = 'Show students with no attempts';
 $string['shownoattemptsonly'] = 'Show only students with no attempts';
 $string['showquestiontext'] = 'Show question text in the question list';
@@ -658,8 +676,7 @@ $string['showuserpicture'] = 'Show the user\'s picture';
 $string['shuffle'] = 'Shuffle';
 $string['shuffleanswers'] = 'Shuffle answers';
 $string['shufflequestions'] = 'Shuffle questions';
-$string['shufflequestionsx'] = 'Shuffle questions: $a';
-$string['shufflequestionsselected'] = '* Shuffle questions has been set so question order is random. As a result, the button Reorder questions has been disabled. You can change this in $a.';
+$string['shufflequestionsselected'] = 'Shuffle questions has been set, so some actions relating to pages are not available. To change the shuffle option go to $a.';
 $string['shufflewithin'] = 'Shuffle within questions';
 $string['significantfigures'] = 'with $a';
 $string['significantfiguresformat'] = 'significant figures';
@@ -690,6 +707,7 @@ $string['timeleft'] = 'Time left';
 $string['timelimit'] = 'Time limit';
 $string['timelimitexeeded'] = 'Sorry! Quiz time limit exceeded!';
 $string['timelimitmin'] = 'Time limit (minutes)';
+$string['timelimitsec'] = 'Time limit (seconds)';
 $string['timestr'] = '%%H:%%M:%%S on %%d/%%m/%%y';
 $string['timesup'] = 'Time is up!';
 $string['timetaken'] = 'Time taken';
index 138dbfc33baf0f65b3b4e0131df9418c0674b6e3..e6e8c139713b5455b5caa598558e0cf7fd7cdb46 100644 (file)
@@ -1753,7 +1753,7 @@ function question_apply_penalty_and_timelimit(&$question, &$state, $attempt, $cm
     // deal with timelimit
     if ($cmoptions->timelimit) {
         // We allow for 5% uncertainty in the following test
-        if ($state->timestamp - $attempt->timestart > $cmoptions->timelimit * 63) {
+        if ($state->timestamp - $attempt->timestart > $cmoptions->timelimit * 1.05) {
             $cm = get_coursemodule_from_instance('quiz', $cmoptions->id);
             if (!has_capability('mod/quiz:ignoretimelimits', get_context_instance(CONTEXT_MODULE, $cm->id),
                     $attempt->userid, false)) {
@@ -2007,12 +2007,25 @@ function question_hash($question) {
 
 /**
  * Round a grade to to the correct number of decimal places, and format it for display.
+ * If $cmoptions->questiondecimalpoints is set, that is used, otherwise
+ * else if $cmoptions->decimalpoints is used,
+ * otherwise a default of 2 is used, but this should not be relied upon, and generated a developer debug warning.
+ * However, if $cmoptions->questiondecimalpoints is -1, the means use $cmoptions->decimalpoints.
  *
- * @param object $cmoptions The modules settings, only ->decimalpoints is used.
+ * @param object $cmoptions The modules settings.
  * @param float $grade The grade to round.
  */
 function question_format_grade($cmoptions, $grade) {
-    return format_float($grade, $cmoptions->decimalpoints);
+    if (isset($cmoptions->questiondecimalpoints) && $cmoptions->questiondecimalpoints != -1) {
+        $decimalplaces = $cmoptions->questiondecimalpoints;
+    } else if (isset($cmoptions->decimalpoints)) {
+        $decimalplaces = $cmoptions->decimalpoints;
+    } else {
+        $decimalplaces = 2;
+        debugging('Code that leads to question_format_grade being called should set ' .
+                '$cmoptions->questiondecimalpoints or $cmoptions->decimalpoints', DEBUG_DEVELOPER);
+    }
+    return format_float($grade, $decimalplaces);
 }
 
 /**
index 0d215d36c0a28708255da1b2cfbf5cc0c9c6f9aa..0d41aa593db3353ebf2217a6e13165a9eed50f17 100644 (file)
@@ -12,10 +12,11 @@ class quiz_access_manager {
 
     /**
      * Create an instance for a particular quiz.
-     * @param object $quiz the quiz we will be controlling access to.
-     * @param integer $timenow the
-     * @param boolean $canpreview whether the current user has the
-     * @param boolean $ignoretimelimits
+     * @param object $quizobj An instance of the class quiz from attemptlib.php.
+     *      The quiz we will be controlling access to.
+     * @param integer $timenow The time to use as 'now'.
+     * @param boolean $canignoretimelimits Whether this user is exempt from time
+     *      limits (has_capability('mod/quiz:ignoretimelimits', ...)).
      */
     public function __construct($quizobj, $timenow, $canignoretimelimits) {
         $this->_quizobj = $quizobj;
@@ -668,10 +669,10 @@ class password_access_rule extends quiz_access_rule_base {
  */
 class time_limit_access_rule extends quiz_access_rule_base {
     public function description() {
-        return get_string('quiztimelimit', 'quiz', format_time($this->_quiz->timelimit * 60));
+        return get_string('quiztimelimit', 'quiz', format_time($this->_quiz->timelimit));
     }
     public function time_left($attempt, $timenow) {
-        return $attempt->timestart + $this->_quiz->timelimit*60 - $timenow;
+        return $attempt->timestart + $this->_quiz->timelimit - $timenow;
     }
 }
 
index e812a0029a357eb238dea594cd216d1d8b58430f..4348c4175209ba931baa7a5859d0b0396fa8cfc4 100644 (file)
@@ -604,7 +604,7 @@ class quiz_attempt extends quiz {
     public function get_question_score($questionid) {
         $options = $this->get_render_options($this->states[$questionid]);
         if ($options->scores) {
-            return quiz_format_grade($this->quiz, $this->states[$questionid]->last_graded->grade);
+            return quiz_format_question_grade($this->quiz, $this->states[$questionid]->last_graded->grade);
         } else {
             return '';
         }
index 230777c38c5eaaedd307cf57259718cb9f267be0..232face751cc0b6c8ef560205a32d33413d0db45 100644 (file)
         fwrite ($bf,full_tag("GRADE",4,false,$quiz->grade));
         fwrite ($bf,full_tag("TIMECREATED",4,false,$quiz->timecreated));
         fwrite ($bf,full_tag("TIMEMODIFIED",4,false,$quiz->timemodified));
-        fwrite ($bf,full_tag("TIMELIMIT",4,false,$quiz->timelimit));
+        fwrite ($bf,full_tag("TIMELIMIT",4,false,round($quiz->timelimit/60)));
+        fwrite ($bf,full_tag("TIMELIMITSECS",4,false,$quiz->timelimit));
         fwrite ($bf,full_tag("PASSWORD",4,false,$quiz->password));
         fwrite ($bf,full_tag("SUBNET",4,false,$quiz->subnet));
         fwrite ($bf,full_tag("POPUP",4,false,$quiz->popup));
index 33dddfee697ccfbbae3ae6bdc4bf25b5df68018f..1f73ef8658f2912906fd9e4692c48a0d8918bb4a 100755 (executable)
@@ -17,8 +17,9 @@
         <FIELD NAME="attempts" TYPE="int" LENGTH="6" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="The maximum number of attempts that a student is allowed at this quiz. 0 mean no limit." PREVIOUS="penaltyscheme" NEXT="attemptonlast"/>
         <FIELD NAME="attemptonlast" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Whether each attempt builds on last mode is on." PREVIOUS="attempts" NEXT="grademethod"/>
         <FIELD NAME="grademethod" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="1" SEQUENCE="false" ENUM="false" COMMENT="How individual attempt grades are combined to get the overall grade. From the top of mod/quiz/lib.php: 1 = QUIZ_GRADEHIGHEST, 2 = QUIZ_GRADEAVERAGE, 3 = QUIZ_ATTEMPTFIRST, 4 = QUIZ_ATTEMPTLAST." PREVIOUS="attemptonlast" NEXT="decimalpoints"/>
-        <FIELD NAME="decimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="2" SEQUENCE="false" ENUM="false" COMMENT="Number of decimal points to display when printing scores belonging to this quiz." PREVIOUS="grademethod" NEXT="review"/>
-        <FIELD NAME="review" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="A bitfield encoding the Review options setting. Read the code of function quiz_get_reviewoptions from mod/quiz/locallib.php to see what each bit means." PREVIOUS="decimalpoints" NEXT="questionsperpage"/>
+        <FIELD NAME="decimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="2" SEQUENCE="false" ENUM="false" COMMENT="Number of decimal points to display when printing scores belonging to this quiz." PREVIOUS="grademethod" NEXT="questiondecimalpoints"/>
+        <FIELD NAME="questiondecimalpoints" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="-2" SEQUENCE="false" ENUM="false" COMMENT="The number of decimal digits to use when displaying question grades. -1 = use decimalpoints, otherwise a separate setting." PREVIOUS="decimalpoints" NEXT="review"/>
+        <FIELD NAME="review" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="A bitfield encoding the Review options setting. Read the code of function quiz_get_reviewoptions from mod/quiz/locallib.php to see what each bit means." PREVIOUS="questiondecimalpoints" NEXT="questionsperpage"/>
         <FIELD NAME="questionsperpage" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="This does not do exactly what the name suggests, and the behaviour depends on the shufflequestions setting." PREVIOUS="review" NEXT="shufflequestions"/>
         <FIELD NAME="shufflequestions" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Whether the list of questions in the quiz should be randomly shuffled at the start of each attempt." PREVIOUS="questionsperpage" NEXT="shuffleanswers"/>
         <FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Whether, in question types that support it, individual parts of a question should be shuffled." PREVIOUS="shufflequestions" NEXT="questions"/>
@@ -27,7 +28,7 @@
         <FIELD NAME="grade" TYPE="number" LENGTH="10" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" DECIMALS="5" COMMENT="Maximum grade that you can get from this quiz." PREVIOUS="sumgrades" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Timestamp when this quiz was created." PREVIOUS="grade" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Timestamp when this row was last updated." PREVIOUS="timecreated" NEXT="timelimit"/>
-        <FIELD NAME="timelimit" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Time limit in minutes. (This should really be changed to seconds for consistency.)" PREVIOUS="timemodified" NEXT="password"/>
+        <FIELD NAME="timelimit" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Time limit in seconds." PREVIOUS="timemodified" NEXT="password"/>
         <FIELD NAME="password" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="Students must enter this password before they can attempt the quiz." PREVIOUS="timelimit" NEXT="subnet"/>
         <FIELD NAME="subnet" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" ENUM="false" COMMENT="If set, only allow attempts from certain IP addresses. The checking is performed by the address_in_subnet function from lib/moodlelib.php." PREVIOUS="password" NEXT="popup"/>
         <FIELD NAME="popup" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="false" DEFAULT="0" SEQUENCE="false" ENUM="false" COMMENT="Force the quiz to be attempted in a full-screen pop-up window with some evil JavaScript that attempts to prevent copying and pasting, etc." PREVIOUS="subnet" NEXT="delay1"/>
index 6c813ccc9a0a83e09d6fcfeeba6b950cfb4b8906..a81a5ecc03441519b51e85a485dd33ac8411b869 100644 (file)
@@ -22,7 +22,7 @@
 
 function xmldb_quiz_upgrade($oldversion) {
     global $CFG, $DB;
-    
+
     $dbman = $DB->get_manager();
     $result = true;
 
@@ -77,7 +77,7 @@ function xmldb_quiz_upgrade($oldversion) {
 
         upgrade_mod_savepoint($result, 2008062001, 'quiz');
     }
-    
+
     if ($result && $oldversion < 2008072402) {
 
     /// Define field lastcron to be added to quiz_report
@@ -196,7 +196,7 @@ function xmldb_quiz_upgrade($oldversion) {
         // question type, this is now a no-op.
         upgrade_mod_savepoint($result, 2008082600, 'quiz');
     }
-    
+
     if ($result && $oldversion < 2008112101) {
 
     /// Define field lastcron to be added to quiz_report
@@ -207,7 +207,7 @@ function xmldb_quiz_upgrade($oldversion) {
         if (!$dbman->field_exists($table, $field)) {
             $dbman->add_field($table, $field);
         }
-        
+
     /// quiz savepoint reached
         upgrade_mod_savepoint($result, 2008112101, 'quiz');
     }
@@ -227,7 +227,55 @@ function xmldb_quiz_upgrade($oldversion) {
         upgrade_mod_savepoint($result, 2009010700, 'quiz');
     }
 
+    if ($result && $oldversion < 2009030900) {
+    /// If there are no quiz settings set to advanced yet, the set up the default
+    /// advanced fields from Moodle 2.0.
+        $quizconfig = get_config('quiz');
+        $arealreadyadvanced = false;
+        foreach (array($quizconfig) as $name => $value) {
+            if (strpos($name, 'fix_') === 0 && !empty($value)) {
+                $arealreadyadvanced = true;
+                break;
+            }
+        }
+
+        if (!$arealreadyadvanced) {
+            set_config('fix_penaltyscheme', 1, 'quiz');
+            set_config('fix_attemptonlast', 1, 'quiz');
+            set_config('fix_questiondecimalpoints', 1, 'quiz');
+            set_config('fix_password', 1, 'quiz');
+            set_config('fix_subnet', 1, 'quiz');
+            set_config('fix_delay1', 1, 'quiz');
+            set_config('fix_delay2', 1, 'quiz');
+            set_config('fix_popup', 1, 'quiz');
+        }
+
+    /// quiz savepoint reached
+        upgrade_mod_savepoint($result, 2009030900, 'quiz');
+    }
+
+    if ($result && $oldversion < 2009031000) {
+    /// Add new questiondecimaldigits setting, separate form the overall decimaldigits one.
+        $table = new xmldb_table('quiz');
+        $field = new xmldb_field('questiondecimalpoints', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, null, null, '2', 'decimalpoints');
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+
+    /// quiz savepoint reached
+        upgrade_mod_savepoint($result, 2009031000, 'quiz');
+    }
+
+    if ($result && $oldversion < 2009031001) {
+    /// Convert quiz.timelimit from minutes to seconds.
+        $DB->execute('UPDATE {quiz} SET timelimit = timelimit * 60');
+        $default = get_config('quiz', 'timelimit');
+        set_config('timelimit', 60 * $default, 'quiz');
+
+    /// quiz savepoint reached
+        upgrade_mod_savepoint($result, 2009031001, 'quiz');
+    }
+
     return $result;
 }
 
-?>
index 5cc08c6d56747565824ce5d9bdb9af33842c8caa..f244b7d7ee661e23db0be34d3da9dac0ef6206a8 100644 (file)
@@ -1,16 +1,40 @@
 <?php  // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
 /**
-* Library of functions for the quiz module.
-*
-* This contains functions that are called also from outside the quiz module
-* Functions that are only called by the quiz module itself are in {@link locallib.php}
-* @author Martin Dougiamas and many others.
-* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
-* @package quiz
-*/
+ * Library of functions for the quiz module.
+ *
+ * This contains functions that are called also from outside the quiz module
+ * Functions that are only called by the quiz module itself are in {@link locallib.php}
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package quiz
+ */
 
-require_once($CFG->libdir.'/pagelib.php');
-require_once($CFG->libdir.'/eventslib.php');
+require_once($CFG->libdir . '/pagelib.php');
+require_once($CFG->libdir . '/eventslib.php');
 
 /// CONSTANTS ///////////////////////////////////////////////////////////////////
 
@@ -18,12 +42,17 @@ require_once($CFG->libdir.'/eventslib.php');
  * Options determining how the grades from individual attempts are combined to give
  * the overall grade for a user
  */
-define("QUIZ_GRADEHIGHEST", "1");
-define("QUIZ_GRADEAVERAGE", "2");
-define("QUIZ_ATTEMPTFIRST", "3");
-define("QUIZ_ATTEMPTLAST",  "4");
+define('QUIZ_GRADEHIGHEST', 1);
+define('QUIZ_GRADEAVERAGE', 2);
+define('QUIZ_ATTEMPTFIRST', 3);
+define('QUIZ_ATTEMPTLAST', 4);
 /**#@-*/
 
+define('QUIZ_MAX_ATTEMPT_OPTION', 10);
+define('QUIZ_MAX_QPP_OPTION', 50);
+define('QUIZ_MAX_DECIMAL_OPTION', 5);
+define('QUIZ_MAX_Q_DECIMAL_OPTION', 7);
+
 /**#@+
  * The different review options are stored in the bits of $quiz->review
  * These constants help to extract the options
@@ -241,7 +270,7 @@ function quiz_user_complete($course, $user, $mod, $quiz) {
             if ($attempt->timefinish == 0) {
                 print_string('unfinished');
             } else {
-                echo quiz_format_grade($quiz, $attempt->sumgrades).'/'.$quiz->sumgrades;
+                echo quiz_format_grade($quiz, $attempt->sumgrades) . '/' . quiz_format_grade($quiz, $quiz->sumgrades);
             }
             echo ' - '.userdate($attempt->timemodified).'<br />';
         }
@@ -330,6 +359,20 @@ function quiz_format_grade($quiz, $grade) {
     return format_float($grade, $quiz->decimalpoints);
 }
 
+/**
+ * Round a grade to to the correct number of decimal places, and format it for display.
+ *
+ * @param object $quiz The quiz table row, only $quiz->decimalpoints is used.
+ * @param float $grade The grade to round.
+ */
+function quiz_format_question_grade($quiz, $grade) {
+    if ($quiz->questiondecimalpoints == -1) {
+        return format_float($grade, $quiz->decimalpoints);
+    } else {
+        return format_float($grade, $quiz->questiondecimalpoints);
+    }
+}
+
 /**
  * Update grades in central gradebook
  *
@@ -733,22 +776,11 @@ function quiz_print_recent_mod_activity($activity, $courseid, $detail, $modnames
 function quiz_process_options(&$quiz) {
     $quiz->timemodified = time();
 
-    // Quiz open time.
-    if (empty($quiz->timeopen)) {
-        $quiz->preventlate = 0;
-    }
-
     // Quiz name.
     if (!empty($quiz->name)) {
         $quiz->name = trim($quiz->name);
     }
 
-    // Time limit. (Get rid of it if the checkbox was not ticked.)
-    if (empty($quiz->timelimitenable)) {
-        $quiz->timelimit = 0;
-    }
-    $quiz->timelimit = round($quiz->timelimit);
-
     // Password field - different in form to stop browsers that remember passwords
     // getting confused.
     $quiz->password = $quiz->quizpassword;
@@ -1233,4 +1265,3 @@ function quiz_get_extra_capabilities() {
     return $caps;
 }
 
-?>
index c618ea2b951b14239f52c1195ae569606af071cc..8608b42b947e8a05da0f06411df853c28f599184 100644 (file)
@@ -1,4 +1,28 @@
 <?php  // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
 /**
  * Library of functions used by the quiz module.
  *
@@ -8,10 +32,6 @@
  * the module-indpendent code for handling questions and which in turn
  * initialises all the questiontype classes.
  *
- * @author Martin Dougiamas and many others. This has recently been completely
- *         rewritten by Alex Smith, Julian Sedding and Gustav Delius as part of
- *         the Serving Mathematics project
- *         {@link http://maths.york.ac.uk/serving_maths}
  * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  * @package quiz
  */
@@ -25,8 +45,8 @@ if (!defined('MOODLE_INTERNAL')) {
  */
 require_once($CFG->dirroot . '/mod/quiz/lib.php');
 require_once($CFG->dirroot . '/mod/quiz/accessrules.php');
-require_once($CFG->dirroot . '/question/editlib.php');
 require_once($CFG->dirroot . '/mod/quiz/attemptlib.php');
+require_once($CFG->dirroot . '/question/editlib.php');
 require_once($CFG->libdir  . '/eventslib.php');
 
 /// Constants ///////////////////////////////////////////////////////////////////
@@ -222,6 +242,15 @@ function quiz_delete_previews($quiz, $userid = null) {
     }
 }
 
+/**
+ * @param integer $quizid The quiz id.
+ * @return boolean whether this quiz has any (non-preview) attempts.
+ */
+function quiz_has_attempts($quizid) {
+    global $DB;
+    return $DB->record_exists('quiz_attempts', array('quiz' => $quizid, 'preview' => 0));
+}
+
 /// Functions to do with quiz layout and pages ////////////////////////////////
 
 /**
@@ -440,13 +469,16 @@ function quiz_update_sumgrades($quiz) {
  * grade for this quiz.
  *
  * @param float $rawgrade the unadjusted grade, fof example $attempt->sumgrades
- * @param object $quiz the quiz object. Only the fields grade, sumgrades and decimalpoints are used.
+ * @param object $quiz the quiz object. Only the fields grade, sumgrades, decimalpoints and questiondecimalpoints are used.
+ * @param mixed $round false = don't round, true = round using quiz_format_grade, 'question' = round using quiz_format_question_grade.
  * @return float the rescaled grade.
  */
 function quiz_rescale_grade($rawgrade, $quiz, $round = true) {
     if ($quiz->sumgrades != 0) {
         $grade = $rawgrade * $quiz->grade / $quiz->sumgrades;
-        if ($round) {
+        if ($round === 'question') { // === really necessary here true == 'question' is true in PHP!
+            $grade = quiz_format_question_grade($quiz, $grade);
+        } else if ($round) {
             $grade = quiz_format_grade($quiz, $grade);
         }
     } else {
@@ -582,7 +614,7 @@ function quiz_save_best_grade($quiz, $userid = null, $attempts = array()) {
 
     // Calculate the best grade
     $bestgrade = quiz_calculate_best_grade($quiz, $attempts);
-    $bestgrade = quiz_rescale_grade($bestgrade, $quiz);
+    $bestgrade = quiz_rescale_grade($bestgrade, $quiz, false);
 
     // Save the best grade in the database
     if ($grade = $DB->get_record('quiz_grades', array('quiz' => $quiz->id, 'userid' => $userid))) {
@@ -1249,4 +1281,3 @@ function quiz_error($quiz, $errorcode, $a = null) {
     }
     print_error($errorcode, 'quiz', $CFG->wwwroot . '/mod/quiz/view.php?q=' . $quiz, $a);
 }
-?>
index 05dce8451febe8ec82ec4408b23eabd49532bece..14595652973ef09dc734811e203a6f0df66fc79a 100644 (file)
@@ -1,8 +1,37 @@
 <?php // $Id$
-require_once ($CFG->dirroot.'/course/moodleform_mod.php');
-
-require_once("$CFG->dirroot/mod/quiz/locallib.php");
 
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// This program is free software; you can redistribute it and/or modify  //
+// it under the terms of the GNU General Public License as published by  //
+// the Free Software Foundation; either version 2 of the License, or     //
+// (at your option) any later version.                                   //
+//                                                                       //
+// This program is distributed in the hope that it will be useful,       //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
+// GNU General Public License for more details:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once($CFG->dirroot . '/course/moodleform_mod.php');
+require_once($CFG->dirroot . '/mod/quiz/locallib.php');
+
+/**
+ * Settings form for the quiz module.
+ * 
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package quiz
+ */
 class mod_quiz_mod_form extends moodleform_mod {
     var $_feedbacks;
 
@@ -15,6 +44,7 @@ class mod_quiz_mod_form extends moodleform_mod {
 //-------------------------------------------------------------------------------
         $mform->addElement('header', 'general', get_string('general', 'form'));
 
+    /// Name.
         $mform->addElement('text', 'name', get_string('name'), array('size'=>'64'));
         if (!empty($CFG->formatstringstriptags)) {
             $mform->setType('name', PARAM_TEXT);
@@ -23,64 +53,57 @@ class mod_quiz_mod_form extends moodleform_mod {
         }
         $mform->addRule('name', null, 'required', null, 'client');
 
-        $mform->addElement('htmleditor', 'intro', get_string("introduction", "quiz"));
+    /// Introduction.
+        $mform->addElement('htmleditor', 'intro', get_string('introduction', 'quiz'));
         $mform->setType('intro', PARAM_RAW);
         $mform->setHelpButton('intro', array('richtext2', get_string('helprichtext')));
 
-//-------------------------------------------------------------------------------
-        $mform->addElement('header', 'timinghdr', get_string('timing', 'form'));
-        $mform->addElement('date_time_selector', 'timeopen', get_string('quizopen', 'quiz'), array('optional'=>true));
+    /// Open and close dates.
+        $mform->addElement('date_time_selector', 'timeopen', get_string('quizopen', 'quiz'), array('optional' => true));
         $mform->setHelpButton('timeopen', array('timeopen', get_string('quizopen', 'quiz'), 'quiz'));
 
-        $mform->addElement('date_time_selector', 'timeclose', get_string('quizclose', 'quiz'), array('optional'=>true));
+        $mform->addElement('date_time_selector', 'timeclose', get_string('quizclose', 'quiz'), array('optional' => true));
         $mform->setHelpButton('timeclose', array('timeopen', get_string('quizclose', 'quiz'), 'quiz'));
 
-
-        $timelimitgrp=array();
-        $timelimitgrp[] = &$mform->createElement('text', 'timelimit');
-        $timelimitgrp[] = &$mform->createElement('checkbox', 'timelimitenable', '', get_string('enable'));
-        $mform->addGroup($timelimitgrp, 'timelimitgrp', get_string('timelimitmin', 'quiz'), array(' '), false);
-        $mform->setType('timelimit', PARAM_TEXT);
-        $timelimitgrprules = array();
-        $timelimitgrprules['timelimit'][] = array(null, 'numeric', null, 'client');
-        $mform->addGroupRule('timelimitgrp', $timelimitgrprules);
-        $mform->disabledIf('timelimitgrp', 'timelimitenable');
-        $mform->setAdvanced('timelimitgrp', $quizconfig->fix_timelimit);
-        $mform->setHelpButton('timelimitgrp', array("timelimit", get_string("quiztimer","quiz"), "quiz"));
+    /// Time limit.
+        $mform->addElement('duration', 'timelimit', get_string('timelimit', 'quiz'), array('optional' => true));
+        $mform->setHelpButton('timelimit', array('timelimit', get_string('quiztimer','quiz'), 'quiz'));
+        $mform->setAdvanced('timelimit', $quizconfig->fix_timelimit);
         $mform->setDefault('timelimit', $quizconfig->timelimit);
-        $mform->setDefault('timelimitenable', !empty($quizconfig->timelimit));
 
-
-        //enforced time delay between quiz attempts add-on
-        $timedelayoptions = array();
-        $timedelayoptions[0] = get_string('none');
-        $timedelayoptions[1800] = get_string('numminutes', '', 30);
-        $timedelayoptions[3600] = get_string('numminutes', '', 60);
-        for($i=2; $i<=23; $i++) {
-             $seconds  = $i*3600;
-             $timedelayoptions[$seconds] = get_string('numhours', '', $i);
-        }
-        $timedelayoptions[86400] = get_string('numhours', '', 24);
-        for($i=2; $i<=7; $i++) {
-             $seconds = $i*86400;
-             $timedelayoptions[$seconds] = get_string('numdays', '', $i);
+    /// Number of attempts.
+        $attemptoptions = array('0' => get_string('unlimited'));
+        for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) {
+            $attemptoptions[$i] = $i;
         }
-        $mform->addElement('select', 'delay1', get_string("delay1", "quiz"), $timedelayoptions);
-        $mform->setHelpButton('delay1', array("timedelay1", get_string("delay1", "quiz"), "quiz"));
-        $mform->setAdvanced('delay1', $quizconfig->fix_delay1);
-        $mform->setDefault('delay1', $quizconfig->delay1);
+        $mform->addElement('select', 'attempts', get_string('attemptsallowed', 'quiz'), $attemptoptions);
+        $mform->setHelpButton('attempts', array('attempts', get_string('attemptsallowed','quiz'), 'quiz'));
+        $mform->setAdvanced('attempts', $quizconfig->fix_attempts);
+        $mform->setDefault('attempts', $quizconfig->attempts);
 
-        $mform->addElement('select', 'delay2', get_string("delay2", "quiz"), $timedelayoptions);
-        $mform->setHelpButton('delay2', array("timedelay2", get_string("delay2", "quiz"), "quiz"));
-        $mform->setAdvanced('delay2', $quizconfig->fix_delay2);
-        $mform->setDefault('delay2', $quizconfig->delay2);
+    /// Grading method.
+        $mform->addElement('select', 'grademethod', get_string('grademethod', 'quiz'), quiz_get_grading_options());
+        $mform->setHelpButton('grademethod', array('grademethod', get_string('grademethod','quiz'), 'quiz'));
+        $mform->setAdvanced('grademethod', $quizconfig->fix_grademethod);
+        $mform->setDefault('grademethod', $quizconfig->grademethod);
+        $mform->disabledIf('grademethod', 'attempts', 'eq', 1);
+
+        $mform->addElement('hidden', 'grade', $quizconfig->maximumgrade);
 
 //-------------------------------------------------------------------------------
-        $mform->addElement('header', 'displayhdr', get_string('display', 'form'));
+        $mform->addElement('header', 'layouthdr', get_string('layout', 'quiz'));
+
+    /// Shuffle questions.
+        $mform->addElement('selectyesno', 'shufflequestions', get_string('shufflequestions', 'quiz'));
+        $mform->setHelpButton('shufflequestions', array('shufflequestions', get_string('shufflequestions','quiz'), 'quiz'));
+        $mform->setAdvanced('shufflequestions', $quizconfig->fix_shufflequestions);
+        $mform->setDefault('shufflequestions', $quizconfig->shufflequestions);
+
+    /// Questions per page.
         $perpage = array();
         $perpage[0] = get_string('never');
         $perpage[1] = get_string('aftereachquestion', 'quiz');
-        for ($i = 2; $i <= 50; ++$i) {
+        for ($i = 2; $i <= QUIZ_MAX_QPP_OPTION; ++$i) {
             $perpage[$i] = get_string('afternquestions', 'quiz', $i);
         }
         $mform->addElement('select', 'questionsperpage', get_string('newpageevery', 'quiz'), $perpage);
@@ -88,72 +111,41 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->setAdvanced('questionsperpage', $quizconfig->fix_questionsperpage);
         $mform->setDefault('questionsperpage', $quizconfig->questionsperpage);
 
-        $mform->addElement('selectyesno', 'shufflequestions', get_string("shufflequestions", "quiz"));
-        $mform->setHelpButton('shufflequestions', array("shufflequestions", get_string("shufflequestions","quiz"), "quiz"));
-        $mform->setAdvanced('shufflequestions', $quizconfig->fix_shufflequestions);
-        $mform->setDefault('shufflequestions', $quizconfig->shufflequestions);
+//-------------------------------------------------------------------------------
+        $mform->addElement('header', 'interactionhdr', get_string('questionbehaviour', 'quiz'));
 
-        $mform->addElement('selectyesno', 'shuffleanswers', get_string("shufflewithin", "quiz"));
-        $mform->setHelpButton('shuffleanswers', array("shufflewithin", get_string("shufflewithin","quiz"), "quiz"));
+    /// Shuffle within questions.
+        $mform->addElement('selectyesno', 'shuffleanswers', get_string('shufflewithin', 'quiz'));
+        $mform->setHelpButton('shuffleanswers', array('shufflewithin', get_string('shufflewithin','quiz'), 'quiz'));
         $mform->setAdvanced('shuffleanswers', $quizconfig->fix_shuffleanswers);
         $mform->setDefault('shuffleanswers', $quizconfig->shuffleanswers);
 
-        $mform->addElement('selectyesno', 'showuserpicture', get_string('showuserpicture', 'quiz'));
-        $mform->setHelpButton('showuserpicture', array('showuserpicture', get_string('showuserpicture', 'quiz'), 'quiz'));
-        $mform->setAdvanced('showuserpicture', $quizconfig->fix_showuserpicture);
-        $mform->setDefault('showuserpicture', $quizconfig->showuserpicture);
-
-//-------------------------------------------------------------------------------
-        $mform->addElement('header', 'attemptshdr', get_string('attempts', 'quiz'));
-        $attemptoptions = array('0' => get_string('unlimited'));
-        for ($i = 1; $i <= 10; $i++) {
-            $attemptoptions[$i] = $i;
-        }
-        $mform->addElement('select', 'attempts', get_string("attemptsallowed", "quiz"), $attemptoptions);
-        $mform->setHelpButton('attempts', array("attempts", get_string("attemptsallowed","quiz"), "quiz"));
-        $mform->setAdvanced('attempts', $quizconfig->fix_attempts);
-        $mform->setDefault('attempts', $quizconfig->attempts);
-
-        $mform->addElement('selectyesno', 'attemptonlast', get_string("eachattemptbuildsonthelast", "quiz"));
-        $mform->setHelpButton('attemptonlast', array("repeatattempts", get_string("eachattemptbuildsonthelast", "quiz"), "quiz"));
-        $mform->setAdvanced('attemptonlast', $quizconfig->fix_attemptonlast);
-        $mform->setDefault('attemptonlast', $quizconfig->attemptonlast);
-
-        $mform->addElement('selectyesno', 'adaptive', get_string("adaptive", "quiz"));
-        $mform->setHelpButton('adaptive', array("adaptive", get_string("adaptive","quiz"), "quiz"));
+    /// Adaptive mode.
+        $mform->addElement('selectyesno', 'adaptive', get_string('adaptive', 'quiz'));
+        $mform->setHelpButton('adaptive', array('adaptive', get_string('adaptive','quiz'), 'quiz'));
         $mform->setAdvanced('adaptive', $quizconfig->fix_optionflags);
         $mform->setDefault('adaptive', $quizconfig->optionflags & QUESTION_ADAPTIVE);
 
-
-//-------------------------------------------------------------------------------
-        $mform->addElement('header', 'gradeshdr', get_string('grades', 'grades'));
-        $mform->addElement('select', 'grademethod', get_string("grademethod", "quiz"), quiz_get_grading_options());
-        $mform->setHelpButton('grademethod', array("grademethod", get_string("grademethod","quiz"), "quiz"));
-        $mform->setAdvanced('grademethod', $quizconfig->fix_grademethod);
-        $mform->setDefault('grademethod', $quizconfig->grademethod);
-
-        $mform->addElement('selectyesno', 'penaltyscheme', get_string("penaltyscheme", "quiz"));
-        $mform->setHelpButton('penaltyscheme', array("penaltyscheme", get_string("penaltyscheme","quiz"), "quiz"));
+    /// Apply penalties.
+        $mform->addElement('selectyesno', 'penaltyscheme', get_string('penaltyscheme', 'quiz'));
+        $mform->setHelpButton('penaltyscheme', array('penaltyscheme', get_string('penaltyscheme','quiz'), 'quiz'));
         $mform->setAdvanced('penaltyscheme', $quizconfig->fix_penaltyscheme);
         $mform->setDefault('penaltyscheme', $quizconfig->penaltyscheme);
+        $mform->disabledIf('penaltyscheme', 'adaptive', 'neq', 1);
 
-        $options = array(
-                    0 => '0',
-                    1 => '1',
-                    2 => '2',
-                    3 => '3');
-        $mform->addElement('select', 'decimalpoints', get_string("decimaldigits", "quiz"), $options);
-        $mform->setHelpButton('decimalpoints', array("decimalpoints", get_string("decimaldigits","quiz"), "quiz"));
-        $mform->setAdvanced('decimalpoints', $quizconfig->fix_decimalpoints);
-        $mform->setDefault('decimalpoints', $quizconfig->decimalpoints);
-
-        $mform->addElement('hidden', 'grade', $quizconfig->maximumgrade);
+    /// Each attempt builds on last.
+        $mform->addElement('selectyesno', 'attemptonlast', get_string('eachattemptbuildsonthelast', 'quiz'));
+        $mform->setHelpButton('attemptonlast', array('repeatattempts', get_string('eachattemptbuildsonthelast', 'quiz'), 'quiz'));
+        $mform->setAdvanced('attemptonlast', $quizconfig->fix_attemptonlast);
+        $mform->setDefault('attemptonlast', $quizconfig->attemptonlast);
+        $mform->disabledIf('attemptonlast', 'attempts', 'eq', 1);
 
 //-------------------------------------------------------------------------------
         $mform->addElement('header', 'reviewoptionshdr', get_string('reviewoptionsheading', 'quiz'));
         $mform->setHelpButton('reviewoptionshdr', array('reviewoptions', get_string('reviewoptionsheading','quiz'), 'quiz'));
         $mform->setAdvanced('reviewoptionshdr', $quizconfig->fix_review);
 
+    /// Review options.
         $immediatelyoptionsgrp=array();
         $immediatelyoptionsgrp[] = &$mform->createElement('checkbox', 'responsesimmediately', '', get_string('responses', 'quiz'));
         $immediatelyoptionsgrp[] = &$mform->createElement('checkbox', 'answersimmediately', '', get_string('answers', 'quiz'));
@@ -161,7 +153,7 @@ class mod_quiz_mod_form extends moodleform_mod {
         $immediatelyoptionsgrp[] = &$mform->createElement('checkbox', 'generalfeedbackimmediately', '', get_string('generalfeedback', 'quiz'));
         $immediatelyoptionsgrp[] = &$mform->createElement('checkbox', 'scoreimmediately', '', get_string('scores', 'quiz'));
         $immediatelyoptionsgrp[] = &$mform->createElement('checkbox', 'overallfeedbackimmediately', '', get_string('overallfeedback', 'quiz'));
-        $mform->addGroup($immediatelyoptionsgrp, 'immediatelyoptionsgrp', get_string("reviewimmediately", "quiz"), null, false);
+        $mform->addGroup($immediatelyoptionsgrp, 'immediatelyoptionsgrp', get_string('reviewimmediately', 'quiz'), null, false);
         $mform->setDefault('responsesimmediately', $quizconfig->review & QUIZ_REVIEW_RESPONSES & QUIZ_REVIEW_IMMEDIATELY);
         $mform->setDefault('answersimmediately', $quizconfig->review & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_IMMEDIATELY);
         $mform->setDefault('feedbackimmediately', $quizconfig->review & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_IMMEDIATELY);
@@ -176,7 +168,7 @@ class mod_quiz_mod_form extends moodleform_mod {
         $openoptionsgrp[] = &$mform->createElement('checkbox', 'generalfeedbackopen', '', get_string('generalfeedback', 'quiz'));
         $openoptionsgrp[] = &$mform->createElement('checkbox', 'scoreopen', '', get_string('scores', 'quiz'));
         $openoptionsgrp[] = &$mform->createElement('checkbox', 'overallfeedbackopen', '', get_string('overallfeedback', 'quiz'));
-        $mform->addGroup($openoptionsgrp, 'openoptionsgrp', get_string("reviewopen", "quiz"), array(' '), false);
+        $mform->addGroup($openoptionsgrp, 'openoptionsgrp', get_string('reviewopen', 'quiz'), array(' '), false);
         $mform->setDefault('responsesopen', $quizconfig->review & QUIZ_REVIEW_RESPONSES & QUIZ_REVIEW_OPEN);
         $mform->setDefault('answersopen', $quizconfig->review & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_OPEN);
         $mform->setDefault('feedbackopen', $quizconfig->review & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_OPEN);
@@ -184,7 +176,6 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->setDefault('scoreopen', $quizconfig->review & QUIZ_REVIEW_SCORES & QUIZ_REVIEW_OPEN);
         $mform->setDefault('overallfeedbackopen', $quizconfig->review & QUIZ_REVIEW_OVERALLFEEDBACK & QUIZ_REVIEW_OPEN);
 
-
         $closedoptionsgrp=array();
         $closedoptionsgrp[] = &$mform->createElement('checkbox', 'responsesclosed', '', get_string('responses', 'quiz'));
         $closedoptionsgrp[] = &$mform->createElement('checkbox', 'answersclosed', '', get_string('answers', 'quiz'));
@@ -192,40 +183,81 @@ class mod_quiz_mod_form extends moodleform_mod {
         $closedoptionsgrp[] = &$mform->createElement('checkbox', 'generalfeedbackclosed', '', get_string('generalfeedback', 'quiz'));
         $closedoptionsgrp[] = &$mform->createElement('checkbox', 'scoreclosed', '', get_string('scores', 'quiz'));
         $closedoptionsgrp[] = &$mform->createElement('checkbox', 'overallfeedbackclosed', '', get_string('overallfeedback', 'quiz'));
-        $mform->addGroup($closedoptionsgrp, 'closedoptionsgrp', get_string("reviewclosed", "quiz"), array(' '), false);
+        $mform->addGroup($closedoptionsgrp, 'closedoptionsgrp', get_string('reviewclosed', 'quiz'), array(' '), false);
         $mform->setDefault('responsesclosed', $quizconfig->review & QUIZ_REVIEW_RESPONSES & QUIZ_REVIEW_CLOSED);
         $mform->setDefault('answersclosed', $quizconfig->review & QUIZ_REVIEW_ANSWERS & QUIZ_REVIEW_CLOSED);
         $mform->setDefault('feedbackclosed', $quizconfig->review & QUIZ_REVIEW_FEEDBACK & QUIZ_REVIEW_CLOSED);
         $mform->setDefault('generalfeedbackclosed', $quizconfig->review & QUIZ_REVIEW_GENERALFEEDBACK & QUIZ_REVIEW_CLOSED);
         $mform->setDefault('scoreclosed', $quizconfig->review & QUIZ_REVIEW_SCORES & QUIZ_REVIEW_CLOSED);
         $mform->setDefault('overallfeedbackclosed', $quizconfig->review & QUIZ_REVIEW_OVERALLFEEDBACK & QUIZ_REVIEW_CLOSED);
+        $mform->disabledIf('closedoptionsgrp', 'timeclose[enabled]');
 
 //-------------------------------------------------------------------------------
-        $mform->addElement('header', 'security', get_string('security', 'form'));
+        $mform->addElement('header', 'display', get_string('display', 'form'));
 
-        $mform->addElement('selectyesno', 'popup', get_string("popup", "quiz"));
-        $mform->setHelpButton('popup', array("popup", get_string("popup", "quiz"), "quiz"));
-        $mform->setAdvanced('popup', $quizconfig->fix_popup);
-        $mform->setDefault('popup', $quizconfig->popup);
+    /// Show user picture.
+        $mform->addElement('selectyesno', 'showuserpicture', get_string('showuserpicture', 'quiz'));
+        $mform->setHelpButton('showuserpicture', array('showuserpicture', get_string('showuserpicture', 'quiz'), 'quiz'));
+        $mform->setAdvanced('showuserpicture', $quizconfig->fix_showuserpicture);
+        $mform->setDefault('showuserpicture', $quizconfig->showuserpicture);
+
+    /// Overall decimal points.
+        $options = array();
+        for ($i = 0; $i <= QUIZ_MAX_DECIMAL_OPTION; $i++) {
+            $options[$i] = $i;
+        }
+        $mform->addElement('select', 'decimalpoints', get_string('decimalplaces', 'quiz'), $options);
+        $mform->setHelpButton('decimalpoints', array('decimalpoints', get_string('decimalplaces','quiz'), 'quiz'));
+        $mform->setAdvanced('decimalpoints', $quizconfig->fix_decimalpoints);
+        $mform->setDefault('decimalpoints', $quizconfig->decimalpoints);
 
-        $mform->addElement('passwordunmask', 'quizpassword', get_string("requirepassword", "quiz"));
+    /// Question decimal points.
+        $options = array(-1 => get_string('sameasoverall', 'quiz'));
+        for ($i = 0; $i <= QUIZ_MAX_Q_DECIMAL_OPTION; $i++) {
+            $options[$i] = $i;
+        }
+        $mform->addElement('select', 'questiondecimalpoints', get_string('decimalplacesquestion', 'quiz'), $options);
+        $mform->setHelpButton('questiondecimalpoints', array('decimalplacesquestion', get_string('decimalplacesquestion','quiz'), 'quiz'));
+        $mform->setAdvanced('questiondecimalpoints', $quizconfig->fix_questiondecimalpoints);
+        $mform->setDefault('questiondecimalpoints', $quizconfig->questiondecimalpoints);
+
+//-------------------------------------------------------------------------------
+        $mform->addElement('header', 'security', get_string('extraattemptrestrictions', 'quiz'));
+
+    /// Enforced time delay between quiz attempts.
+        $mform->addElement('passwordunmask', 'quizpassword', get_string('requirepassword', 'quiz'));
         $mform->setType('quizpassword', PARAM_TEXT);
-        $mform->setHelpButton('quizpassword', array("requirepassword", get_string("requirepassword", "quiz"), "quiz"));
+        $mform->setHelpButton('quizpassword', array('requirepassword', get_string('requirepassword', 'quiz'), 'quiz'));
         $mform->setAdvanced('quizpassword', $quizconfig->fix_password);
         $mform->setDefault('quizpassword', $quizconfig->password);
 
-        $mform->addElement('text', 'subnet', get_string("requiresubnet", "quiz"));
+    /// IP address.
+        $mform->addElement('text', 'subnet', get_string('requiresubnet', 'quiz'));
         $mform->setType('subnet', PARAM_TEXT);
-        $mform->setHelpButton('subnet', array("requiresubnet", get_string("requiresubnet", "quiz"), "quiz"));
+        $mform->setHelpButton('subnet', array('requiresubnet', get_string('requiresubnet', 'quiz'), 'quiz'));
         $mform->setAdvanced('subnet', $quizconfig->fix_subnet);
         $mform->setDefault('subnet', $quizconfig->subnet);
 
-//-------------------------------------------------------------------------------
-        $features = new stdClass;
-        $features->groups = true;
-        $features->groupings = true;
-        $features->groupmembersonly = true;
-        $this->standard_coursemodule_elements($features);
+    /// Enforced time delay between quiz attempts.
+        $mform->addElement('duration', 'delay1', get_string('delay1st2nd', 'quiz'), array('optional' => true));
+        $mform->setHelpButton('delay1', array('timedelay1', get_string('delay1st2nd', 'quiz'), 'quiz'));
+        $mform->setAdvanced('delay1', $quizconfig->fix_delay1);
+        $mform->setDefault('delay1', $quizconfig->delay1);
+        $mform->disabledIf('delay1', 'attempts', 'eq', 1);
+
+        $mform->addElement('duration', 'delay2', get_string('delaylater', 'quiz'), array('optional' => true));
+        $mform->setHelpButton('delay2', array('timedelay2', get_string('delaylater', 'quiz'), 'quiz'));
+        $mform->setAdvanced('delay2', $quizconfig->fix_delay2);
+        $mform->setDefault('delay2', $quizconfig->delay2);
+        $mform->disabledIf('delay2', 'attempts', 'eq', 1);
+        $mform->disabledIf('delay2', 'attempts', 'eq', 2);
+
+    /// 'Secure' window.
+        $mform->addElement('selectyesno', 'popup', get_string('showinsecurepopup', 'quiz'));
+        $mform->setHelpButton('popup', array('popup', get_string('showinsecurepopup', 'quiz'), 'quiz'));
+        $mform->setAdvanced('popup', $quizconfig->fix_popup);
+        $mform->setDefault('popup', $quizconfig->popup);
+
 //-------------------------------------------------------------------------------
         $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'quiz'));
         $mform->setHelpButton('overallfeedbackhdr', array('overallfeedback', get_string('overallfeedback', 'quiz'), 'quiz'));
@@ -246,7 +278,7 @@ class mod_quiz_mod_form extends moodleform_mod {
         $mform->setType('feedbacktext', PARAM_RAW);
         $mform->setType('feedbackboundaries', PARAM_NOTAGS);
 
-        $nextel=$this->repeat_elements($repeatarray, $numfeedbacks-1,
+        $nextel=$this->repeat_elements($repeatarray, $numfeedbacks - 1,
                 array(), 'boundary_repeats', 'boundary_add_fields', 3,
                 get_string('addmoreoverallfeedbacks', 'quiz'), true);
 
@@ -257,6 +289,13 @@ class mod_quiz_mod_form extends moodleform_mod {
         $insertEl = &MoodleQuickForm::createElement('static', 'gradeboundarystatic2', get_string('gradeboundary', 'quiz'), '0%');
         $mform->insertElementBefore($insertEl, 'boundary_add_fields');
 
+//-------------------------------------------------------------------------------
+        $features = new stdClass;
+        $features->groups = true;
+        $features->groupings = true;
+        $features->groupmembersonly = true;
+        $this->standard_coursemodule_elements($features);
+
 //-------------------------------------------------------------------------------
         // buttons
         $this->add_action_buttons();
index 54feb712eafc24541fdbb8b8f36f71ac1927c28b..0a0e6b2b371c7dbca7b2b14b79a747901bad8606 100644 (file)
@@ -162,11 +162,11 @@ function quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz
     foreach(array_keys($questions) as $questionid) {
         if (isset($avggradebyq[$questionid])){
             $grade = $avggradebyq[$questionid];
-            $grade = quiz_rescale_grade($grade, $quiz);
+            $grade = quiz_rescale_grade($grade, $quiz, 'question');
         } else {
             $grade = '--';
         }
-        $row['qsgrade'.$questionid]= $grade;
+        $row['qsgrade'.$questionid] = $grade;
     }
     return $row;
 }
index d84bedf35a295a26515afe1868816d68ae1400f8..d4fdf7736c44d12428153ac68612e79eb50d839a 100644 (file)
             $quiz->grade = backup_todb($info['MOD']['#']['GRADE']['0']['#']);
             $quiz->timecreated = backup_todb($info['MOD']['#']['TIMECREATED']['0']['#']);
             $quiz->timemodified = backup_todb($info['MOD']['#']['TIMEMODIFIED']['0']['#']);
-            $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMIT']['0']['#']);
+            if (isset($info['MOD']['#']['TIMELIMITSECS']['0']['#'])) {
+                $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMITSECS']['0']['#']);
+            } else {
+                $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMIT']['0']['#']) * 60;
+            }
             $quiz->password = backup_todb($info['MOD']['#']['PASSWORD']['0']['#']);
             $quiz->subnet = backup_todb($info['MOD']['#']['SUBNET']['0']['#']);
             $quiz->popup = backup_todb($info['MOD']['#']['POPUP']['0']['#']);
index 451fec6644bc2ccb395c2e3c32e415d8697fb99c..4fc900807efb36ece7f1406b6fb40f802e233e26 100644 (file)
             $quiz->grade = backup_todb($info['MOD']['#']['GRADE']['0']['#']);
             $quiz->timecreated = backup_todb($info['MOD']['#']['TIMECREATED']['0']['#']);
             $quiz->timemodified = backup_todb($info['MOD']['#']['TIMEMODIFIED']['0']['#']);
-            $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMIT']['0']['#']);
+            $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMIT']['0']['#']) * 60;
             $quiz->password = backup_todb($info['MOD']['#']['PASSWORD']['0']['#']);
             $quiz->subnet = backup_todb($info['MOD']['#']['SUBNET']['0']['#']);
             $quiz->popup = backup_todb($info['MOD']['#']['POPUP']['0']['#']);
index 4254bc782587bf23dfb81623177ac208087ae448..d6e61da5d37ea2dcbb75c106b0a0bec44d7dab5e 100644 (file)
 /// Work out some time-related things.
     $attempt = $attemptobj->get_attempt();
     $quiz = $attemptobj->get_quiz();
-    $timelimit = $quiz->timelimit * 60;
     $overtime = 0;
 
     if ($attempt->timefinish) {
         if ($timetaken = ($attempt->timefinish - $attempt->timestart)) {
-            if($timelimit && $timetaken > ($timelimit + 60)) {
-                $overtime = $timetaken - $timelimit;
+            if($quiz->timelimit && $timetaken > ($quiz->timelimit + 60)) {
+                $overtime = $timetaken - $quiz->timelimit;
                 $overtime = format_time($overtime);
             }
             $timetaken = format_time($timetaken);
index 231def4692d9d95fabc2f3f8cdd363b8f7e9923b..9e1d272d88d0e75b4546c67f2a07cd6d5cf4b7b6 100644 (file)
@@ -39,119 +39,115 @@ $quizsettings = new admin_settingpage('modsettingquiz', $pagetitle, 'moodle/site
 // Introductory explanation that all the settings are defaults for the add quiz form.
 $quizsettings->add(new admin_setting_heading('quizintro', '', get_string('configintro', 'quiz')));
 
-// timelimit
+// Time limit
 $quizsettings->add(new admin_setting_text_with_advanced('quiz/timelimit',
-        get_string('timelimit', 'quiz'), get_string('configtimelimit', 'quiz'),
+        get_string('timelimitsec', 'quiz'), get_string('configtimelimitsec', 'quiz'),
         array('value' => '0', 'fix' => false), PARAM_INT));
 
-// delay1 and delay2
-$timedelayoptions = array();
-$timedelayoptions[0] = get_string('none');
-$timedelayoptions[1800] = get_string('numminutes', '', 30);
-$timedelayoptions[3600] = get_string('numminutes', '', 60);
-for($i=2; $i<=23; $i++) {
-    $seconds  = $i*3600;
-    $timedelayoptions[$seconds] = get_string('numhours', '', $i);
-}
-$timedelayoptions[86400] = get_string('numhours', '', 24);
-for($i=2; $i<=7; $i++) {
-     $seconds = $i*86400;
-     $timedelayoptions[$seconds] = get_string('numdays', '', $i);
+// Number of attempts
+$options = array(get_string('unlimited'));
+for ($i = 1; $i <= QUIZ_MAX_ATTEMPT_OPTION; $i++) {
+    $options[$i] = $i;
 }
-$quizsettings->add(new admin_setting_combo_with_advanced('quiz/delay1',
-        get_string('delay1', 'quiz'), get_string('configdelay1', 'quiz'),
-        array('value' => 0, 'fix' => false), $timedelayoptions));
-$quizsettings->add(new admin_setting_combo_with_advanced('quiz/delay2',
-        get_string('delay2', 'quiz'), get_string('configdelay2', 'quiz'),
-        array('value' => 0, 'fix' => false), $timedelayoptions));
-
-// questionsperpage
+$quizsettings->add(new admin_setting_combo_with_advanced('quiz/attempts',
+        get_string('attemptsallowed', 'quiz'), get_string('configattemptsallowed', 'quiz'),
+        array('value' => 0, 'fix' => false), $options));
+
+// Grading method.
+$quizsettings->add(new admin_setting_combo_with_advanced('quiz/grademethod',
+        get_string('grademethod', 'quiz'), get_string('configgrademethod', 'quiz'),
+        array('value' => QUIZ_GRADEHIGHEST, 'fix' => false), quiz_get_grading_options()));
+
+// Maximum grade
+$quizsettings->add(new admin_setting_configtext('quiz/maximumgrade',
+        get_string('maximumgrade'), get_string('configmaximumgrade', 'quiz'), 10, PARAM_INT));
+
+// Shuffle questions
+$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/shufflequestions',
+        get_string('shufflequestions', 'quiz'), get_string('configshufflequestions', 'quiz'),
+        array('value' => 0, 'fix' => false)));
+
+// Questions per page
 $perpage = array();
 $perpage[0] = get_string('never');
 $perpage[1] = get_string('aftereachquestion', 'quiz');
-for ($i = 2; $i <= 50; ++$i) {
+for ($i = 2; $i <= QUIZ_MAX_QPP_OPTION; ++$i) {
     $perpage[$i] = get_string('afternquestions', 'quiz', $i);
 }
 $quizsettings->add(new admin_setting_combo_with_advanced('quiz/questionsperpage',
         get_string('newpageevery', 'quiz'), get_string('confignewpageevery', 'quiz'),
         array('value' => 1, 'fix' => false), $perpage));
 
-// shufflequestions
-$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/shufflequestions',
-        get_string('shufflequestions', 'quiz'), get_string('configshufflequestions', 'quiz'),
-        array('value' => 0, 'fix' => false)));
-
-// shuffleanswers
+// Shuffle within questions
 $quizsettings->add(new admin_setting_yesno_with_advanced('quiz/shuffleanswers',
         get_string('shufflewithin', 'quiz'), get_string('configshufflewithin', 'quiz'),
         array('value' => 1, 'fix' => false)));
 
-// showuserpicture
-$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/showuserpicture',
-        get_string('showuserpicture', 'quiz'), get_string('configshowuserpicture', 'quiz'),
-        array('value' => 0, 'fix' => false)));
-
-// attempts
-$options = array(get_string('unlimited'));
-for ($i = 1; $i <= 6; $i++) {
-    $options[$i] = $i;
-}
-$quizsettings->add(new admin_setting_combo_with_advanced('quiz/attempts',
-        get_string('attemptsallowed', 'quiz'), get_string('configattemptsallowed', 'quiz'),
-        array('value' => 0, 'fix' => false), $options));
-
-// attemptonlast
-$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/attemptonlast',
-        get_string('eachattemptbuildsonthelast', 'quiz'), get_string('configeachattemptbuildsonthelast', 'quiz'),
-        array('value' => 0, 'fix' => false)));
-
-// optionflags
+// Adaptive mode.
 $quizsettings->add(new admin_setting_yesno_with_advanced('quiz/optionflags',
         get_string('adaptive', 'quiz'), get_string('configadaptive', 'quiz'),
         array('value' => 1, 'fix' => false)));
 
-// maximumgrade
-$quizsettings->add(new admin_setting_configtext('quiz/maximumgrade',
-        get_string('maximumgrade'), get_string('configmaximumgrade', 'quiz'), 10, PARAM_INT));
-
-// grademethod
-$quizsettings->add(new admin_setting_combo_with_advanced('quiz/grademethod',
-        get_string('grademethod', 'quiz'), get_string('configgrademethod', 'quiz'),
-        array('value' => QUIZ_GRADEHIGHEST, 'fix' => false), quiz_get_grading_options()));
-
-// penaltyscheme
+// Apply penalties.
 $quizsettings->add(new admin_setting_yesno_with_advanced('quiz/penaltyscheme',
         get_string('penaltyscheme', 'quiz'), get_string('configpenaltyscheme', 'quiz'),
-        array('value' => 1, 'fix' => false)));
+        array('value' => 1, 'fix' => true)));
+
+// Each attempt builds on last.
+$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/attemptonlast',
+        get_string('eachattemptbuildsonthelast', 'quiz'), get_string('configeachattemptbuildsonthelast', 'quiz'),
+        array('value' => 0, 'fix' => true)));
+
+// Review options.
+$quizsettings->add(new admin_setting_quiz_reviewoptions('quiz/review',
+        get_string('reviewoptions', 'quiz'), get_string('configreviewoptions', 'quiz'),
+        array('value' => QUIZ_REVIEW_IMMEDIATELY | QUIZ_REVIEW_OPEN | QUIZ_REVIEW_CLOSED, 'fix' => false)));
+
+// Show the user's picture
+$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/showuserpicture',
+        get_string('showuserpicture', 'quiz'), get_string('configshowuserpicture', 'quiz'),
+        array('value' => 0, 'fix' => false)));
 
-// decimalpoints
+// Decimal places for overall grades.
 $options = array();
-for ($i = 0; $i <= 5; $i++) {
+for ($i = 0; $i <= QUIZ_MAX_DECIMAL_OPTION; $i++) {
     $options[$i] = $i;
 }
 $quizsettings->add(new admin_setting_combo_with_advanced('quiz/decimalpoints',
-        get_string('decimaldigits', 'quiz'), get_string('configdecimaldigits', 'quiz'),
+        get_string('decimalplaces', 'quiz'), get_string('configdecimalplaces', 'quiz'),
         array('value' => 2, 'fix' => false), $options));
 
-// review
-$quizsettings->add(new admin_setting_quiz_reviewoptions('quiz/review',
-        get_string('reviewoptions', 'quiz'), get_string('configreviewoptions', 'quiz'),
-        array('value' => 0x3fffffff, 'fix' => false)));
-
-// popup
-$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/popup',
-        get_string('popup', 'quiz'), get_string('configpopup', 'quiz'),
-        array('value' => 0, 'fix' => false)));
+// Decimal places for question grades.
+$options = array(-1 => get_string('sameasoverall', 'quiz'));
+for ($i = 0; $i <= QUIZ_MAX_Q_DECIMAL_OPTION; $i++) {
+    $options[$i] = $i;
+}
+$quizsettings->add(new admin_setting_combo_with_advanced('quiz/questiondecimalpoints',
+        get_string('decimalplacesquestion', 'quiz'), get_string('configdecimalplacesquestion', 'quiz'),
+        array('value' => -1, 'fix' => true), $options));
 
-// quizpassword
+// Password.
 $quizsettings->add(new admin_setting_text_with_advanced('quiz/password',
         get_string('requirepassword', 'quiz'), get_string('configrequirepassword', 'quiz'),
-        array('value' => '', 'fix' => false), PARAM_TEXT));
+        array('value' => '', 'fix' => true), PARAM_TEXT));
 
-// subnet
+// IP restrictions.
 $quizsettings->add(new admin_setting_text_with_advanced('quiz/subnet',
         get_string('requiresubnet', 'quiz'), get_string('configrequiresubnet', 'quiz'),
-        array('value' => '', 'fix' => false), PARAM_TEXT));
+        array('value' => '', 'fix' => true), PARAM_TEXT));
+
+// Enforced delay between attempts.
+$quizsettings->add(new admin_setting_text_with_advanced('quiz/delay1',
+        get_string('delay1st2nd', 'quiz'), get_string('configdelay1st2nd', 'quiz'),
+        array('value' => 0, 'fix' => true), PARAM_INTEGER));
+$quizsettings->add(new admin_setting_text_with_advanced('quiz/delay2',
+        get_string('delaylater', 'quiz'), get_string('configdelaylater', 'quiz'),
+        array('value' => 0, 'fix' => true), PARAM_INTEGER));
+
+// 'Secure' window.
+$quizsettings->add(new admin_setting_yesno_with_advanced('quiz/popup',
+        get_string('showinsecurepopup', 'quiz'), get_string('configpopup', 'quiz'),
+        array('value' => 0, 'fix' => true)));
 
 /// Now, depending on whether any reports have their own settings page, add
 /// the quiz setting page to the appropriate place in the tree.
@@ -171,4 +167,3 @@ if (empty($reportsbyname)) {
         $ADMIN->add('modsettingsquizcat', $settings);
     }
 }
-?>
index 5e10cbcfef961ba598f6b024467fa0c98ed26c68..3c6994ad1b9c4ed621c2cf5682f1b2b0fe303fb4 100644 (file)
@@ -74,7 +74,7 @@ class simple_rules_test extends UnitTestCase {
 
     function test_time_limit_access_rule() {
         $quiz = new stdClass;
-        $quiz->timelimit = 60;
+        $quiz->timelimit = 3600;
         $quiz->questions = '';
         $cm = new stdClass;
         $cm->id = 0;
index f878f0123bd83b340a5629f2ed4b7c1620ba567b..c125b8c93e0a3d82d7cb8bfe003e41da828d9efb 100644 (file)
@@ -26,5 +26,32 @@ class quiz_lib_test extends UnitTestCase {
         $quiz->sumgrades = '100.0000';
         $this->assertFalse(quiz_has_grades($quiz));
     }
+
+    function test_quiz_format_grade() {
+        $quiz = new stdClass;
+        $quiz->decimalpoints = 2;
+        $this->assertEqual(quiz_format_grade($quiz, 0.12345678), format_float(0.12, 2));
+        $this->assertEqual(quiz_format_grade($quiz, 0), format_float(0, 2));
+        $this->assertEqual(quiz_format_grade($quiz, 1.000000000000), format_float(1, 2));
+        $quiz->decimalpoints = 0;
+        $this->assertEqual(quiz_format_grade($quiz, 0.12345678), '0');
+    }
+
+    function test_quiz_format_question_grade() {
+        $quiz = new stdClass;
+        $quiz->decimalpoints = 2;
+        $quiz->questiondecimalpoints = 2;
+        $this->assertEqual(quiz_format_question_grade($quiz, 0.12345678), format_float(0.12, 2));
+        $this->assertEqual(quiz_format_question_grade($quiz, 0), format_float(0, 2));
+        $this->assertEqual(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 2));
+        $quiz->decimalpoints = 3;
+        $quiz->questiondecimalpoints = -1;
+        $this->assertEqual(quiz_format_question_grade($quiz, 0.12345678), format_float(0.123, 3));
+        $this->assertEqual(quiz_format_question_grade($quiz, 0), format_float(0, 3));
+        $this->assertEqual(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 3));
+        $quiz->questiondecimalpoints = 4;
+        $this->assertEqual(quiz_format_question_grade($quiz, 0.12345678), format_float(0.1235, 4));
+        $this->assertEqual(quiz_format_question_grade($quiz, 0), format_float(0, 4));
+        $this->assertEqual(quiz_format_question_grade($quiz, 1.000000000000), format_float(1, 4));
+    }
 }
-?>
\ No newline at end of file
index 01d115f173cb000432127d210803f037fa633cb6..6bc35f9bba536e5bd93f3d0fc6616c522b6ec7c7 100644 (file)
@@ -71,5 +71,19 @@ class quiz_locallib_test extends UnitTestCase {
         $this->assertEqual(quiz_clean_layout('1,0,2', true), '1,0,2,0');
         $this->assertEqual(quiz_clean_layout('0,1,0,0,2,0', true), '1,0,2,0');
     }
+
+    function test_quiz_rescale_grade() {
+        $quiz = new stdClass;
+        $quiz->decimalpoints = 2;
+        $quiz->questiondecimalpoints = 3;
+        $quiz->grade = 10;
+        $quiz->sumgrades = 10;
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, false), 0.12345678);
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.12, 2));
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, 'question'), format_float(0.123, 3));
+        $quiz->sumgrades = 5;
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, false), 0.24691356);
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, true), format_float(0.25, 2));
+        $this->assertEqual(quiz_rescale_grade(0.12345678, $quiz, 'question'), format_float(0.247, 3));
+    }
 }
-?>
\ No newline at end of file
index 5453ac40e4d812be3b65a51378bf2561a338a997..8b8359c7a402cf0a1a6d33d317eca2a65dbff890 100644 (file)
@@ -5,7 +5,7 @@
 //  This fragment is called by moodle_needs_upgrading() and /admin/index.php
 ////////////////////////////////////////////////////////////////////////////////
 
-$module->version  = 2009011400;   // The (date) version of this module
+$module->version  = 2009031001;   // The (date) version of this module
 $module->requires = 2008072401;   // Requires this Moodle version
 $module->cron     = 0;            // How often should cron check this module (seconds)?
 
index e0a87e1254b6a0f766e9b2e1aa476d9f600927c8..84f0e68afb4e046daa8cbb71a700985b75422ad0 100644 (file)
             }
 
             // Ouside the if because we may be showing feedback but not grades.
-            $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz);
+            $attemptgrade = quiz_rescale_grade($attempt->sumgrades, $quiz, false);
 
             if ($gradecolumn) {
                 if ($attemptoptions->scores && $attempt->timefinish > 0) {
-                    $formattedgrade = $attemptgrade;
+                    $formattedgrade = quiz_format_grade($quiz, $attemptgrade);
                     // highlight the highest grade if appropriate
                     if ($overallstats && !$attempt->preview && $numattempts > 1 && !is_null($mygrade) &&
                             $attemptgrade == $mygrade && $quiz->grademethod == QUIZ_GRADEHIGHEST) {