1 <?php 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 17 /** 18 * Defines the editing form for the calculated question type. 19 * 20 * @package qtype 21 * @subpackage calculated 22 * @copyright 2007 Jamie Pratt me@jamiep.org 23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once($CFG->dirroot . '/question/type/numerical/edit_numerical_form.php'); 30 31 32 /** 33 * Calculated question type editing form definition. 34 * 35 * @copyright 2007 Jamie Pratt me@jamiep.org 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class qtype_calculated_edit_form extends qtype_numerical_edit_form { 39 /** 40 * Handle to the question type for this question. 41 * 42 * @var qtype_calculated 43 */ 44 public $qtypeobj; 45 public $questiondisplay; 46 public $activecategory; 47 public $categorychanged = false; 48 public $initialname = ''; 49 public $reload = false; 50 51 public function __construct($submiturl, $question, $category, $contexts, 52 $formeditable = true) { 53 global $CFG, $DB; 54 $this->question = $question; 55 $this->reload = optional_param('reload', false, PARAM_BOOL); 56 57 if (!$this->reload) { // Use database data as this is first pass. 58 if (isset($this->question->id)) { 59 // Remove prefix #{..}# if exists. 60 $this->initialname = $question->name; 61 $question->name = question_bank::get_qtype($this->qtype()) 62 ->clean_technical_prefix_from_question_name($question->name); 63 } 64 } 65 parent::__construct($submiturl, $question, $category, $contexts, $formeditable); 66 } 67 68 public function get_per_answer_fields($mform, $label, $gradeoptions, 69 &$repeatedoptions, &$answersoption) { 70 $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, 71 $repeatedoptions, $answersoption); 72 73 // Reorganise answer options group. 0 is the answer. 1 is tolerance. 2 is Grade. 74 $answeroptions = $repeated[0]->getElements(); 75 // Tolerance field will be part of its own group. 76 $tolerance = $answeroptions[1]; 77 78 // Update Answer options group to contain only answer and grade fields. 79 $answeroptions[0]->setSize(55); 80 $answeroptions = array($answeroptions[0], $answeroptions[2]); 81 $repeated[0]->setElements($answeroptions); 82 83 // Update answer field and group label. 84 $repeated[0]->setLabel(get_string('answerformula', 'qtype_calculated', '{no}') . ' ='); 85 $answeroptions[0]->setLabel(get_string('answerformula', 'qtype_calculated', '{no}') . ' ='); 86 87 // Get feedback field to re append later. 88 $feedback = array_pop($repeated); 89 90 // Create tolerance group. 91 $answertolerance = array(); 92 $tolerance->setLabel(get_string('tolerance', 'qtype_calculated') . '='); 93 $answertolerance[] = $tolerance; 94 $answertolerance[] = $mform->createElement('select', 'tolerancetype', 95 get_string('tolerancetype', 'qtype_calculated'), $this->qtypeobj->tolerance_types()); 96 $repeated[] = $mform->createElement('group', 'answertolerance', 97 get_string('tolerance', 'qtype_calculated'), $answertolerance, null, false); 98 $repeatedoptions['tolerance']['default'] = 0.01; 99 100 // Create display group. 101 $answerdisplay = array(); 102 $answerdisplay[] = $mform->createElement('select', 'correctanswerlength', 103 get_string('answerdisplay', 'qtype_calculated'), range(0, 9)); 104 $repeatedoptions['correctanswerlength']['default'] = 2; 105 106 $answerlengthformats = array( 107 '1' => get_string('decimalformat', 'qtype_numerical'), 108 '2' => get_string('significantfiguresformat', 'qtype_calculated') 109 ); 110 $answerdisplay[] = $mform->createElement('select', 'correctanswerformat', 111 get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats); 112 $repeated[] = $mform->createElement('group', 'answerdisplay', 113 get_string('answerdisplay', 'qtype_calculated'), $answerdisplay, null, false); 114 115 // Add feedback. 116 $repeated[] = $feedback; 117 118 return $repeated; 119 } 120 121 /** 122 * Add question-type specific form fields. 123 * 124 * @param MoodleQuickForm $mform the form being built. 125 */ 126 protected function definition_inner($mform) { 127 $this->qtypeobj = question_bank::get_qtype($this->qtype()); 128 $label = get_string('sharedwildcards', 'qtype_calculated'); 129 $mform->addElement('hidden', 'initialcategory', 1); 130 $mform->addElement('hidden', 'reload', 1); 131 $mform->setType('initialcategory', PARAM_INT); 132 $mform->setType('reload', PARAM_BOOL); 133 $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question); 134 $mform->insertElementBefore( 135 $mform->createElement('static', 'listcategory', $label, $html2), 'name'); 136 if (isset($this->question->id)) { 137 $mform->insertElementBefore($mform->createElement('static', 'initialname', 138 get_string('questionstoredname', 'qtype_calculated'), 139 format_string($this->initialname)), 'name'); 140 }; 141 $addfieldsname = 'updatecategory'; 142 $addstring = get_string('updatecategory', 'qtype_calculated'); 143 $mform->registerNoSubmitButton($addfieldsname); 144 145 $mform->insertElementBefore( 146 $mform->createElement('submit', $addfieldsname, $addstring), 'listcategory'); 147 $mform->registerNoSubmitButton('createoptionbutton'); 148 149 // Editing as regular question. 150 $mform->setType('single', PARAM_INT); 151 152 $mform->addElement('hidden', 'shuffleanswers', '1'); 153 $mform->setType('shuffleanswers', PARAM_INT); 154 $mform->addElement('hidden', 'answernumbering', 'abc'); 155 $mform->setType('answernumbering', PARAM_SAFEDIR); 156 157 $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), 158 question_bank::fraction_options(), 1, 1); 159 160 $repeated = array(); 161 162 $this->add_unit_options($mform, $this); 163 $this->add_unit_fields($mform, $this); 164 $this->add_interactive_settings(); 165 166 // Hidden elements. 167 $mform->addElement('hidden', 'synchronize', ''); 168 $mform->setType('synchronize', PARAM_INT); 169 $mform->addElement('hidden', 'wizard', 'datasetdefinitions'); 170 $mform->setType('wizard', PARAM_ALPHA); 171 } 172 173 protected function can_preview() { 174 return false; // Generally not possible for calculated questions on this page. 175 } 176 177 public function data_preprocessing($question) { 178 $question = parent::data_preprocessing($question); 179 $question = $this->data_preprocessing_answers($question); 180 $question = $this->data_preprocessing_hints($question); 181 $question = $this->data_preprocessing_units($question); 182 $question = $this->data_preprocessing_unit_options($question); 183 184 if (isset($question->options->synchronize)) { 185 $question->synchronize = $question->options->synchronize; 186 } 187 188 return $question; 189 } 190 191 protected function data_preprocessing_answers($question, $withanswerfiles = false) { 192 $question = parent::data_preprocessing_answers($question, $withanswerfiles); 193 if (empty($question->options->answers)) { 194 return $question; 195 } 196 197 $key = 0; 198 foreach ($question->options->answers as $answer) { 199 // See comment in the parent method about this hack. 200 unset($this->_form->_defaultValues["tolerancetype[{$key}]"]); 201 unset($this->_form->_defaultValues["correctanswerlength[{$key}]"]); 202 unset($this->_form->_defaultValues["correctanswerformat[{$key}]"]); 203 204 $question->tolerancetype[$key] = $answer->tolerancetype; 205 $question->correctanswerlength[$key] = $answer->correctanswerlength; 206 $question->correctanswerformat[$key] = $answer->correctanswerformat; 207 $key++; 208 } 209 210 return $question; 211 } 212 213 public function qtype() { 214 return 'calculated'; 215 } 216 217 /** 218 * Validate the equations in the some question content. 219 * @param array $errors where errors are being accumulated. 220 * @param string $field the field being validated. 221 * @param string $text the content of that field. 222 * @return array the updated $errors array. 223 */ 224 protected function validate_text($errors, $field, $text) { 225 $problems = qtype_calculated_find_formula_errors_in_text($text); 226 if ($problems) { 227 $errors[$field] = $problems; 228 } 229 return $errors; 230 } 231 232 public function validation($data, $files) { 233 $errors = parent::validation($data, $files); 234 235 // Verifying for errors in {=...} in question text. 236 $errors = $this->validate_text($errors, 'questiontext', $data['questiontext']['text']); 237 $errors = $this->validate_text($errors, 'generalfeedback', $data['generalfeedback']['text']); 238 239 // Check that the answers use datasets. 240 $answers = $data['answer']; 241 $mandatorydatasets = array(); 242 foreach ($answers as $key => $answer) { 243 $problems = qtype_calculated_find_formula_errors($answer); 244 if ($problems) { 245 $errors['answeroptions['.$key.']'] = $problems; 246 } 247 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); 248 $errors = $this->validate_text($errors, 'feedback[' . $key . ']', 249 $data['feedback'][$key]['text']); 250 } 251 if (empty($mandatorydatasets)) { 252 foreach ($answers as $key => $answer) { 253 $errors['answeroptions['.$key.']'] = 254 get_string('atleastonewildcard', 'qtype_calculated'); 255 } 256 } 257 258 // Validate the answer format. 259 foreach ($answers as $key => $answer) { 260 $trimmedanswer = trim($answer); 261 if (trim($answer)) { 262 if ($data['correctanswerformat'][$key] == 2 && 263 $data['correctanswerlength'][$key] == '0') { 264 $errors['answerdisplay['.$key.']'] = 265 get_string('zerosignificantfiguresnotallowed', 'qtype_calculated'); 266 } 267 } 268 } 269 270 return $errors; 271 } 272 273 protected function is_valid_answer($answer, $data) { 274 return !qtype_calculated_find_formula_errors($answer); 275 } 276 277 protected function valid_answer_message($answer) { 278 if (!$answer) { 279 return get_string('mustenteraformulaorstar', 'qtype_numerical'); 280 } else { 281 return qtype_calculated_find_formula_errors($answer); 282 } 283 } 284 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body