Merge branch 'MDL-70065_310' of https://github.com/timhunt/moodle into MOODLE_310_STABLE
[moodle.git] / question / type / calculatedsimple / edit_calculatedsimple_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
83a15d02 17/**
18 * Defines the editing form for the calculated simplequestion type.
19 *
b04a4319
TH
20 * @package qtype
21 * @subpackage calculatedsimple
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
a17b297d
TH
27defined('MOODLE_INTERNAL') || die();
28
efe3e87b
TH
29require_once($CFG->dirroot . '/question/type/calculated/edit_calculated_form.php');
30
a17b297d 31
b04a4319
TH
32/**
33 * Editing form for the calculated simplequestion type.
34 *
35 * @copyright 2007 Jamie Pratt me@jamiep.org
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
83a15d02 37 */
efe3e87b 38class qtype_calculatedsimple_edit_form extends qtype_calculated_edit_form {
83a15d02 39 /**
40 * Handle to the question type for this question.
41 *
42 * @var question_calculatedsimple_qtype
43 */
fe6ce234 44 public $qtypeobj;
0735b509 45
8200ccd6 46 public $wildcarddisplay;
0735b509 47
8200ccd6 48 public $questiondisplay;
83a15d02 49
50 public $datasetdefs;
51
8200ccd6 52 public $reload = false;
aeb15530 53
83a15d02 54 public $maxnumber = -1;
55
56 public $regenerate = true;
57
58 public $noofitems;
aeb15530 59
8200ccd6 60 public $outsidelimit = false;
aeb15530
PS
61
62 public $commentanswer = array();
63
83a15d02 64 public $answer = array();
65
66 public $nonemptyanswer = array();
aeb15530 67
a31697ba 68 public $numbererrors = array();
69
aeb15530
PS
70 public $formdata = array();
71
8200ccd6 72 public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
83a15d02 73 $this->regenerate = true;
74 $this->question = $question;
b003b818 75
efe3e87b 76 $this->qtypeobj = question_bank::get_qtype($this->question->qtype);
3d9645ae 77 // Get the dataset definitions for this question.
78 // Coming here everytime even when using a NoSubmitButton.
79 // This will only set the values to the actual question database content
80 // which is not what we want, so this should be removed from here.
81 // Get priority to paramdatasets.
aeb15530 82
7d087744 83 $this->reload = optional_param('reload', false, PARAM_BOOL);
3d9645ae 84 if (!$this->reload) { // Use database data as this is first pass
85 // Question->id == 0 so no stored datasets.
fe6ce234
DC
86 if (!empty($question->id)) {
87
8200ccd6
TH
88 $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
89 $question->id, array());
aeb15530 90
8200ccd6 91 if (!empty($this->datasetdefs)) {
1d1f5784 92 foreach ($this->datasetdefs as $defid => $datasetdef) {
3d9645ae 93 // First get the items in case their number does not correspond to itemcount.
1d1f5784 94 if (isset($datasetdef->id)) {
8200ccd6
TH
95 $this->datasetdefs[$defid]->items =
96 $this->qtypeobj->get_database_dataset_items($datasetdef->id);
97 if ($this->datasetdefs[$defid]->items != '') {
0735b509 98 $datasetdef->itemcount = count($this->datasetdefs[$defid]->items);
99 } else {
8200ccd6 100 $datasetdef->itemcount = 0;
0735b509 101 }
1d1f5784 102 }
3d9645ae 103 // Get maxnumber.
83a15d02 104 if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
105 $this->maxnumber = $datasetdef->itemcount;
106 }
107 }
83a15d02 108 }
1d1f5784 109
8200ccd6
TH
110 $i = 0;
111 foreach ($this->question->options->answers as $answer) {
112 $this->answer[$i] = $answer;
83a15d02 113 $i++;
aeb15530 114 }
8200ccd6 115 $this->nonemptyanswer = $this->answer;
aeb15530 116 }
83a15d02 117 $datasettoremove = false;
8200ccd6
TH
118 $newdatasetvalues = false;
119 $newdataset = false;
120 } else {
3d9645ae 121 // Handle reload to get values from the form-elements
8200ccd6
TH
122 // answers, datasetdefs and data_items. In any case the validation
123 // step will warn the user of any error in settings the values.
aeb15530 124 // Verification for the specific dataset values as the other parameters
3d9645ae 125 // units, feeedback etc are handled elsewhere.
126 // Handle request buttons :
127 // 'analyzequestion' (Identify the wild cards {x..} present in answers).
128 // 'addbutton' (create new set of datatitems).
129 // 'updatedatasets' is handled automatically on each reload.
aeb15530 130 // The analyzequestion is done every time on reload
83a15d02 131 // to detect any new wild cards so that the current display reflects
3d9645ae 132 // the mandatory (i.e. in answers) datasets.
133 // To implement : don't do any changes if the question is used in a quiz.
aeb15530 134 // If new datadef, new properties should erase items.
3d9645ae 135 // most of the data.
06f80c6c 136 $datasettoremove = false;
8200ccd6
TH
137 $newdatasetvalues = false;
138 $newdataset = false;
0735b509 139 $dummyform = new stdClass();
140 $mandatorydatasets = array();
3d9645ae 141 // Should not test on adding a new answer.
142 // Should test if there are already olddatasets or if the 'analyzequestion'.
143 // submit button has been clicked.
7d087744
TH
144 if (optional_param_array('datasetdef', false, PARAM_BOOL) ||
145 optional_param('analyzequestion', false, PARAM_BOOL)) {
aeb15530 146
7d087744 147 if ($dummyform->answer = optional_param_array('answer', '', PARAM_NOTAGS)) {
3d9645ae 148 // There is always at least one answer...
61cca0b7 149 $fraction = optional_param_array('fraction', '', PARAM_FLOAT);
47538a6b 150 $tolerance = optional_param_array('tolerance', '', PARAM_LOCALISEDFLOAT);
61cca0b7 151 $tolerancetype = optional_param_array('tolerancetype', '', PARAM_FLOAT);
7d087744
TH
152 $correctanswerlength = optional_param_array('correctanswerlength', '', PARAM_INT);
153 $correctanswerformat = optional_param_array('correctanswerformat', '', PARAM_INT);
aeb15530 154
8200ccd6 155 foreach ($dummyform->answer as $key => $answer) {
3d9645ae 156 if (trim($answer) != '') { // Just look for non-empty.
8200ccd6 157 $this->answer[$key] = new stdClass();
06f80c6c 158 $this->answer[$key]->answer = $answer;
2a2c5eff 159 $this->answer[$key]->fraction = $fraction[$key];
06f80c6c 160 $this->answer[$key]->tolerance = $tolerance[$key];
161 $this->answer[$key]->tolerancetype = $tolerancetype[$key];
162 $this->answer[$key]->correctanswerlength = $correctanswerlength[$key];
163 $this->answer[$key]->correctanswerformat = $correctanswerformat[$key];
164 $this->nonemptyanswer[]= $this->answer[$key];
8200ccd6 165 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
06f80c6c 166 }
0735b509 167 }
83a15d02 168 }
06f80c6c 169 $this->datasetdefs = array();
3d9645ae 170 // Rebuild datasetdefs from old values.
7d087744 171 if ($olddef = optional_param_array('datasetdef', '', PARAM_RAW)) {
47538a6b 172 $calcmin = optional_param_array('calcmin', '', PARAM_LOCALISEDFLOAT);
7d087744 173 $calclength = optional_param_array('calclength', '', PARAM_INT);
47538a6b 174 $calcmax = optional_param_array('calcmax', '', PARAM_LOCALISEDFLOAT);
7d087744 175 $oldoptions = optional_param_array('defoptions', '', PARAM_RAW);
8200ccd6
TH
176 $newdatasetvalues = false;
177 $sizeofolddef = count($olddef);
178 for ($key = 1; $key <= $sizeofolddef; $key++) {
179 $def = $olddef[$key];
180 $this->datasetdefs[$def]= new stdClass();
06f80c6c 181 $this->datasetdefs[$def]->type = 1;
182 $this->datasetdefs[$def]->category = 0;
8200ccd6
TH
183 $this->datasetdefs[$def]->options = $oldoptions[$key];
184 $this->datasetdefs[$def]->calcmin = $calcmin[$key];
185 $this->datasetdefs[$def]->calcmax = $calcmax[$key];
186 $this->datasetdefs[$def]->calclength = $calclength[$key];
3d9645ae 187 // Then compare with new values.
8200ccd6
TH
188 if (preg_match('~^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$~',
189 $this->datasetdefs[$def]->options, $regs)) {
190 if ($this->datasetdefs[$def]->calcmin != $regs[2]||
191 $this->datasetdefs[$def]->calcmax != $regs[3] ||
192 $this->datasetdefs[$def]->calclength != $regs[4]) {
193 $newdatasetvalues = true;
aeb15530 194 }
06f80c6c 195 }
8200ccd6
TH
196 $this->datasetdefs[$def]->options = "uniform:" .
197 $this->datasetdefs[$def]->calcmin . ":" .
198 $this->datasetdefs[$def]->calcmax . ":" .
199 $this->datasetdefs[$def]->calclength;
06f80c6c 200 }
8200ccd6 201 }
3d9645ae 202 // Detect new datasets.
8200ccd6
TH
203 $newdataset = false;
204 foreach ($mandatorydatasets as $datasetname) {
f4fe3968
TH
205 if (!isset($this->datasetdefs["1-0-{$datasetname}"])) {
206 $key = "1-0-{$datasetname}";
8200ccd6
TH
207 $this->datasetdefs[$key] = new stdClass();
208 $this->datasetdefs[$key]->type = 1;
209 $this->datasetdefs[$key]->category = 0;
210 $this->datasetdefs[$key]->name = $datasetname;
211 $this->datasetdefs[$key]->options = "uniform:1.0:10.0:1";
212 $newdataset = true;
213 } else {
f4fe3968 214 $this->datasetdefs["1-0-{$datasetname}"]->name = $datasetname;
8200ccd6 215 }
83a15d02 216 }
3d9645ae 217 // Remove obsolete datasets.
8200ccd6
TH
218 $datasettoremove = false;
219 foreach ($this->datasetdefs as $defkey => $datasetdef) {
220 if (!isset($datasetdef->name)) {
221 $datasettoremove = true;
222 unset($this->datasetdefs[$defkey]);
223 }
83a15d02 224 }
06f80c6c 225 }
3d9645ae 226 } // Handle reload.
227 // Create items if $newdataset and noofitems > 0 and !$newdatasetvalues.
228 // Eliminate any items if $newdatasetvalues.
229 // Eliminate any items if $datasettoremove, $newdataset, $newdatasetvalues.
8200ccd6
TH
230 if ($datasettoremove ||$newdataset ||$newdatasetvalues) {
231 foreach ($this->datasetdefs as $defkey => $datasetdef) {
83a15d02 232 $datasetdef->itemcount = 0;
233 unset($datasetdef->items);
234 }
235 }
8200ccd6 236 $maxnumber = -1;
7d087744 237 if (optional_param('addbutton', false, PARAM_BOOL)) {
3d9645ae 238 $maxnumber = optional_param('selectadd', '', PARAM_INT); // FIXME: sloppy coding.
83a15d02 239 foreach ($this->datasetdefs as $defid => $datasetdef) {
240 $datasetdef->itemcount = $maxnumber;
241 unset($datasetdef->items);
8200ccd6 242 for ($numberadded = 1; $numberadded <= $maxnumber; $numberadded++) {
0ff4bd08 243 $datasetitem = new stdClass();
83a15d02 244 $datasetitem->itemnumber = $numberadded;
245 $datasetitem->id = 0;
8200ccd6
TH
246 $datasetitem->value = $this->qtypeobj->generate_dataset_item(
247 $datasetdef->options);
248 $this->datasetdefs[$defid]->items[$numberadded] = $datasetitem;
249 }
250 }
251 $this->maxnumber = $maxnumber;
252 } else {
3d9645ae 253 // Handle reload dataset items.
7d087744 254 if (optional_param_array('definition', '', PARAM_NOTAGS) &&
8200ccd6 255 !($datasettoremove ||$newdataset ||$newdatasetvalues)) {
83a15d02 256 $i = 1;
7d087744 257 $fromformdefinition = optional_param_array('definition', '', PARAM_NOTAGS);
47538a6b 258 $fromformnumber = optional_param_array('number', '', PARAM_LOCALISEDFLOAT);
7d087744 259 $fromformitemid = optional_param_array('itemid', '', PARAM_INT);
83a15d02 260 ksort($fromformdefinition);
aeb15530 261
8200ccd6 262 foreach ($fromformdefinition as $key => $defid) {
83a15d02 263 $addeditem = new stdClass();
8200ccd6 264 $addeditem->id = $fromformitemid[$i];
83a15d02 265 $addeditem->value = $fromformnumber[$i];
266 $addeditem->itemnumber = ceil($i / count($this->datasetdefs));
8200ccd6
TH
267 $this->datasetdefs[$defid]->items[$addeditem->itemnumber] = $addeditem;
268 $this->datasetdefs[$defid]->itemcount = $i;
83a15d02 269 $i++;
270 }
271 }
8200ccd6 272 if (isset($addeditem->itemnumber) && $this->maxnumber < $addeditem->itemnumber) {
83a15d02 273 $this->maxnumber = $addeditem->itemnumber;
8200ccd6 274 if (!empty($this->datasetdefs)) {
83a15d02 275 foreach ($this->datasetdefs as $datasetdef) {
8200ccd6 276 $datasetdef->itemcount = $this->maxnumber;
83a15d02 277 }
278 }
279 }
280 }
281
8200ccd6 282 parent::__construct($submiturl, $question, $category, $contexts, $formeditable);
83a15d02 283 }
284
83a15d02 285 /**
286 * Add question-type specific form fields.
287 *
288 * @param MoodleQuickForm $mform the form being built.
289 */
c7df5006 290 protected function definition_inner($mform) {
83a15d02 291 $strquestionlabel = $this->qtypeobj->comment_header($this->nonemptyanswer);
2fa83505 292 $label = get_string("sharedwildcards", "qtype_calculated");
b003b818 293 $mform->addElement('hidden', 'synchronize', 0);
83a15d02 294 $mform->addElement('hidden', 'initialcategory', 1);
ce5bb3a9 295 $mform->setType('synchronize', PARAM_BOOL);
d18e0fe6 296 $mform->setType('initialcategory', PARAM_INT);
83a15d02 297 $mform->addElement('hidden', 'reload', 1);
d18e0fe6 298 $mform->setType('reload', PARAM_INT);
8200ccd6
TH
299 $addfieldsname = 'updatequestion value';
300 $addstring = get_string("updatecategory", "qtype_calculated");
a31697ba 301 $mform->registerNoSubmitButton($addfieldsname);
83a15d02 302
83a15d02 303 $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
92111e8d 304 question_bank::fraction_options(), 1, 1);
83a15d02 305
efe3e87b
TH
306 $this->add_unit_options($mform, $this);
307 $this->add_unit_fields($mform, $this);
b130270d 308 $this->add_interactive_settings();
aeb15530 309
8200ccd6
TH
310 $label = "<div class='mdl-align'></div><div class='mdl-align'>" .
311 get_string('wildcardrole', 'qtype_calculatedsimple') . "</div>";
83a15d02 312 $mform->addElement('html', "<div class='mdl-align'>&nbsp;</div>");
3d9645ae 313 // Explaining the role of datasets so other strings can be shortened.
8200ccd6 314 $mform->addElement('html', $label);
83a15d02 315
8200ccd6
TH
316 $mform->addElement('submit', 'analyzequestion',
317 get_string('findwildcards', 'qtype_calculatedsimple'));
83a15d02 318 $mform->registerNoSubmitButton('analyzequestion');
319 $mform->closeHeaderBefore('analyzequestion');
72553162 320 $this->wizarddisplay = optional_param('analyzequestion', false, PARAM_BOOL);
8200ccd6 321 if ($this->maxnumber != -1) {
83a15d02 322 $this->noofitems = $this->maxnumber;
323 } else {
324 $this->noofitems = 0;
325 }
3d9645ae 326 if (!empty($this->datasetdefs)) {// So there are some datadefs.
327 // We put them on the page.
0735b509 328 $key = 0;
8200ccd6
TH
329 $mform->addElement('header', 'additemhdr',
330 get_string('wildcardparam', 'qtype_calculatedsimple'));
0735b509 331 $idx = 1;
3d9645ae 332 if (!empty($this->datasetdefs)) {// Unnecessary test.
0735b509 333 $j = (($this->noofitems) * count($this->datasetdefs))+1;//
8200ccd6 334 foreach ($this->datasetdefs as $defkey => $datasetdef) {
f4fe3968 335 $mform->addElement('static', "na[{$j}]",
8200ccd6 336 get_string('param', 'qtype_calculated', $datasetdef->name));
0735b509 337 $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
f4fe3968
TH
338 $mform->addElement('hidden', "datasetdef[{$idx}]");
339 $mform->setType("datasetdef[{$idx}]", PARAM_RAW);
340 $mform->addElement('hidden', "defoptions[{$idx}]");
341 $mform->setType("defoptions[{$idx}]", PARAM_RAW);
0735b509 342 $idx++;
f4fe3968 343 $mform->addElement('static', "divider[{$j}]", '', '<hr />');
0735b509 344 $j++;
345 }
346 }
3d9645ae 347 // This should be done before the elements are created and stored as $this->formdata.
348 // Fill out all data sets and also the fields for the next item to add.
fe6ce234
DC
349 /*Here we do already the values error analysis so that
350 * we could force all wild cards values display if there is an error in values.
351 * as using a , in a number */
352 $this->numbererrors = array();
8200ccd6 353 if (!empty($this->datasetdefs)) {
fe6ce234 354 $j = $this->noofitems * count($this->datasetdefs);
8200ccd6 355 for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
fe6ce234 356 $data = array();
47538a6b 357 $numbererrors = '';
0ff4bd08 358 $comment = new stdClass();
fe6ce234 359 $comment->stranswers = array();
8200ccd6 360 $comment->outsidelimit = false;
fe6ce234
DC
361 $comment->answers = array();
362
8200ccd6
TH
363 foreach ($this->datasetdefs as $defid => $datasetdef) {
364 if (isset($datasetdef->items[$itemnumber])) {
f4fe3968
TH
365 $this->formdata["definition[{$j}]"] = $defid;
366 $this->formdata["itemid[{$j}]"] =
8200ccd6 367 $datasetdef->items[$itemnumber]->id;
fe6ce234 368 $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
f4fe3968 369 $this->formdata["number[{$j}]"] = $number =
8200ccd6
TH
370 $datasetdef->items[$itemnumber]->value;
371 if (! is_numeric($number)) {
0ff4bd08 372 $a = new stdClass();
8200ccd6
TH
373 $a->name = '{'.$datasetdef->name.'}';
374 $a->value = $datasetdef->items[$itemnumber]->value;
375 if (stristr($number, ',')) {
f4fe3968 376 $this->numbererrors["number[{$j}]"] =
8200ccd6 377 get_string('nocommaallowed', 'qtype_calculated');
fe6ce234 378 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
aeb15530 379
8200ccd6 380 } else {
f4fe3968 381 $this->numbererrors["number[{$j}]"] =
8200ccd6 382 get_string('notvalidnumber', 'qtype_calculated', $a);
0735b509 383 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
fe6ce234 384 }
3d9645ae 385 } else if (stristr($number, 'x')) { // Hexa will pass the test.
0ff4bd08 386 $a = new stdClass();
8200ccd6
TH
387 $a->name = '{'.$datasetdef->name.'}';
388 $a->value = $datasetdef->items[$itemnumber]->value;
389 $this->numbererrors['number['.$j.']'] =
390 get_string('hexanotallowed', 'qtype_calculated', $a);
fe6ce234 391 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
8200ccd6 392 } else if (is_nan($number)) {
0ff4bd08 393 $a = new stdClass();
8200ccd6
TH
394 $a->name = '{'.$datasetdef->name.'}';
395 $a->value = $datasetdef->items[$itemnumber]->value;
f4fe3968 396 $this->numbererrors["number[{$j}]"] =
8200ccd6 397 get_string('notvalidnumber', 'qtype_calculated', $a);
fe6ce234 398 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
0735b509 399 }
0735b509 400 }
fe6ce234
DC
401 $j--;
402 }
8200ccd6 403 if ($this->noofitems != 0) {
fe6ce234
DC
404 if (empty($numbererrors)) {
405 if (!isset($this->question->id)) {
8200ccd6 406 $this->question->id = 0;
fe6ce234 407 }
8200ccd6
TH
408 $this->question->questiontext = !empty($this->question->questiontext) ?
409 $this->question->questiontext : '';
410 $comment = $this->qtypeobj->comment_on_datasetitems(
411 $this->qtypeobj, $this->question->id,
412 $this->question->questiontext, $this->nonemptyanswer,
413 $data, $itemnumber);
fe6ce234 414 if ($comment->outsidelimit) {
8200ccd6 415 $this->outsidelimit = $comment->outsidelimit;
0735b509 416 }
8200ccd6 417 $totalcomment = '';
fe6ce234
DC
418
419 foreach ($this->nonemptyanswer as $key => $answer) {
420 $totalcomment .= $comment->stranswers[$key].'<br/>';
421 }
422
8200ccd6 423 $this->formdata['answercomment['.$itemnumber.']'] = $totalcomment;
fe6ce234 424 }
0735b509 425 }
fe6ce234
DC
426 }
427 $this->formdata['selectdelete'] = '1';
428 $this->formdata['selectadd'] = '1';
429 $j = $this->noofitems * count($this->datasetdefs)+1;
3d9645ae 430 $data = array(); // Data for comment_on_datasetitems later.
8200ccd6
TH
431 $idx = 1;
432 foreach ($this->datasetdefs as $defid => $datasetdef) {
f4fe3968 433 $this->formdata["datasetdef[{$idx}]"] = $defid;
0735b509 434 $idx++;
435 }
8200ccd6
TH
436 $this->formdata = $this->qtypeobj->custom_generator_set_data(
437 $this->datasetdefs, $this->formdata);
fe6ce234
DC
438 }
439
fe6ce234 440 $addoptions = Array();
8200ccd6
TH
441 $addoptions['1'] = '1';
442 for ($i = 10; $i <= 100; $i += 10) {
f4fe3968 443 $addoptions["{$i}"] = "{$i}";
fe6ce234
DC
444 }
445 $showoptions = Array();
8200ccd6
TH
446 $showoptions['1'] = '1';
447 $showoptions['2'] = '2';
448 $showoptions['5'] = '5';
449 for ($i = 10; $i <= 100; $i += 10) {
f4fe3968 450 $showoptions["{$i}"] = "{$i}";
fe6ce234
DC
451 }
452 $mform->closeHeaderBefore('additemhdr');
453 $addgrp = array();
8200ccd6
TH
454 $addgrp[] = $mform->createElement('submit', 'addbutton',
455 get_string('generatenewitemsset', 'qtype_calculatedsimple'));
456 $addgrp[] = $mform->createElement('select', "selectadd", '', $addoptions);
457 $addgrp[] = $mform->createElement('static', "stat", '',
458 get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
fe6ce234
DC
459 $mform->addGroup($addgrp, 'addgrp', '', ' ', false);
460 $mform->registerNoSubmitButton('addbutton');
461 $mform->closeHeaderBefore('addgrp');
462 $addgrp1 = array();
8200ccd6
TH
463 $addgrp1[] = $mform->createElement('submit', 'showbutton',
464 get_string('showitems', 'qtype_calculatedsimple'));
465 $addgrp1[] = $mform->createElement('select', "selectshow", '', $showoptions);
466 $addgrp1[] = $mform->createElement('static', "stat", '',
467 get_string('setwildcardvalues', 'qtype_calculatedsimple'));
fe6ce234
DC
468 $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
469 $mform->registerNoSubmitButton('showbutton');
470 $mform->closeHeaderBefore('addgrp1');
471 $mform->addElement('static', "divideradd", '', '');
472 if ($this->noofitems == 0) {
8200ccd6
TH
473 $mform->addElement('static', 'warningnoitems', '', '<span class="error">' .
474 get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple') .
475 '</span>');
fe6ce234 476 $mform->closeHeaderBefore('warningnoitems');
8200ccd6
TH
477 } else {
478 $mform->addElement('header', 'additemhdr1',
479 get_string('wildcardvalues', 'qtype_calculatedsimple'));
fe6ce234 480 $mform->closeHeaderBefore('additemhdr1');
8200ccd6
TH
481 if (!empty($this->numbererrors) || $this->outsidelimit) {
482 $mform->addElement('static', "alert", '', '<span class="error">' .
483 get_string('useadvance', 'qtype_calculatedsimple').'</span>');
0735b509 484 }
485
8200ccd6
TH
486 $mform->addElement('submit', 'updatedatasets',
487 get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
fe6ce234 488 $mform->registerNoSubmitButton('updatedatasets');
8200ccd6 489 $mform->setAdvanced("updatedatasets", true);
aeb15530 490
3d9645ae 491 // ...--------------------------------------------------------------.
fe6ce234 492 $j = $this->noofitems * count($this->datasetdefs);
7d087744 493 $k = optional_param('selectshow', 1, PARAM_INT);
aeb15530 494
8200ccd6
TH
495 for ($i = $this->noofitems; $i >= 1; $i--) {
496 foreach ($this->datasetdefs as $defkey => $datasetdef) {
497 if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
47538a6b 498 $mform->addElement('float', "number[{$j}]", get_string(
8200ccd6 499 'wildcard', 'qtype_calculatedsimple', $datasetdef->name));
f4fe3968 500 $mform->setAdvanced("number[{$j}]", true);
8200ccd6 501 if (!empty($this->numbererrors['number['.$j.']'])) {
f4fe3968 502 $mform->addElement('static', "numbercomment[{$j}]", '',
8200ccd6
TH
503 '<span class="error">' .
504 $this->numbererrors['number['.$j.']'] . '</span>');
f4fe3968 505 $mform->setAdvanced("numbercomment[{$j}]", true);
fe6ce234 506 }
8200ccd6 507 } else {
47538a6b
SR
508 $mform->addElement('hidden', "number[{$j}]", '');
509 $mform->setType("number[{$j}]", PARAM_LOCALISEDFLOAT); // Localisation handling has to be done manually.
510 if (isset($this->formdata["number[{$j}]"])) {
9173b83e 511 $this->formdata["number[{$j}]"] = format_float($this->formdata["number[{$j}]"], -1);
47538a6b 512 }
fe6ce234 513 }
83a15d02 514
f4fe3968
TH
515 $mform->addElement('hidden', "itemid[{$j}]");
516 $mform->setType("itemid[{$j}]", PARAM_INT);
a31697ba 517
f4fe3968
TH
518 $mform->addElement('hidden', "definition[{$j}]");
519 $mform->setType("definition[{$j}]", PARAM_NOTAGS);
83a15d02 520
fe6ce234
DC
521 $j--;
522 }
8200ccd6
TH
523 if (!empty($strquestionlabel) && ($k > 0 || $this->outsidelimit ||
524 !empty($this->numbererrors))) {
f4fe3968 525 $mform->addElement('static', "answercomment[{$i}]", "<b>" .
8200ccd6
TH
526 get_string('setno', 'qtype_calculatedsimple', $i) .
527 "</b>&nbsp;&nbsp;" . $strquestionlabel);
aeb15530 528
fe6ce234 529 }
8200ccd6 530 if ($k > 0 || $this->outsidelimit || !empty($this->numbererrors)) {
f4fe3968 531 $mform->addElement('static', "divider1[{$j}]", '', '<hr />');
aeb15530 532
fe6ce234 533 }
8200ccd6 534 $k--;
fe6ce234
DC
535 }
536 }
8200ccd6
TH
537 } else {
538 $mform->addElement('static', 'warningnowildcards', '', '<span class="error">' .
539 get_string('atleastonewildcard', 'qtype_calculatedsimple') . '</span>');
fe6ce234 540 $mform->closeHeaderBefore('warningnowildcards');
83a15d02 541 }
83a15d02 542
3d9645ae 543 // ...----------------------------------------------------------------------.
544 // Non standard name for button element needed so not using add_action_buttons.
545 // Hidden elements.
83a15d02 546
547 $mform->addElement('hidden', 'id');
548 $mform->setType('id', PARAM_INT);
549
550 $mform->addElement('hidden', 'courseid');
551 $mform->setType('courseid', PARAM_INT);
552 $mform->setDefault('courseid', 0);
553
554 $mform->addElement('hidden', 'cmid');
555 $mform->setType('cmid', PARAM_INT);
556 $mform->setDefault('cmid', 0);
8200ccd6
TH
557 if (!empty($this->question->id)) {
558 if ($this->question->formoptions->cansaveasnew) {
559 $mform->addElement('header', 'additemhdr',
560 get_string('converttocalculated', 'qtype_calculatedsimple'));
fe6ce234 561 $mform->closeHeaderBefore('additemhdr');
aeb15530 562
8200ccd6
TH
563 $mform->addElement('checkbox', 'convert', '',
564 get_string('willconverttocalculated', 'qtype_calculatedsimple'));
fe6ce234 565 $mform->setDefault('convert', 0);
83a15d02 566
83a15d02 567 }
fe6ce234 568 }
83a15d02 569 }
570
8011be18
TH
571 protected function can_preview() {
572 return empty($this->question->beingcopied) && !empty($this->question->id) &&
573 $this->question->formoptions->canedit && $this->noofitems > 0;
574 }
575
8200ccd6 576 public function data_preprocessing($question) {
5cf69d7f
TH
577 $question = parent::data_preprocessing($question);
578 $question = $this->data_preprocessing_answers($question);
579 $question = $this->data_preprocessing_hints($question);
efe3e87b
TH
580 $question = $this->data_preprocessing_units($question);
581 $question = $this->data_preprocessing_unit_options($question);
582
5cf69d7f
TH
583 // This is a bit ugly, but it loads all the dataset values.
584 $question = (object)((array)$question + $this->formdata);
585
fe6ce234 586 return $question;
83a15d02 587 }
588
8200ccd6 589 public function qtype() {
83a15d02 590 return 'calculatedsimple';
591 }
592
8200ccd6 593 public function validation($data, $files) {
83a15d02 594 $errors = parent::validation($data, $files);
dfcaa245
TH
595
596 if (array_key_exists('number', $data)) {
597 $numbers = $data['number'];
598 } else {
599 $numbers = array();
600 }
9ddb8a56 601 foreach ($numbers as $key => $number) {
602 if (! is_numeric($number)) {
603 if (stristr($number, ',')) {
604 $errors['number['.$key.']'] = get_string('nocommaallowed', 'qtype_calculated');
605 } else {
606 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
607 }
608 } else if (stristr($number, 'x')) {
609 $a = new stdClass();
610 $a->name = '';
611 $a->value = $number;
612 $errors['number['.$key.']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
613 } else if (is_nan($number)) {
614 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
615 }
616 }
83a15d02 617
e6d76583
TH
618 if (empty($data['definition'])) {
619 $errors['selectadd'] = get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple');
620 }
621
83a15d02 622 return $errors;
623 }
624}