MDL-7861 still some icons left ;grr previous commid had wrong MDL id
[moodle.git] / mod / quiz / editlib.php
1 <?php // $Id$
2 /**
3 * Functions used by edit.php to edit quizzes
4 *
5 * @version $Id$
6 * @author Martin Dougiamas and many others. This has recently been extensively
7 *         rewritten by members of the Serving Mathematics project
8 *         {@link http://maths.york.ac.uk/serving_maths}
9 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
10 * @package quiz
11 */
13 require_once("locallib.php");
15 /**
16 * Delete a question from a quiz
17 *
18 * Deletes a question or a pagebreak from a quiz by updating $modform
19 * as well as the quiz, quiz_question_instances
20 * @return boolean         false if the question was not in the quiz
21 * @param int $id          The id of the question to be deleted
22 * @param object $modform  The extended quiz object as used by edit.php
23 *                         This is updated by this function
24 */
25 function quiz_delete_quiz_question($id, &$modform) {
26     // TODO: For the sake of safety check that this question can be deleted
27     // safely, i.e., that it is not already in use.
28     $questions = explode(",", $modform->questions);
30     // only do something if this question exists
31     if (!isset($questions[$id])) {
32         return false;
33     }
35     $question = $questions[$id];
36     unset($questions[$id]);
37     // If we deleted the question at the top and it was followed by
38     // a page break then delete page break as well
39     if ($id == 0 and $questions[1] == 0) {
40         unset($questions[1]);
41     }
42     $modform->questions = implode(",", $questions);
43     // Avoid duplicate page breaks
44     $modform->questions = str_replace(',0,0', ',0', $modform->questions);
45     // save new questionlist in database
46     if (!set_field('quiz', 'questions', $modform->questions, 'id', $modform->instance)) {
47         error('Could not save question list');
48     }
49     delete_records('quiz_question_instances', 'quiz', $modform->instance, 'question', $question);
50     return true;
51 }
54 /**
55 * Add a question to a quiz
56 *
57 * Adds a question to a quiz by updating $modform as well as the
58 * quiz and quiz_question_instances tables. It also adds a page break
59 * if required.
60 * @return boolean         false if the question was already in the quiz
61 * @param int $id          The id of the question to be added
62 * @param object $modform  The extended quiz object as used by edit.php
63 *                         This is updated by this function
64 */
65 function quiz_add_quiz_question($id, &$modform) {
66     $questions = explode(",", $modform->questions);
68     if (in_array($id, $questions)) {
69         return false;
70     }
72     // remove ending page break if it is not needed
73     if ($breaks = array_keys($questions, 0)) {
74         // determine location of the last two page breaks
75         $end = end($breaks);
76         $last = prev($breaks);
77         $last = $last ? $last : -1;
78         if (!$modform->questionsperpage or (($end - $last -1) < $modform->questionsperpage)) {
79             array_pop($questions);
80         }
81     }
82     // add question
83     $questions[] = $id;
84     // add ending page break
85     $questions[] = 0;
87     // Save new questionslist in database
88     $modform->questions = implode(",", $questions);
89     if (!set_field('quiz', 'questions', $modform->questions, 'id', $modform->id)) {
90         error('Could not save question list');
91     }
93     // update question grades
94     $questionrecord = get_record("question", "id", $id);
95     $modform->grades[$id] = $questionrecord->defaultgrade;
96     quiz_update_question_instance($modform->grades[$id], $id, $modform->instance);
98     return true;
99 }
101 /**
102 * Save changes to question instance
104 * Saves changes to the question grades in the quiz_question_instances table.
105 * It does not update 'sumgrades' in the quiz table.
106 * @return boolean         Indicates success or failure.
107 * @param integer grade    The maximal grade for the question
108 * @param integer $questionid  The id of the question
109 * @param integer $quizid  The id of the quiz to update / add the instances for.
110 */
111 function quiz_update_question_instance($grade, $questionid, $quizid) {
112     if ($instance = get_record("quiz_question_instances", "quiz", $quizid, 'question', $questionid)) {
113         $instance->grade = $grade;
114         return update_record('quiz_question_instances', $instance);
115     } else {
116         unset($instance);
117         $instance->quiz = $quizid;
118         $instance->question = $questionid;
119         $instance->grade = $grade;
120         return insert_record("quiz_question_instances", $instance);
121     }
124 /**
125 * Prints a list of quiz questions in a small layout form with knobs
127 * @return int sum of maximum grades
128 * @param object $quiz This is not the standard quiz object used elsewhere but
129 *     it contains the quiz layout in $quiz->questions and the grades in
130 *     $quiz->grades
131 * @param boolean $allowdelete Indicates whether the delete icons should be displayed
132 * @param boolean $showbreaks  Indicates whether the page breaks should be displayed
133 * @param boolean $showbreaks  Indicates whether the reorder tool should be displayed
134 */
135 function quiz_print_question_list($quiz, $allowdelete=true, $showbreaks=true, $reordertool=false) {
136     global $USER, $CFG, $QTYPES;
138     $strorder = get_string("order");
139     $strquestionname = get_string("questionname", "quiz");
140     $strgrade = get_string("grade");
141     $strremove = get_string('remove', 'quiz');
142     $stredit = get_string("edit");
143     $straction = get_string("action");
144     $strmoveup = get_string("moveup");
145     $strmovedown = get_string("movedown");
146     $strsavegrades = get_string("savegrades", "quiz");
147     $strtype = get_string("type", "quiz");
148     $strpreview = get_string("preview", "quiz");
150     if (!$quiz->questions) {
151         echo "<p align=\"center\">";
152         print_string("noquestions", "quiz");
153         echo "</p>";
154         return 0;
155     }
157     if (!$questions = get_records_sql("SELECT q.*,c.course
158                               FROM {$CFG->prefix}question q,
159                                    {$CFG->prefix}question_categories c
160                              WHERE q.id in ($quiz->questions)
161                                AND q.category = c.id")) {
162         echo "<p align=\"center\">";
163         print_string("noquestions", "quiz");
164         echo "</p>";
165         return 0;
166     }
168     $count = 0;
169     $qno = 1;
170     $sumgrade = 0;
171     $order = explode(",", $quiz->questions);
172     $lastindex = count($order)-1;
173     // If the list does not end with a pagebreak then add it on.
174     if ($order[$lastindex] != 0) {
175         $order[] = 0;
176         $lastindex++;
177     }
178     echo "<form method=\"post\" action=\"edit.php\">";
179     echo "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />";
181     print_simple_box_start('center', '100%', '#ffffff', 0);
182     echo "<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\" width=\"100%\">\n";
183     echo "<tr><th colspan=\"3\" nowrap=\"nowrap\" class=\"header\" scope=\"col\">$strorder</th><th class=\"header\" scope=\"col\">#</th><th align=\"left\" width=\"100%\" nowrap=\"nowrap\" class=\"header\" scope=\"col\">$strquestionname</th><th nowrap=\"nowrap\" class=\"header\" scope=\"col\">$strtype</th><th nowrap=\"nowrap\" class=\"header\" scope=\"col\">$strgrade</th><th align=\"center\" width=\"60\" nowrap=\"nowrap\" class=\"header\" scope=\"col\">$straction</th></tr>\n";
184     foreach ($order as $i => $qnum) {
186         if ($qnum and empty($questions[$qnum])) {
187             continue;
188         }
190         // If the questiontype is missing change the question type
191         if ($qnum and !array_key_exists($questions[$qnum]->qtype, $QTYPES)) {
192             $questions[$qnum]->qtype = 'missingtype';
193         }
195         // Show the re-ordering field if the tool is turned on.
196         // But don't show it in front of pagebreaks if they are hidden.
197         if ($reordertool) {
198             if ($qnum or $showbreaks) {
199                 echo '<tr><td><input type="text" name="o'.$i.'" size="2" value="'.(10*$count+10).'" /></td>';
200             } else {
201                 echo '<tr><td><input type="hidden" name="o'.$i.'" size="2" value="'.(10*$count+10).'" /></td>';
202             }
203         } else {
204             echo '<tr><td></td>';
205         }
206         if ($qnum == 0) { // This is a page break
207             if ($showbreaks) {
208                 echo '<td colspan ="3">&nbsp;</td>';
209                 echo '<td><table width="100%" style="line-height:11px; font-size:9px; margin: -5px -5px;"><tr>';
210                 echo '<td><hr noshade="noshade" /></td>';
211                 echo '<td width="50">Page break</td>';
212                 echo '<td><hr noshade="noshade" /></td><td width="45">';
213                 if ($count > 1) {
214                     echo "<a title=\"$strmoveup\" href=\"edit.php?up=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\"><img
215                          src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall\" alt=\"$strmoveup\" /></a>";
216                 }
217                 echo '&nbsp;';
218                 if ($count < $lastindex) {
219                     echo "<a title=\"$strmovedown\" href=\"edit.php?down=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\"><img
220                          src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\" alt=\"$strmovedown\" /></a>";
222                     echo "<a title=\"$strremove\" href=\"edit.php?delete=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\">
223                           <img src=\"$CFG->pixpath/t/delete.gif\" class=\"iconsmall\" alt=\"$strremove\" /></a>";
224                 }
225                 echo '</td></tr></table></td>';
226                 echo '<td colspan="2">&nbsp;</td>';
227             }
228             $count++;
229             // missing </tr> here, if loop is broken, need to close the </tr> from line 199/201
230             echo "</tr>";
231             continue;
232         }
233         $question = $questions[$qnum];
234         $canedit = has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $question->course));
236         echo "<td>";
237         if ($count != 0) {
238             echo "<a title=\"$strmoveup\" href=\"edit.php?up=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\"><img
239                  src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall\" alt=\"$strmoveup\" /></a>";
240         }
241         echo "</td>";
242         echo "<td>";
243         if ($count < $lastindex-1) {
244             echo "<a title=\"$strmovedown\" href=\"edit.php?down=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\"><img
245                  src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\" alt=\"$strmovedown\" /></a>";
246         }
247         echo "</td>";
249         if (!$quiz->shufflequestions) {
250             // Print and increment question number
251             echo '<td>'.($question->length ? $qno : '&nbsp;').'</td>';
252             $qno += $question->length;
253         } else {
254             echo '<td>&nbsp;</td>';
255         }
257         echo "<td>$question->name</td>";
258         echo "<td align=\"center\">";
259         print_question_icon($question, $canedit);
260         echo "</td>";
261         echo '<td align="left">';
262         if ($question->qtype == 'description') {
263             echo "<input type=\"hidden\" name=\"q$qnum\" value=\"0\" /> \n";
264         } else {
265             echo '<input type="text" name="q'.$qnum.'" size="2" value="'.$quiz->grades[$qnum].
266              '" tabindex="'.($lastindex+$qno).'" />';
267         }
268         echo '</td><td align="center">';
270         $context = $quiz->id ? '&amp;contextquiz='.$quiz->id : '';
271         $quiz_id = $quiz->id ? '&amp;quizid=' . $quiz->id : '';
272         if ($question->qtype != 'random') {
273             echo "<a title=\"$strpreview\" href=\"javascript:void(0)\" onClick=\"openpopup('/question/preview.php?id=$qnum$quiz_id','questionpreview', " . 
274                     QUESTION_PREVIEW_POPUP_OPTIONS . ", false)\">
275                     <img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" /></a>";
276         }
277         if ($canedit) {
278             echo "<a title=\"$stredit\" href=\"$CFG->wwwroot/question/question.php?id=$qnum$context\">
279                     <img src=\"$CFG->pixpath/t/edit.gif\" class=\"iconsmall\" alt=\"$stredit\" /></a>";
280         }
281         if ($allowdelete) {
282             echo "<a title=\"$strremove\" href=\"edit.php?delete=$count&amp;quizid=$quiz->id&amp;sesskey=$USER->sesskey\">
283                     <img src=\"$CFG->pixpath/t/removeright.gif\" class=\"iconsmall\" alt=\"$strremove\" /></a>";
284         }
286         echo "</td></tr>";
287         $count++;
288         $sumgrade += $quiz->grades[$qnum];
289     }
291     echo "<tr><td colspan=\"6\" align=\"right\">\n";
292     print_string('total');
293     echo "</td>";
294     echo ": <td align=\"left\">\n";
295     echo "<b>$sumgrade</b>";
296     echo "</td><td>&nbsp;\n</td></tr>\n";
298     echo "<tr><td colspan=\"6\" align=\"right\">\n";
299     print_string('maximumgrade');
300     echo "</td>";
301     echo ": <td align=\"left\">\n";
302     echo '<input type="text" name="maxgrade" size="2" tabindex="'.($qno+1)
303      .'" value="'.$quiz->grade.'" />';
304     echo '</td><td align="left">';
305     helpbutton("maxgrade", get_string("maximumgrade"), "quiz");
306     echo "</td></tr></table>\n";
308     echo '<div align="center"><input type="submit" value="'.get_string('savechanges').'" />';
309     echo '<input type="hidden" name="savechanges" value="save" /></div>';
310     echo '<input type="hidden" name="savequizid" value="'.$quiz->id.'" />'; // ugly hack to prevent modform session "mistakes"
312     print_simple_box_end();
313     echo "</form>\n";
315 /// Form to choose to show pagebreaks and to repaginate quiz
316     echo '<form method="post" action="edit.php" id="showbreaks">';
317     echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
318     echo '<input type="hidden" name="showbreaks" value="0" />';
319     echo '<input type="checkbox" name="showbreaks" value="1"';
320     if ($showbreaks) {
321         echo ' checked="checked"';
322     }
323     echo ' onchange="getElementById(\'showbreaks\').submit(); return true;" />';
324     print_string('showbreaks', 'quiz');
326     if ($showbreaks) {
327         $perpage= array();
328         for ($i=0; $i<=50; ++$i) {
329             $perpage[$i] = $i;
330         }
331         $perpage[0] = get_string('allinone', 'quiz');
332         echo '<br />&nbsp;&nbsp;';
333         print_string('repaginate', 'quiz',
334          choose_from_menu($perpage, 'questionsperpage', $quiz->questionsperpage, '', '', '', true));
335     }
337     echo '<br /><input type="hidden" name="reordertool" value="0" />';
338     echo '<input type="checkbox" name="reordertool" value="1"';
339     if ($reordertool) {
340         echo ' checked="checked"';
341     }
342     echo ' onchange="getElementById(\'showbreaks\').submit(); return true;" />';
343     print_string('reordertool', 'quiz');
344     echo ' ';
345     helpbutton('reorderingtool', get_string('reorderingtool', 'quiz'), 'quiz');
346     
347     echo '<div align="center"><input type="submit" name="repaginate" value="'. get_string('go') .'" /></div>';
348     echo '</form>';
350     return $sumgrade;
353 ?>