Index: mod/quiz/report/regrade/report.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/report/regrade/report.php,v
retrieving revision 1.19.2.1
diff -u -r1.19.2.1 report.php
--- mod/quiz/report/regrade/report.php	2 Nov 2007 16:20:37 -0000	1.19.2.1
+++ mod/quiz/report/regrade/report.php	1 Apr 2008 12:07:33 -0000
@@ -11,77 +11,97 @@
         // Print header
         $this->print_header_and_tabs($cm, $course, $quiz, $reportmode="regrade");
 
-        // Check permissions
-        $context = get_context_instance(CONTEXT_MODULE, $cm->id);
-        if (!has_capability('mod/quiz:grade', $context)) {
-            notify(get_string('regradenotallowed', 'quiz'));
-            return true;
-        }
+        $test_result = quiz_save_best_grade($quiz, null, true);
+        
+        require_once($CFG->libdir . '/grade/constants.php');
+        $proceedanyway = optional_param('proceedanyway', false, PARAM_BOOL);
+        
+        if ($proceedanyway || $test_result != GRADE_UPDATE_ITEM_LOCKED) {
+            // Check permissions
+            $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+            if (!has_capability('mod/quiz:grade', $context)) {
+                notify(get_string('regradenotallowed', 'quiz'));
+                return true;
+            }
 
-        // Fetch all attempts
-        if (!$attempts = get_records_select('quiz_attempts', "quiz = '$quiz->id' AND preview = 0")) {
-            print_heading(get_string('noattempts', 'quiz'));
-            return true;
-        }
+            // Fetch all attempts
+            if (!$attempts = get_records_select('quiz_attempts', "quiz = '$quiz->id' AND preview = 0")) {
+                print_heading(get_string('noattempts', 'quiz'));
+                return true;
+            }
+
+            // Fetch all questions
+            $sql = "SELECT q.*, i.grade AS maxgrade FROM {$CFG->prefix}question q,
+                                             {$CFG->prefix}quiz_question_instances i
+                    WHERE i.quiz = $quiz->id
+                    AND i.question = q.id";
+
+            if (! $questions = get_records_sql($sql)) {
+                error("Failed to get questions for regrading!");
+            }
+            get_question_options($questions);
 
-        // Fetch all questions
-        $sql = "SELECT q.*, i.grade AS maxgrade FROM {$CFG->prefix}question q,
-                                         {$CFG->prefix}quiz_question_instances i
-                WHERE i.quiz = $quiz->id
-                AND i.question = q.id";
-
-        if (! $questions = get_records_sql($sql)) {
-            error("Failed to get questions for regrading!");
-        }
-        get_question_options($questions);
-
-        // Print heading
-        print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
-        echo '<div class="boxaligncenter">';
-        print_string('regradedisplayexplanation', 'quiz');
-        echo '</div>';
-
-        // Loop through all questions and all attempts and regrade while printing progress info
-        foreach ($questions as $question) {
-            echo '<strong>'.get_string('regradingquestion', 'quiz', $question->name).'</strong> '.get_string('attempts', 'quiz').": \n";
+            // Print heading
+            print_heading(get_string('regradingquiz', 'quiz', format_string($quiz->name)));
+            echo '<div class="boxaligncenter">';
+            print_string('regradedisplayexplanation', 'quiz');
+            echo '</div>';
+
+            // Loop through all questions and all attempts and regrade while printing progress info
+            foreach ($questions as $question) {
+                echo '<strong>'.get_string('regradingquestion', 'quiz', $question->name).'</strong> '.get_string('attempts', 'quiz').": \n";
+                foreach ($attempts as $attempt) {
+                    set_time_limit(30);
+                    $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
+                    if ($changed) {
+                        link_to_popup_window ('/mod/quiz/reviewquestion.php?attempt='.$attempt->id.'&amp;question='.$question->id,
+                         'reviewquestion', ' #'.$attempt->id, 450, 550, get_string('reviewresponse', 'quiz'));
+                    } else {
+                        echo ' #'.$attempt->id;
+                    }
+                }
+                echo '<br />';
+                // the following makes sure that the output is sent immediately.
+                @flush();@ob_flush();
+            }
+
+            // Loop through all questions and recalculate $attempt->sumgrade
+            $attemptschanged = 0;
             foreach ($attempts as $attempt) {
-                set_time_limit(30);
-                $changed = regrade_question_in_attempt($question, $attempt, $quiz, true);
-                if ($changed) {
-                    link_to_popup_window ('/mod/quiz/reviewquestion.php?attempt='.$attempt->id.'&amp;question='.$question->id,
-                     'reviewquestion', ' #'.$attempt->id, 450, 550, get_string('reviewresponse', 'quiz'));
-                } else {
-                    echo ' #'.$attempt->id;
+                $sumgrades = 0;
+                $questionids = explode(',', quiz_questions_in_quiz($attempt->layout));
+                foreach($questionids as $questionid) {
+                    $lastgradedid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->uniqueid, 'questionid', $questionid);
+                    $sumgrades += get_field('question_states', 'grade', 'id', $lastgradedid);
+                }
+                if ($attempt->sumgrades != $sumgrades) {
+                    $attemptschanged++;
+                    set_field('quiz_attempts', 'sumgrades', $sumgrades, 'id', $attempt->id);
                 }
             }
-            echo '<br />';
-            // the following makes sure that the output is sent immediately.
-            @flush();@ob_flush();
-        }
-
-        // Loop through all questions and recalculate $attempt->sumgrade
-        $attemptschanged = 0;
-        foreach ($attempts as $attempt) {
-            $sumgrades = 0;
-            $questionids = explode(',', quiz_questions_in_quiz($attempt->layout));
-            foreach($questionids as $questionid) {
-                $lastgradedid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->uniqueid, 'questionid', $questionid);
-                $sumgrades += get_field('question_states', 'grade', 'id', $lastgradedid);
-            }
-            if ($attempt->sumgrades != $sumgrades) {
-                $attemptschanged++;
-                set_field('quiz_attempts', 'sumgrades', $sumgrades, 'id', $attempt->id);
-            }
-        }
-
-        // Update the overall quiz grades
-        if ($grades = get_records('quiz_grades', 'quiz', $quiz->id)) {
-            foreach($grades as $grade) {
-                quiz_save_best_grade($quiz, $grade->userid);
+
+            // Update the overall quiz grades
+            if ($grades = get_records('quiz_grades', 'quiz', $quiz->id)) {
+                foreach($grades as $grade) {
+                    quiz_save_best_grade($quiz, $grade->userid);
+                }
             }
-        }
 
-        return true;
+            return true; 
+        
+        } else {
+            $forward_link = $back_link = $CFG->wwwroot . '/mod/quiz/report.php';
+            
+            $forward_params = $back_params = array('q' => $quiz->id, 'mode' => 'overview');
+
+            $forward_params['proceedanyway'] = true;
+            $forward_params['mode'] = 'regrade';
+
+            $confirm_text = get_string('updategradesanyway', 'grades');
+            $quiz_item_locked_confirm = quiz_item_locked_confirm($quiz, $back_link, $forward_link, $back_params, $forward_params, $confirm_text, true);
+            echo $quiz_item_locked_confirm;
+            return true;
+        } 
     }
 }
 
Index: mod/quiz/report/overview/report.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/report/overview/report.php,v
retrieving revision 1.98.2.7
diff -u -r1.98.2.7 report.php
--- mod/quiz/report/overview/report.php	27 Jan 2008 01:26:47 -0000	1.98.2.7
+++ mod/quiz/report/overview/report.php	1 Apr 2008 12:07:33 -0000
@@ -33,15 +33,46 @@
         // Deal with actions
         $action = optional_param('action', '', PARAM_ACTION);
 
+        $noattempts = optional_param('noattempts', 0, PARAM_INT);
+        $detailedmarks = optional_param('detailedmarks', 0, PARAM_INT);
+        $pagesize = optional_param('pagesize', 10, PARAM_INT);
         switch($action) {
             case 'delete': // Some attempts need to be deleted
                 require_capability('mod/quiz:deleteattempts', $context);
                 $attemptids = optional_param('attemptid', array(), PARAM_INT);
 
-                foreach($attemptids as $attemptid) {
-                    add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id,
-                            $attemptid, $cm->id);
-                    quiz_delete_attempt($attemptid, $quiz);
+                // Do a test first to see if the quiz grade item is locked, which would prevent the grades from being deleted
+                $test_result = quiz_delete_attempt(reset($attemptids), $quiz, true);
+                
+                require_once($CFG->libdir . '/grade/constants.php');
+                $proceedanyway = optional_param('proceedanyway', false, PARAM_BOOL);
+
+                if ($proceedanyway || $test_result != GRADE_UPDATE_ITEM_LOCKED) {
+                    foreach($attemptids as $attemptid) {
+                        add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id,
+                             $attemptid, $cm->id);
+                        quiz_delete_attempt($attemptid, $quiz);
+                    }
+                } else {
+                    $forward_link = $back_link = $CFG->wwwroot . '/mod/quiz/report.php';
+                    $back_params = array('id' => $cm->id, 'mode' => 'overview');
+
+                    $forward_params = array('mode' => 'overview',
+                                            'id' => $cm->id,
+                                            'noattempts' => $noattempts,
+                                            'detailedmarks' => $detailedmarks,
+                                            'action' => 'delete',
+                                            'pagesize' => $pagesize,
+                                            'proceedanyway' => true);
+
+                    foreach ($attemptids as $key => $attemptid) {
+                        $forward_params["attemptid[$key]"] = $attemptid;
+                    }
+
+                    $confirm_text = get_string('deletegradesanyway', 'grades');
+                    $quiz_item_locked_confirm = quiz_item_locked_confirm($quiz, $back_link, $forward_link, $back_params, $forward_params, $confirm_text, true);
+                    echo $quiz_item_locked_confirm;
+                    return true;
                 }
             break;
         }
@@ -66,9 +97,6 @@
         $showgrades = $quiz->grade && $quiz->sumgrades && $reviewoptions->scores;
 
         // Set table options
-        $noattempts = optional_param('noattempts', 0, PARAM_INT);
-        $detailedmarks = optional_param('detailedmarks', 0, PARAM_INT);
-        $pagesize = optional_param('pagesize', 10, PARAM_INT);
         $reporturl = $CFG->wwwroot.'/mod/quiz/report.php?mode=overview';
         if ($pagesize < 1) {
             $pagesize = 10;
Index: mod/quiz/report/grading/report.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/report/grading/report.php,v
retrieving revision 1.25.2.2
diff -u -r1.25.2.2 report.php
--- mod/quiz/report/grading/report.php	18 Dec 2007 16:11:41 -0000	1.25.2.2
+++ mod/quiz/report/grading/report.php	1 Apr 2008 12:07:33 -0000
@@ -28,6 +28,7 @@
      * Displays the report.
      */
     function display($quiz, $cm, $course) {
+        global $CFG;
 
         $action = optional_param('action', 'viewquestions', PARAM_ALPHA);
         $questionid = optional_param('questionid', 0, PARAM_INT);
@@ -66,9 +67,17 @@
 
         echo '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>'; // for overlib
 
-        if ($data = data_submitted()) {  // post data submitted, process it
+        $data = data_submitted();
+
+        if (!empty($data->manualgrades)) {  // post data submitted, process it
             confirm_sesskey();
 
+            $test_result = quiz_save_best_grade($quiz, null, true);
+
+            require_once($CFG->libdir . '/grade/constants.php');
+            $proceedanyway = optional_param('proceedanyway', false, PARAM_BOOL);
+            
+            if ($proceedanyway || $test_result != GRADE_UPDATE_ITEM_LOCKED) {
             // now go through all of the responses and save them.
             foreach($data->manualgrades as $uniqueid => $response) {
                 // get our attempt
@@ -91,6 +100,30 @@
                     quiz_save_best_grade($quiz, $attempt->userid);
                 }
             }
+            } else {
+                $forward_link = $back_link = $CFG->wwwroot . '/mod/quiz/report.php';
+                
+                $back_params = array('q' => $data->q, 
+                                     'mode' => 'grading',
+                                     'questionid' => $data->questionid,
+                                     'action' => $data->action);
+
+                $forward_params = fullclone($back_params);
+                
+                foreach ($data->manualgrades as $id => $grade) {
+                    $forward_params["manualgrades[$id][comment]"] = $grade['comment'];
+                    $forward_params["manualgrades[$id][grade]"] = $grade['grade'];
+                }
+               
+                $forward_params['proceedanyway'] = true;
+                $forward_params['sesskey'] = sesskey();
+
+                $confirm_text = get_string('updategradesanyway', 'grades');
+                $quiz_item_locked_confirm = quiz_item_locked_confirm($quiz, $back_link, $forward_link, $back_params, $forward_params, $confirm_text, true);
+                echo $quiz_item_locked_confirm;
+                return true;
+            
+            }
             notify(get_string('changessaved', 'quiz'), 'notifysuccess');
         }
 
@@ -130,7 +163,8 @@
     function view_questions($quiz) {
         global $CFG, $QTYPE_MANUAL;
 
-        $users = get_course_students($quiz->course);
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
+        $users = get_users_by_capability($coursecontext, 'mod/quiz:attempt');
 
         if(empty($users)) {
             print_heading(get_string("noattempts", "quiz"));
@@ -197,7 +231,9 @@
     function view_question($quiz, $question) {
         global $CFG, $db;
 
-        $users     = get_course_students($quiz->course);
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
+        $users = get_users_by_capability($coursecontext, 'mod/quiz:attempt');
+        
         $userids   = implode(',', array_keys($users));
         $usercount = count($users);
 
@@ -336,7 +372,8 @@
 
         $questions[$question->id] = &$question;
         $usehtmleditor = can_use_richtext_editor();
-        $users     = get_course_students($quiz->course);
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
+        $users = get_users_by_capability($coursecontext, 'mod/quiz:attempt');
         $userids   = implode(',', array_keys($users));
 
         // this sql joins the attempts table and the user table
Index: lang/en_utf8/grades.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lang/en_utf8/grades.php,v
retrieving revision 1.111.2.54
diff -u -r1.111.2.54 grades.php
--- lang/en_utf8/grades.php	7 Mar 2008 17:30:52 -0000	1.111.2.54
+++ lang/en_utf8/grades.php	1 Apr 2008 12:07:33 -0000
@@ -127,6 +127,7 @@
 $string['default'] = 'Default';
 $string['defaultprev'] = 'Default ($a)';
 $string['deletecategory'] = 'Delete category';
+$string['deletegradesanyway'] = 'Delete grades anyway';
 $string['disablegradehistory'] = 'Disable grade history';
 $string['displaylettergrade'] = 'Display letter grades';
 $string['displaypercent'] = 'Display percents';
@@ -438,6 +439,7 @@
 $string['setcategories'] = 'Set categories';
 $string['setcategorieserror'] = 'You must first set the categories for your course before you can give weights to them.';
 $string['setgradeletters'] = 'Set grade letters';
+$string['setmaxgradeanyway'] = 'Set maximum grade anyway';
 $string['setpreferences'] = 'Set preferences';
 $string['setting'] = 'Setting';
 $string['settings'] = 'Settings';
@@ -494,6 +496,7 @@
 $string['unlock'] = 'Unlock';
 $string['unlockverbose'] = 'Unlock $a->category$a->itemmodule $a->itemname';
 $string['unused'] = 'Unused';
+$string['updategradesanyway'] = 'Update grades anyway';
 $string['uploadgrades'] = 'Upload grades';
 $string['useadvanced'] = 'Use Advanced Features';
 $string['usedcourses'] = 'Used courses';
Index: mod/quiz/lib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/lib.php,v
retrieving revision 1.282.2.13
diff -u -r1.282.2.13 lib.php
--- mod/quiz/lib.php	19 Mar 2008 12:21:54 -0000	1.282.2.13
+++ mod/quiz/lib.php	1 Apr 2008 12:07:33 -0000
@@ -290,20 +290,24 @@
     }
 
     if ($quiz != null) {
+        $result = null;
         if ($grades = quiz_get_user_grades($quiz, $userid)) {
-            quiz_grade_item_update($quiz, $grades);
+            $result = quiz_grade_item_update($quiz, $grades);
 
         } else if ($userid and $nullifnone) {
             $grade = new object();
             $grade->userid   = $userid;
             $grade->rawgrade = NULL;
-            quiz_grade_item_update($quiz, $grade);
+            $result = quiz_grade_item_update($quiz, $grade);
 
         } else {
-            quiz_grade_item_update($quiz);
+            $result = quiz_grade_item_update($quiz);
         }
 
+        return $result;
+
     } else {
+        $locked_quizzes = array();
         $sql = "SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
                   FROM {$CFG->prefix}quiz a, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
                  WHERE m.name='quiz' AND m.id=cm.module AND cm.instance=a.id";
@@ -312,11 +316,16 @@
                 if ($quiz->grade != 0) {
                     quiz_update_grades($quiz, 0, false);
                 } else {
-                    quiz_grade_item_update($quiz);
+                    if (quiz_grade_item_update($quiz) == GRADE_UPDATE_ITEM_LOCKED) {
+                        $locked_quizzes[] = $quiz;
+                    }
                 }
             }
             rs_close($rs);
         }
+        
+        // TODO print notice showing the list of locked_quizzes
+        return $locked_quizzes;
     }
 }
 
@@ -377,28 +386,6 @@
         $grades = NULL;
     }
     
-    $gradebook_grades = grade_get_grades($quiz->course, 'mod', 'quiz', $quiz->id);
-    if (!empty($gradebook_grades->items)) {
-        $grade_item = $gradebook_grades->items[0];
-        if ($grade_item->locked) {
-            $confirm_regrade = optional_param('confirm_regrade', 0, PARAM_INT);
-            if (!$confirm_regrade) {
-                $message = get_string('gradeitemislocked', 'grades');
-                $back_link = $CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id . '&amp;mode=overview';
-                $regrade_link = qualified_me() . '&amp;confirm_regrade=1';
-                print_box_start('generalbox', 'notice');
-                echo '<p>'. $message .'</p>';
-                echo '<div class="buttons">';
-                print_single_button($regrade_link, null, get_string('regradeanyway', 'grades'), 'post', $CFG->framename);
-                print_single_button($back_link,  null,  get_string('cancel'),  'post',  $CFG->framename);
-                echo '</div>';
-                print_box_end();
-    
-                return GRADE_UPDATE_ITEM_LOCKED;
-            }
-        }
-    }
-
     return grade_update('mod/quiz', $quiz->course, 'mod', 'quiz', $quiz->id, 0, $grades, $params);
 }
 
@@ -970,6 +957,7 @@
  * Removes all grades from gradebook
  * @param int $courseid
  * @param string optional type
+ * @return array Array of quizzes for which grades could not be deleted
  */
 function quiz_reset_gradebook($courseid, $type='') {
     global $CFG;
@@ -978,11 +966,18 @@
               FROM {$CFG->prefix}quiz q, {$CFG->prefix}course_modules cm, {$CFG->prefix}modules m
              WHERE m.name='quiz' AND m.id=cm.module AND cm.instance=q.id AND q.course=$courseid";
 
+    $locked_quizes = array();
+
     if ($quizs = get_records_sql($sql)) {
         foreach ($quizs as $quiz) {
-            quiz_grade_item_update($quiz, 'reset');
+            if (quiz_grade_item_update($quiz, 'reset') == GRADE_UPDATE_ITEM_LOCKED) {
+                $locked_quizes[] = $quiz;
+            }
         }
     }
+
+    // TODO MDL-14119 Use this return array to display a notice
+    return $locked_quizes;
 }
 
 /**
@@ -1174,4 +1169,31 @@
     }
     return '';
 }
+
+function quiz_item_locked_confirm($quiz, $back_link, $forward_link, $back_params=false, $forward_params=false, $confirm_text=null, $return=false) {
+    global $CFG;
+    
+    if (empty($confirm_text)) {
+        $confirm_text = get_string('proceedanyway');
+    }
+
+    $return_string = '';
+
+    $message = get_string('gradeitemislocked', 'grades');
+    
+    $return_string .= print_box_start('generalbox', 'notice', true);
+    $return_string .= '<p>'. $message .'</p>';
+    $return_string .= '<div class="buttons">';
+    $return_string .= print_single_button($forward_link, $forward_params, $confirm_text, 'post', $CFG->framename, true);
+    $return_string .= print_single_button($back_link,  $back_params,  get_string('cancel'),  'post',  $CFG->framename, true);
+    $return_string .= '</div>';
+    $return_string .= print_box_end(true);
+
+    if ($return) {
+        return $return_string;
+    } else {
+        echo $return_string;
+    }
+
+}
 ?>
Index: mod/quiz/locallib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/locallib.php,v
retrieving revision 1.127.2.10
diff -u -r1.127.2.10 locallib.php
--- mod/quiz/locallib.php	29 Feb 2008 16:22:13 -0000	1.127.2.10
+++ mod/quiz/locallib.php	1 Apr 2008 12:07:33 -0000
@@ -102,8 +102,13 @@
 
 /**
  * Delete a quiz attempt.
+ * @param object $attempt
+ * @param object $quiz
+ * @param bool   $test If true, only returns the gradebook's response to the grade delete request
+ * @return mixed
  */
-function quiz_delete_attempt($attempt, $quiz) {
+function quiz_delete_attempt($attempt, $quiz, $test=false) {
+
     if (is_numeric($attempt)) {
         if (!$attempt = get_record('quiz_attempts', 'id', $attempt)) {
             return;
@@ -116,6 +121,11 @@
         return;
     }
 
+    if ($test) { 
+        $userid = $attempt->userid;
+        return quiz_update_grades($quiz, $userid);
+    }
+
     delete_records('quiz_attempts', 'id', $attempt->id);
     delete_attempt($attempt->uniqueid);
 
@@ -130,7 +140,7 @@
         quiz_save_best_grade($quiz, $userid);
     }
 
-    quiz_update_grades($quiz, $userid);
+    return quiz_update_grades($quiz, $userid);
 }
 
 /// Functions to do with quiz layout and pages ////////////////////////////////
@@ -373,9 +383,14 @@
  *
  * @param float $newgrade the new maximum grade for the quiz.
  * @param object $quiz the quiz we are updating. Passed by reference so its grade field can be updated too.
+ * @param bool $test Only do a test to see if the gradebook will accept the update: does not perform any change in DB
  * @return boolean indicating success or failure.
  */
-function quiz_set_grade($newgrade, &$quiz) {
+function quiz_set_grade($newgrade, &$quiz, $test=false) {
+    if ($test) {
+        return quiz_grade_item_update($quiz);
+    }
+
     // This is potentially expensive, so only do it if necessary.
     if (abs($quiz->grade - $newgrade) < 1e-7) {
         // Nothing to do.
@@ -412,11 +427,20 @@
     }
 
     // update grade item and send all grades to gradebook
-    quiz_grade_item_update($quiz);
+    $item_locked = false;
+    if (quiz_grade_item_update($quiz) == GRADE_UPDATE_ITEM_LOCKED) {
+        $item_locked = true; 
+    }
+
     quiz_update_grades($quiz);
 
     if ($success) {
-        return commit_sql();
+        $result = commit_sql();
+        if ($result && $item_locked) {
+            return GRADE_UPDATE_ITEM_LOCKED;
+        } else {
+            return $result;
+        }
     } else {
         rollback_sql();
         return false;
@@ -428,11 +452,16 @@
  *
  * @param object $quiz The quiz for which the best grade is to be calculated and then saved.
  * @param integer $userid The userid to calculate the grade for. Defaults to the current user.
+ * @param bool    $test If true, returns the response from the gradebook but does not update the grades.
  * @return boolean Indicates success or failure.
  */
-function quiz_save_best_grade($quiz, $userid = null) {
+function quiz_save_best_grade($quiz, $userid = null, $test=false) {
     global $USER;
 
+    if ($test) {
+        return quiz_update_grades($quiz, $userid, true);
+    }
+
     if (empty($userid)) {
         $userid = $USER->id;
     }
@@ -466,8 +495,7 @@
         }
     }
 
-    quiz_update_grades($quiz, $userid);
-    return true;
+    return quiz_update_grades($quiz, $userid);
 }
 
 /**
Index: mod/quiz/edit.php
===================================================================
RCS file: /cvsroot/moodle/moodle/mod/quiz/edit.php,v
retrieving revision 1.107.2.8
diff -u -r1.107.2.8 edit.php
--- mod/quiz/edit.php	5 Mar 2008 10:16:17 -0000	1.107.2.8
+++ mod/quiz/edit.php	1 Apr 2008 12:07:33 -0000
@@ -81,6 +81,8 @@
 
     list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', true);
 
+    $quiz_item_locked_confirm = false;
+    
     //these params are only passed from page request to request while we stay on this page
     //otherwise they would go in question_edit_setup
     $quiz_showbreaks = optional_param('showbreaks', -1, PARAM_BOOL);
@@ -237,6 +239,7 @@
         $oldquestions = explode(",", $quiz->questions); // the questions in the old order
         $questions = array(); // for questions in the new order
         $rawgrades = $_POST;
+        $quiz_grades = $quiz->grades;
         unset($quiz->grades);
         foreach ($rawgrades as $key => $value) {
         /// Parse input for question -> grades
@@ -277,10 +280,36 @@
         }
 
         // If rescaling is required save the new maximum
-        if (isset($_REQUEST['maxgrade'])) {
-            if (!quiz_set_grade(optional_param('maxgrade', 0), $quiz)) {
+        $maxgrade = optional_param('maxgrade', null, PARAM_NUMBER);
+
+        if (!is_null($maxgrade)) {
+            $result = quiz_set_grade(optional_param('maxgrade', 0), $quiz, true); // only a test
+            $proceedanyway = optional_param('proceedanyway', false, PARAM_BOOL);
+            
+            require_once($CFG->libdir . '/grade/constants.php');
+
+            if ($proceedanyway || $result != GRADE_UPDATE_ITEM_LOCKED) {
+                $result = quiz_set_grade(optional_param('maxgrade', 0), $quiz); // this time, the real thing
+                if (!$result) {
                 error('Could not set a new maximum grade for the quiz');
             }
+                $quiz->grades = $quiz_grades;
+            } else {
+                $savechanges = optional_param('savechanges', false, PARAM_BOOL);
+
+                $forward_link = $back_link = $CFG->wwwroot . '/mod/quiz/edit.php';
+                $back_params = array('cmid' => $cmid);
+                $forward_params = array('sesskey' => sesskey(),
+                                        'recurse' => $pagevars['recurse'],
+                                        'qpage' => $pagevars['qpage'],
+                                        'cat' => $pagevars['cat'],
+                                        'cmid' => $cmid, 
+                                        'maxgrade' => $maxgrade,
+                                        'savechanges' => $savechanges,
+                                        'proceedanyway' => true);
+                $confirm_text = get_string('setmaxgradeanyway', 'grades');
+                $quiz_item_locked_confirm = quiz_item_locked_confirm($quiz, $back_link, $forward_link, $back_params, $forward_params, $confirm_text, true);
+            }
         }
     }
 
@@ -309,20 +338,24 @@
 
         include('tabs.php');
 
-        print_box_start();
-
-        echo "<div class=\"quizattemptcounts\">\n";
-        echo '<a href="report.php?mode=overview&amp;id=' . $cm->id . '">' .
-                quiz_num_attempt_summary($quiz, $cm) . '</a><br />' .
-                get_string('cannoteditafterattempts', 'quiz');
-        echo "</div>\n";
-
-        $sumgrades = quiz_print_question_list($quiz,  $thispageurl, false, $quiz_showbreaks, $quiz_reordertool);
-        if (!set_field('quiz', 'sumgrades', $sumgrades, 'id', $quiz->instance)) {
-            error('Failed to set sumgrades');
+        if ($quiz_item_locked_confirm) {
+            echo $quiz_item_locked_confirm;
+        } else {
+            print_box_start();
+            
+            echo "<div class=\"quizattemptcounts\">\n";
+            echo '<a href="report.php?mode=overview&amp;id=' . $cm->id . '">' .
+            quiz_num_attempt_summary($quiz, $cm) . '</a><br />' .
+                    get_string('cannoteditafterattempts', 'quiz');
+            echo "</div>\n";
+            
+            $sumgrades = quiz_print_question_list($quiz,  $thispageurl, false, $quiz_showbreaks, $quiz_reordertool);
+            if (!set_field('quiz', 'sumgrades', $sumgrades, 'id', $quiz->instance)) {
+                error('Failed to set sumgrades');
+            }
+            
+            print_box_end();
         }
-
-        print_box_end();
         print_footer($course);
         exit;
     }
@@ -339,25 +372,29 @@
 
     include('tabs.php');
 
-    echo '<table border="0" style="width:100%" cellpadding="2" cellspacing="0">';
-    echo '<tr><td style="width:50%" valign="top">';
-    print_box_start('generalbox quizquestions');
-    print_heading(get_string('questionsinthisquiz', 'quiz'), '', 2);
-
-    $sumgrades = quiz_print_question_list($quiz, $thispageurl, true, $quiz_showbreaks, $quiz_reordertool);
-    if (!set_field('quiz', 'sumgrades', $sumgrades, 'id', $quiz->instance)) {
-        error('Failed to set sumgrades');
+    if ($quiz_item_locked_confirm) {
+        echo $quiz_item_locked_confirm;
+    } else {
+        echo '<table border="0" style="width:100%" cellpadding="2" cellspacing="0">';
+        echo '<tr><td style="width:50%" valign="top">';
+        print_box_start('generalbox quizquestions');
+        print_heading(get_string('questionsinthisquiz', 'quiz'), '', 2);
+        
+        $sumgrades = quiz_print_question_list($quiz, $thispageurl, true, $quiz_showbreaks, $quiz_reordertool);
+        if (!set_field('quiz', 'sumgrades', $sumgrades, 'id', $quiz->instance)) {
+         error('Failed to set sumgrades');
+        }
+        
+        print_box_end();
+        
+        echo '</td><td style="width:50%" valign="top">';
+        
+        question_showbank('editq', $contexts, $thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
+                     $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['showquestiontext']);
+        
+        echo '</td></tr>';
+        echo '</table>';
     }
 
-    print_box_end();
-
-    echo '</td><td style="width:50%" valign="top">';
-
-    question_showbank('editq', $contexts, $thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
-                    $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['showquestiontext']);
-
-    echo '</td></tr>';
-    echo '</table>';
-
     print_footer($course);
 ?>
