weekly release 2.3dev (blame stronk7 for 0202 mistake)
[moodle.git] / question / type / edit_question_form.php
CommitLineData
aeb15530 1<?php
fe6ce234
DC
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
36703ed7 17/**
18 * A base class for question editing forms.
19 *
7764183a 20 * @package moodlecore
2b7da645 21 * @subpackage questiontypes
b04a4319
TH
22 * @copyright 2006 The Open University
23 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
fe6ce234 24 */
36703ed7 25
2b7da645 26
a17b297d
TH
27defined('MOODLE_INTERNAL') || die();
28
29
36703ed7 30/**
31 * Form definition base class. This defines the common fields that
32 * all question types need. Question types should define their own
33 * class that inherits from this one, and implements the definition_inner()
34 * method.
271e6dec 35 *
7764183a
TH
36 * @copyright 2006 The Open University
37 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
36703ed7 38 */
2b7da645
TH
39abstract class question_edit_form extends moodleform {
40 const DEFAULT_NUM_HINTS = 2;
41
271ffe3f 42 /**
43 * Question object with options and answers already loaded by get_question_options
44 * Be careful how you use this it is needed sometimes to set up the structure of the
32db0d42 45 * form in definition_inner but data is always loaded into the form with set_data.
271ffe3f 46 * @var object
47 */
2b7da645
TH
48 protected $question;
49
50 protected $contexts;
51 protected $category;
52 protected $categorycontext;
271e6dec 53
fe6ce234
DC
54 /** @var object current context */
55 public $context;
56 /** @var array html editor options */
57 public $editoroptions;
58 /** @var array options to preapre draft area */
59 public $fileoptions;
60 /** @var object instance of question type */
61 public $instance;
62
2b7da645 63 public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
fe6ce234 64 global $DB;
271e6dec 65
271ffe3f 66 $this->question = $question;
271e6dec 67 $this->contexts = $contexts;
68
eaeb6b51
TH
69 $record = $DB->get_record('question_categories',
70 array('id' => $question->category), 'contextid');
fe6ce234
DC
71 $this->context = get_context_instance_by_id($record->contextid);
72
eaeb6b51
TH
73 $this->editoroptions = array('subdirs' => 1, 'maxfiles' => EDITOR_UNLIMITED_FILES,
74 'context' => $this->context);
41dcc2a5 75 $this->fileoptions = array('subdirs' => 1, 'maxfiles' => -1, 'maxbytes' => -1);
fe6ce234 76
271e6dec 77 $this->category = $category;
78 $this->categorycontext = get_context_instance_by_id($category->contextid);
271e6dec 79
2b7da645 80 parent::__construct($submiturl, null, 'post', '', null, $formeditable);
271ffe3f 81 }
8e652f02 82
36703ed7 83 /**
84 * Build the form definition.
1d284fbd 85 *
295043c2 86 * This adds all the form fields that the default question type supports.
36703ed7 87 * If your question type does not support all these fields, then you can
88 * override this method and remove the ones you don't want with $mform->removeElement().
89 */
c7df5006 90 protected function definition() {
f34488b2 91 global $COURSE, $CFG, $DB;
1d284fbd 92
36703ed7 93 $qtype = $this->qtype();
94 $langfile = "qtype_$qtype";
1d284fbd 95
f9b0500f 96 $mform = $this->_form;
36703ed7 97
98 // Standard fields at the start of the form.
271ffe3f 99 $mform->addElement('header', 'generalheader', get_string("general", 'form'));
1d284fbd 100
2b7da645 101 if (!isset($this->question->id)) {
5d548d3e 102 // Adding question
2b7da645 103 $mform->addElement('questioncategory', 'category', get_string('category', 'question'),
522b89d1 104 array('contexts' => $this->contexts->having_cap('moodle/question:add')));
eaeb6b51
TH
105 } else if (!($this->question->formoptions->canmove ||
106 $this->question->formoptions->cansaveasnew)) {
5d548d3e 107 // Editing question with no permission to move from category.
2b7da645 108 $mform->addElement('questioncategory', 'category', get_string('category', 'question'),
271e6dec 109 array('contexts' => array($this->categorycontext)));
eaeb6b51 110 } else if ($this->question->formoptions->movecontext) {
5d548d3e 111 // Moving question to another context.
eaeb6b51
TH
112 $mform->addElement('questioncategory', 'categorymoveto',
113 get_string('category', 'question'),
271e6dec 114 array('contexts' => $this->contexts->having_cap('moodle/question:add')));
115
116 } else {
5d548d3e 117 // Editing question with permission to move from category or save as new q
271e6dec 118 $currentgrp = array();
eaeb6b51
TH
119 $currentgrp[0] = $mform->createElement('questioncategory', 'category',
120 get_string('categorycurrent', 'question'),
271e6dec 121 array('contexts' => array($this->categorycontext)));
eaeb6b51
TH
122 if ($this->question->formoptions->canedit ||
123 $this->question->formoptions->cansaveasnew) {
271e6dec 124 //not move only form
eaeb6b51
TH
125 $currentgrp[1] = $mform->createElement('checkbox', 'usecurrentcat', '',
126 get_string('categorycurrentuse', 'question'));
271e6dec 127 $mform->setDefault('usecurrentcat', 1);
128 }
129 $currentgrp[0]->freeze();
130 $currentgrp[0]->setPersistantFreeze(false);
eaeb6b51
TH
131 $mform->addGroup($currentgrp, 'currentgrp',
132 get_string('categorycurrent', 'question'), null, false);
271e6dec 133
eaeb6b51
TH
134 $mform->addElement('questioncategory', 'categorymoveto',
135 get_string('categorymoveto', 'question'),
271e6dec 136 array('contexts' => array($this->categorycontext)));
eaeb6b51
TH
137 if ($this->question->formoptions->canedit ||
138 $this->question->formoptions->cansaveasnew) {
271e6dec 139 //not move only form
140 $mform->disabledIf('categorymoveto', 'usecurrentcat', 'checked');
141 }
142 }
375ed78a 143
eaeb6b51
TH
144 $mform->addElement('text', 'name', get_string('questionname', 'question'),
145 array('size' => 50));
271ffe3f 146 $mform->setType('name', PARAM_TEXT);
36703ed7 147 $mform->addRule('name', null, 'required', null, 'client');
1d284fbd 148
2b7da645 149 $mform->addElement('editor', 'questiontext', get_string('questiontext', 'question'),
5d548d3e 150 array('rows' => 15), $this->editoroptions);
36703ed7 151 $mform->setType('questiontext', PARAM_RAW);
1d284fbd 152
2b7da645 153 $mform->addElement('text', 'defaultmark', get_string('defaultmark', 'question'),
36703ed7 154 array('size' => 3));
7664182d 155 $mform->setType('defaultmark', PARAM_FLOAT);
2b7da645
TH
156 $mform->setDefault('defaultmark', 1);
157 $mform->addRule('defaultmark', null, 'required', null, 'client');
36703ed7 158
2b7da645 159 $mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'question'),
5d548d3e 160 array('rows' => 10), $this->editoroptions);
36703ed7 161 $mform->setType('generalfeedback', PARAM_RAW);
2b7da645 162 $mform->addHelpButton('generalfeedback', 'generalfeedback', 'question');
1d284fbd 163
36703ed7 164 // Any questiontype specific fields.
165 $this->definition_inner($mform);
166
c599a682 167 if (!empty($CFG->usetags)) {
168 $mform->addElement('header', 'tagsheader', get_string('tags'));
169 $mform->addElement('tags', 'tags', get_string('tags'));
170 }
171
2b7da645 172 if (!empty($this->question->id)) {
eaeb6b51
TH
173 $mform->addElement('header', 'createdmodifiedheader',
174 get_string('createdmodifiedheader', 'question'));
7f389342 175 $a = new stdClass();
2b7da645 176 if (!empty($this->question->createdby)) {
271e6dec 177 $a->time = userdate($this->question->timecreated);
eaeb6b51
TH
178 $a->user = fullname($DB->get_record(
179 'user', array('id' => $this->question->createdby)));
271e6dec 180 } else {
181 $a->time = get_string('unknown', 'question');
182 $a->user = get_string('unknown', 'question');
183 }
eaeb6b51
TH
184 $mform->addElement('static', 'created', get_string('created', 'question'),
185 get_string('byandon', 'question', $a));
2b7da645 186 if (!empty($this->question->modifiedby)) {
7f389342 187 $a = new stdClass();
271e6dec 188 $a->time = userdate($this->question->timemodified);
eaeb6b51
TH
189 $a->user = fullname($DB->get_record(
190 'user', array('id' => $this->question->modifiedby)));
191 $mform->addElement('static', 'modified', get_string('modified', 'question'),
192 get_string('byandon', 'question', $a));
271e6dec 193 }
194 }
195
36703ed7 196 // Standard fields at the end of the form.
197 $mform->addElement('hidden', 'id');
198 $mform->setType('id', PARAM_INT);
199
200 $mform->addElement('hidden', 'qtype');
201 $mform->setType('qtype', PARAM_ALPHA);
202
203 $mform->addElement('hidden', 'inpopup');
204 $mform->setType('inpopup', PARAM_INT);
205
206 $mform->addElement('hidden', 'versioning');
207 $mform->setType('versioning', PARAM_BOOL);
208
271e6dec 209 $mform->addElement('hidden', 'movecontext');
210 $mform->setType('movecontext', PARAM_BOOL);
211
9ab75b2b 212 $mform->addElement('hidden', 'cmid');
213 $mform->setType('cmid', PARAM_INT);
214 $mform->setDefault('cmid', 0);
215
271e6dec 216 $mform->addElement('hidden', 'courseid');
217 $mform->setType('courseid', PARAM_INT);
218 $mform->setDefault('courseid', 0);
219
7cd4fda6 220 $mform->addElement('hidden', 'returnurl');
221 $mform->setType('returnurl', PARAM_LOCALURL);
271e6dec 222 $mform->setDefault('returnurl', 0);
7cd4fda6 223
a13d4fbd
TH
224 $mform->addElement('hidden', 'scrollpos');
225 $mform->setType('scrollpos', PARAM_INT);
226 $mform->setDefault('scrollpos', 0);
227
fa583f5f 228 $mform->addElement('hidden', 'appendqnumstring');
229 $mform->setType('appendqnumstring', PARAM_ALPHA);
230 $mform->setDefault('appendqnumstring', 0);
231
375ed78a 232 $buttonarray = array();
2b7da645 233 if (!empty($this->question->id)) {
271e6dec 234 //editing / moving question
2b7da645 235 if ($this->question->formoptions->movecontext) {
eaeb6b51
TH
236 $buttonarray[] = $mform->createElement('submit', 'submitbutton',
237 get_string('moveq', 'question'));
238 } else if ($this->question->formoptions->canedit ||
239 $this->question->formoptions->canmove ||
240 $this->question->formoptions->movecontext) {
241 $buttonarray[] = $mform->createElement('submit', 'submitbutton',
242 get_string('savechanges'));
271e6dec 243 }
2b7da645 244 if ($this->question->formoptions->cansaveasnew) {
eaeb6b51
TH
245 $buttonarray[] = $mform->createElement('submit', 'makecopy',
246 get_string('makecopy', 'question'));
271e6dec 247 }
eaeb6b51 248 $buttonarray[] = $mform->createElement('cancel');
271e6dec 249 } else {
250 // adding new question
eaeb6b51
TH
251 $buttonarray[] = $mform->createElement('submit', 'submitbutton',
252 get_string('savechanges'));
253 $buttonarray[] = $mform->createElement('cancel');
375ed78a 254 }
375ed78a 255 $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
256 $mform->closeHeaderBefore('buttonar');
271e6dec 257
5d548d3e 258 if ($this->question->formoptions->movecontext) {
271e6dec 259 $mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar'));
eaeb6b51
TH
260 } else if ((!empty($this->question->id)) && (!($this->question->formoptions->canedit ||
261 $this->question->formoptions->cansaveasnew))) {
271e6dec 262 $mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar', 'currentgrp'));
263 }
36703ed7 264 }
fa583f5f 265
36703ed7 266 /**
267 * Add any question-type specific form fields.
1d284fbd 268 *
269 * @param object $mform the form being built.
36703ed7 270 */
2b7da645 271 protected function definition_inner($mform) {
36703ed7 272 // By default, do nothing.
273 }
1d284fbd 274
2aef1fe5 275 /**
276 * Get the list of form elements to repeat, one for each answer.
277 * @param object $mform the form being built.
278 * @param $label the label to use for each option.
279 * @param $gradeoptions the possible grades for each answer.
280 * @param $repeatedoptions reference to array of repeated options to fill
eaeb6b51
TH
281 * @param $answersoption reference to return the name of $question->options
282 * field holding an array of answers
2aef1fe5 283 * @return array of form fields.
284 */
2a6c5c52 285 protected function get_per_answer_fields($mform, $label, $gradeoptions,
eaeb6b51 286 &$repeatedoptions, &$answersoption) {
2aef1fe5 287 $repeated = array();
1c2ed7c5 288 $repeated[] = $mform->createElement('header', 'answerhdr', $label);
eaeb6b51
TH
289 $repeated[] = $mform->createElement('text', 'answer',
290 get_string('answer', 'question'), array('size' => 80));
291 $repeated[] = $mform->createElement('select', 'fraction',
292 get_string('grade'), $gradeoptions);
293 $repeated[] = $mform->createElement('editor', 'feedback',
294 get_string('feedback', 'question'), array('rows' => 5), $this->editoroptions);
2aef1fe5 295 $repeatedoptions['answer']['type'] = PARAM_RAW;
296 $repeatedoptions['fraction']['default'] = 0;
297 $answersoption = 'answers';
298 return $repeated;
299 }
300
301 /**
302 * Add a set of form fields, obtained from get_per_answer_fields, to the form,
303 * one for each existing answer, with some blanks for some new ones.
304 * @param object $mform the form being built.
305 * @param $label the label to use for each option.
306 * @param $gradeoptions the possible grades for each answer.
eaeb6b51
TH
307 * @param $minoptions the minimum number of answer blanks to display.
308 * Default QUESTION_NUMANS_START.
2aef1fe5 309 * @param $addoptions the number of answer blanks to add. Default QUESTION_NUMANS_ADD.
310 */
eaeb6b51
TH
311 protected function add_per_answer_fields(&$mform, $label, $gradeoptions,
312 $minoptions = QUESTION_NUMANS_START, $addoptions = QUESTION_NUMANS_ADD) {
2aef1fe5 313 $answersoption = '';
314 $repeatedoptions = array();
eaeb6b51
TH
315 $repeated = $this->get_per_answer_fields($mform, $label, $gradeoptions,
316 $repeatedoptions, $answersoption);
2aef1fe5 317
2b7da645 318 if (isset($this->question->options)) {
2aef1fe5 319 $countanswers = count($this->question->options->$answersoption);
320 } else {
321 $countanswers = 0;
322 }
2b7da645 323 if ($this->question->formoptions->repeatelements) {
2aef1fe5 324 $repeatsatstart = max($minoptions, $countanswers + $addoptions);
325 } else {
326 $repeatsatstart = $countanswers;
327 }
328
eaeb6b51
TH
329 $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions,
330 'noanswers', 'addanswers', $addoptions,
331 get_string('addmorechoiceblanks', 'qtype_multichoice'));
2aef1fe5 332 }
333
2b7da645
TH
334 protected function add_combined_feedback_fields($withshownumpartscorrect = false) {
335 $mform = $this->_form;
336
eaeb6b51
TH
337 $mform->addElement('header', 'combinedfeedbackhdr',
338 get_string('combinedfeedback', 'question'));
2b7da645 339
eaeb6b51
TH
340 $fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
341 foreach ($fields as $feedbackname) {
2b7da645
TH
342 $mform->addElement('editor', $feedbackname, get_string($feedbackname, 'question'),
343 array('rows' => 5), $this->editoroptions);
344 $mform->setType($feedbackname, PARAM_RAW);
345
346 if ($withshownumpartscorrect && $feedbackname == 'partiallycorrectfeedback') {
f7094147 347 $mform->addElement('advcheckbox', 'shownumcorrect',
eaeb6b51
TH
348 get_string('options', 'question'),
349 get_string('shownumpartscorrect', 'question'));
2b7da645
TH
350 }
351 }
352 }
353
354 protected function get_hint_fields($withclearwrong = false, $withshownumpartscorrect = false) {
355 $mform = $this->_form;
356
357 $repeated = array();
43e607ca 358 $repeated[] = $mform->createElement('header', 'hinthdr', get_string('hintn', 'question'));
7a719748
TH
359 $repeated[] = $mform->createElement('editor', 'hint', get_string('hinttext', 'question'),
360 array('rows' => 5), $this->editoroptions);
2b7da645
TH
361 $repeatedoptions['hint']['type'] = PARAM_RAW;
362
363 if ($withclearwrong) {
f7094147 364 $repeated[] = $mform->createElement('advcheckbox', 'hintclearwrong',
eaeb6b51 365 get_string('options', 'question'), get_string('clearwrongparts', 'question'));
2b7da645
TH
366 }
367 if ($withshownumpartscorrect) {
f7094147 368 $repeated[] = $mform->createElement('advcheckbox', 'hintshownumcorrect', '',
eaeb6b51 369 get_string('shownumpartscorrect', 'question'));
2b7da645
TH
370 }
371
372 return array($repeated, $repeatedoptions);
373 }
374
eaeb6b51
TH
375 protected function add_interactive_settings($withclearwrong = false,
376 $withshownumpartscorrect = false) {
2b7da645
TH
377 $mform = $this->_form;
378
eaeb6b51
TH
379 $mform->addElement('header', 'multitriesheader',
380 get_string('settingsformultipletries', 'question'));
2b7da645
TH
381
382 $penalties = array(
383 1.0000000,
384 0.5000000,
385 0.3333333,
386 0.2500000,
387 0.2000000,
388 0.1000000,
389 0.0000000
390 );
391 if (!empty($this->question->penalty) && !in_array($this->question->penalty, $penalties)) {
392 $penalties[] = $this->question->penalty;
393 sort($penalties);
394 }
395 $penaltyoptions = array();
396 foreach ($penalties as $penalty) {
397 $penaltyoptions["$penalty"] = (100 * $penalty) . '%';
398 }
eaeb6b51
TH
399 $mform->addElement('select', 'penalty',
400 get_string('penaltyforeachincorrecttry', 'question'), $penaltyoptions);
2b7da645 401 $mform->addRule('penalty', null, 'required', null, 'client');
068b4594 402 $mform->addHelpButton('penalty', 'penaltyforeachincorrecttry', 'question');
2b7da645
TH
403 $mform->setDefault('penalty', 0.3333333);
404
405 if (isset($this->question->hints)) {
406 $counthints = count($this->question->hints);
407 } else {
408 $counthints = 0;
409 }
410
411 if ($this->question->formoptions->repeatelements) {
412 $repeatsatstart = max(self::DEFAULT_NUM_HINTS, $counthints);
413 } else {
414 $repeatsatstart = $counthints;
415 }
416
417 list($repeated, $repeatedoptions) = $this->get_hint_fields(
418 $withclearwrong, $withshownumpartscorrect);
419 $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions,
420 'numhints', 'addhint', 1, get_string('addanotherhint', 'question'));
421 }
422
423 public function set_data($question) {
f9b0500f 424 question_bank::get_qtype($question->qtype)->set_default_options($question);
2b7da645 425
fe6ce234
DC
426 // prepare question text
427 $draftid = file_get_submitted_draft_itemid('questiontext');
428
429 if (!empty($question->questiontext)) {
430 $questiontext = $question->questiontext;
431 } else {
432 $questiontext = '';
271ffe3f 433 }
eaeb6b51
TH
434 $questiontext = file_prepare_draft_area($draftid, $this->context->id,
435 'question', 'questiontext', empty($question->id) ? null : (int) $question->id,
436 $this->fileoptions, $questiontext);
fe6ce234
DC
437
438 $question->questiontext = array();
439 $question->questiontext['text'] = $questiontext;
eaeb6b51
TH
440 $question->questiontext['format'] = empty($question->questiontextformat) ?
441 editors_get_preferred_format() : $question->questiontextformat;
fe6ce234
DC
442 $question->questiontext['itemid'] = $draftid;
443
444 // prepare general feedback
445 $draftid = file_get_submitted_draft_itemid('generalfeedback');
446
447 if (empty($question->generalfeedback)) {
448 $question->generalfeedback = '';
449 }
450
eaeb6b51
TH
451 $feedback = file_prepare_draft_area($draftid, $this->context->id,
452 'question', 'generalfeedback', empty($question->id) ? null : (int) $question->id,
453 $this->fileoptions, $question->generalfeedback);
fe6ce234
DC
454 $question->generalfeedback = array();
455 $question->generalfeedback['text'] = $feedback;
eaeb6b51
TH
456 $question->generalfeedback['format'] = empty($question->generalfeedbackformat) ?
457 editors_get_preferred_format() : $question->generalfeedbackformat;
fe6ce234 458 $question->generalfeedback['itemid'] = $draftid;
295043c2 459
9152f6a5 460 // Remove unnecessary trailing 0s form grade fields.
cfd24d98 461 if (isset($question->defaultgrade)) {
462 $question->defaultgrade = 0 + $question->defaultgrade;
463 }
464 if (isset($question->penalty)) {
465 $question->penalty = 0 + $question->penalty;
466 }
9152f6a5 467
295043c2 468 // Set any options.
eaeb6b51
TH
469 $extraquestionfields = question_bank::get_qtype($question->qtype)->extra_question_fields();
470 if (is_array($extraquestionfields) && !empty($question->options)) {
471 array_shift($extraquestionfields);
472 foreach ($extraquestionfields as $field) {
b555ce76 473 if (isset($question->options->$field)) {
8e652f02 474 $question->$field = $question->options->$field;
475 }
295043c2 476 }
477 }
c9c989a0 478
fe6ce234
DC
479 // subclass adds data_preprocessing code here
480 $question = $this->data_preprocessing($question);
2b7da645 481
32db0d42 482 parent::set_data($question);
36703ed7 483 }
1d284fbd 484
fe6ce234 485 /**
fdd015b7
TH
486 * Perform an preprocessing needed on the data passed to {@link set_data()}
487 * before it is used to initialise the form.
488 * @param object $question the data being passed to the form.
489 * @return object $question the modified data.
fe6ce234 490 */
c7df5006 491 protected function data_preprocessing($question) {
7a719748
TH
492 return $question;
493 }
494
fdd015b7
TH
495 /**
496 * Perform the necessary preprocessing for the fields added by
497 * {@link add_per_answer_fields()}.
498 * @param object $question the data being passed to the form.
499 * @return object $question the modified data.
500 */
2a6c5c52 501 protected function data_preprocessing_answers($question, $withanswerfiles = false) {
7a719748
TH
502 if (empty($question->options->answers)) {
503 return $question;
504 }
505
506 $key = 0;
eaeb6b51 507 foreach ($question->options->answers as $answer) {
2a6c5c52 508 if ($withanswerfiles) {
509 // Prepare the feedback editor to display files in draft area
510 $draftitemid = file_get_submitted_draft_itemid('answer['.$key.']');
511 $question->answer[$key]['text'] = file_prepare_draft_area(
512 $draftitemid, // draftid
513 $this->context->id, // context
514 'question', // component
515 'answer', // filarea
516 !empty($answer->id) ? (int) $answer->id : null, // itemid
517 $this->fileoptions, // options
518 $answer->answer // text
519 );
520 $question->answer[$key]['itemid'] = $draftitemid;
521 $question->answer[$key]['format'] = $answer->answerformat;
522 } else {
523 $question->answer[$key] = $answer->answer;
524 }
525
7a719748
TH
526 $question->fraction[$key] = 0 + $answer->fraction;
527 $question->feedback[$key] = array();
528
529 // Evil hack alert. Formslib can store defaults in two ways for
eaeb6b51
TH
530 // repeat elements:
531 // ->_defaultValues['fraction[0]'] and
532 // ->_defaultValues['fraction'][0].
533 // The $repeatedoptions['fraction']['default'] = 0 bit above means
534 // that ->_defaultValues['fraction[0]'] has already been set, but we
535 // are using object notation here, so we will be setting
536 // ->_defaultValues['fraction'][0]. That does not work, so we have
537 // to unset ->_defaultValues['fraction[0]']
7a719748
TH
538 unset($this->_form->_defaultValues["fraction[$key]"]);
539
540 // Prepare the feedback editor to display files in draft area
541 $draftitemid = file_get_submitted_draft_itemid('feedback['.$key.']');
542 $question->feedback[$key]['text'] = file_prepare_draft_area(
543 $draftitemid, // draftid
544 $this->context->id, // context
545 'question', // component
546 'answerfeedback', // filarea
547 !empty($answer->id) ? (int) $answer->id : null, // itemid
548 $this->fileoptions, // options
549 $answer->feedback // text
550 );
551 $question->feedback[$key]['itemid'] = $draftitemid;
552 $question->feedback[$key]['format'] = $answer->feedbackformat;
553 $key++;
554 }
555 return $question;
556 }
557
fdd015b7
TH
558 /**
559 * Perform the necessary preprocessing for the fields added by
560 * {@link add_combined_feedback_fields()}.
561 * @param object $question the data being passed to the form.
562 * @return object $question the modified data.
563 */
eaeb6b51
TH
564 protected function data_preprocessing_combined_feedback($question,
565 $withshownumcorrect = false) {
c9c989a0
TH
566 if (empty($question->options)) {
567 return $question;
568 }
569
eaeb6b51
TH
570 $fields = array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback');
571 foreach ($fields as $feedbackname) {
c9c989a0 572 $draftid = file_get_submitted_draft_itemid($feedbackname);
8b9dfc2b
TH
573 $feedback = array();
574 $feedback['text'] = file_prepare_draft_area(
c9c989a0
TH
575 $draftid, // draftid
576 $this->context->id, // context
93cadb1e 577 'question', // component
c9c989a0
TH
578 $feedbackname, // filarea
579 !empty($question->id) ? (int) $question->id : null, // itemid
580 $this->fileoptions, // options
581 $question->options->$feedbackname // text
582 );
583 $feedbackformat = $feedbackname . 'format';
8b9dfc2b
TH
584 $feedback['format'] = $question->options->$feedbackformat;
585 $feedback['itemid'] = $draftid;
586
587 $question->$feedbackname = $feedback;
c9c989a0
TH
588 }
589
590 if ($withshownumcorrect) {
591 $question->shownumcorrect = $question->options->shownumcorrect;
592 }
593
594 return $question;
595 }
596
fdd015b7
TH
597 /**
598 * Perform the necessary preprocessing for the hint fields.
599 * @param object $question the data being passed to the form.
600 * @return object $question the modified data.
601 */
eaeb6b51
TH
602 protected function data_preprocessing_hints($question, $withclearwrong = false,
603 $withshownumpartscorrect = false) {
7a719748
TH
604 if (empty($question->hints)) {
605 return $question;
606 }
607
608 $key = 0;
eaeb6b51 609 foreach ($question->hints as $hint) {
7a719748
TH
610 $question->hint[$key] = array();
611
612 // prepare feedback editor to display files in draft area
613 $draftitemid = file_get_submitted_draft_itemid('hint['.$key.']');
614 $question->hint[$key]['text'] = file_prepare_draft_area(
615 $draftitemid, // draftid
616 $this->context->id, // context
617 'question', // component
618 'hint', // filarea
619 !empty($hint->id) ? (int) $hint->id : null, // itemid
620 $this->fileoptions, // options
621 $hint->hint // text
622 );
623 $question->hint[$key]['itemid'] = $draftitemid;
624 $question->hint[$key]['format'] = $hint->hintformat;
625 $key++;
7a719748 626
8b9dfc2b
TH
627 if ($withclearwrong) {
628 $question->hintclearwrong[] = $hint->clearwrong;
629 }
630 if ($withshownumpartscorrect) {
631 $question->hintshownumcorrect[] = $hint->shownumcorrect;
632 }
633 }
7a719748 634
fe6ce234
DC
635 return $question;
636 }
637
2b7da645
TH
638 public function validation($fromform, $files) {
639 $errors = parent::validation($fromform, $files);
640 if (empty($fromform->makecopy) && isset($this->question->id)
eaeb6b51
TH
641 && ($this->question->formoptions->canedit ||
642 $this->question->formoptions->cansaveasnew)
2b7da645
TH
643 && empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove) {
644 $errors['currentgrp'] = get_string('nopermissionmove', 'question');
645 }
646 return $errors;
647 }
648
36703ed7 649 /**
650 * Override this in the subclass to question type name.
eaeb6b51
TH
651 * @return the question type name, should be the same as the name() method
652 * in the question type class.
36703ed7 653 */
2b7da645 654 public abstract function qtype();
36703ed7 655}