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