MDL-20636 Boilerplate and other cleanup in the question core code.
[moodle.git] / question / type / calculatedsimple / edit_calculatedsimple_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
83a15d02 18/**
19 * Defines the editing form for the calculated simplequestion type.
20 *
b04a4319
TH
21 * @package qtype
22 * @subpackage calculatedsimple
23 * @copyright 2007 Jamie Pratt me@jamiep.org
24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 */
26
27
28/**
29 * Editing form for the calculated simplequestion type.
30 *
31 * @copyright 2007 Jamie Pratt me@jamiep.org
32 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
83a15d02 33 */
83a15d02 34class question_edit_calculatedsimple_form extends question_edit_form {
35 /**
36 * Handle to the question type for this question.
37 *
38 * @var question_calculatedsimple_qtype
39 */
fe6ce234 40 public $qtypeobj;
0735b509 41
fe6ce234 42 public $wildcarddisplay ;
0735b509 43
fe6ce234 44 public $questiondisplay ;
83a15d02 45
46 public $datasetdefs;
47
48 public $reload = false ;
aeb15530 49
83a15d02 50 public $maxnumber = -1;
51
52 public $regenerate = true;
53
54 public $noofitems;
aeb15530 55
83a15d02 56 public $outsidelimit = false ;
aeb15530
PS
57
58 public $commentanswer = array();
59
83a15d02 60 public $answer = array();
61
62 public $nonemptyanswer = array();
aeb15530 63
a31697ba 64 public $numbererrors = array();
65
aeb15530
PS
66 public $formdata = array();
67
83a15d02 68 function question_edit_calculatedsimple_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
69 global $QTYPES, $SESSION, $CFG, $DB;
83a15d02 70 $this->regenerate = true;
71 $this->question = $question;
b003b818 72
83a15d02 73 $this->qtypeobj =& $QTYPES[$this->question->qtype];
74 //get the dataset definitions for this question
75 //coming here everytime even when using a NoSubmitButton
76 //so this will only set the values to the actual question database content which is not what we want
77 //so this should be removed from here
78 // get priority to paramdatasets
aeb15530 79
fe6ce234
DC
80 if ("1" == optional_param('reload','', PARAM_INT )) {
81 $this->reload = true;
83a15d02 82 }else {
fe6ce234 83 $this->reload = false;
83a15d02 84 }
fe6ce234 85 if (!$this->reload) { // use database data as this is first pass
0735b509 86 // question->id == 0 so no stored datasets
aeb15530 87 // else get datasets
2fa83505 88 // echo "<p>question <pre>";print_r($question);echo "</pre></p>";
fe6ce234
DC
89 if (!empty($question->id)) {
90
2fa83505 91 /* if (empty($question->options)) {
83a15d02 92 $this->get_question_options($question);
2fa83505 93 }*/
83a15d02 94 $this->datasetdefs = $this->qtypeobj->get_dataset_definitions($question->id, array());
aeb15530 95
83a15d02 96 if(!empty($this->datasetdefs)){
1d1f5784 97 foreach ($this->datasetdefs as $defid => $datasetdef) {
aeb15530 98 // first get the items in case their number does not correspond to itemcount
1d1f5784 99 if (isset($datasetdef->id)) {
0735b509 100 $this->datasetdefs[$defid]->items = $this->qtypeobj->get_database_dataset_items($datasetdef->id);
101 if ( $this->datasetdefs[$defid]->items != '') {
102 $datasetdef->itemcount = count($this->datasetdefs[$defid]->items);
103 } else {
104 $datasetdef->itemcount = 0 ;
105 }
1d1f5784 106 }
83a15d02 107 // Get maxnumber
108 if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
109 $this->maxnumber = $datasetdef->itemcount;
110 }
111 }
83a15d02 112 }
1d1f5784 113
83a15d02 114 $i = 0 ;
115 foreach($this->question->options->answers as $answer){
116 $this->answer[$i] = $answer ;
117 $i++;
aeb15530 118 }
83a15d02 119 $this->nonemptyanswer = $this->answer ;
aeb15530 120 }
83a15d02 121 $datasettoremove = false;
aeb15530
PS
122 $newdatasetvalues = false ;
123 $newdataset = false ;
124 }else {
83a15d02 125 // handle reload to get values from the form-elements
126 // answers, datasetdefs and data_items
aeb15530
PS
127 // In any case the validation step will warn the user of any error in settings the values.
128 // Verification for the specific dataset values as the other parameters
83a15d02 129 // unints, feeedback etc are handled elsewhere
130 // handle request buttons :
aeb15530 131 // 'analyzequestion' (Identify the wild cards {x..} present in answers)
83a15d02 132 // 'addbutton' (create new set of datatitems)
133 // 'updatedatasets' is handled automatically on each reload
aeb15530 134 // The analyzequestion is done every time on reload
83a15d02 135 // to detect any new wild cards so that the current display reflects
136 // the mandatory (i.e. in answers) datasets
137 // to implement : don't do any changes if the question is used in a quiz.
aeb15530
PS
138 // If new datadef, new properties should erase items.
139 // Most of the data
06f80c6c 140 $datasettoremove = false;
aeb15530
PS
141 $newdatasetvalues = false ;
142 $newdataset = false ;
0735b509 143 $dummyform = new stdClass();
144 $mandatorydatasets = array();
aeb15530 145 // should not test on adding a new answer
06f80c6c 146 // should test if there are already olddatasets or if the 'analyzequestion' submit button has been clicked
fe6ce234 147 if ('' != optional_param('datasetdef', '', PARAM_RAW) || '' != optional_param('analyzequestion', '', PARAM_RAW)){
aeb15530
PS
148
149 if ( $dummyform->answer = optional_param('answer', '', PARAM_NOTAGS)) { // there is always at least one answer...
2a2c5eff 150 $fraction = optional_param('fraction', '', PARAM_NUMBER);
aeb15530
PS
151 $tolerance = optional_param('tolerance', '', PARAM_NUMBER);
152 $tolerancetype = optional_param('tolerancetype', '', PARAM_NUMBER);
153 $correctanswerlength = optional_param('correctanswerlength', '', PARAM_INT);
154 $correctanswerformat = optional_param('correctanswerformat', '', PARAM_INT);
155
06f80c6c 156 foreach( $dummyform->answer as $key => $answer ) {
aeb15530 157 if(trim($answer) != ''){ // just look for non-empty
06f80c6c 158 $this->answer[$key]=new stdClass();
159 $this->answer[$key]->answer = $answer;
2a2c5eff 160 $this->answer[$key]->fraction = $fraction[$key];
06f80c6c 161 $this->answer[$key]->tolerance = $tolerance[$key];
162 $this->answer[$key]->tolerancetype = $tolerancetype[$key];
163 $this->answer[$key]->correctanswerlength = $correctanswerlength[$key];
164 $this->answer[$key]->correctanswerformat = $correctanswerformat[$key];
165 $this->nonemptyanswer[]= $this->answer[$key];
166 $mandatorydatasets +=$this->qtypeobj->find_dataset_names($answer);
167 }
0735b509 168 }
83a15d02 169 }
06f80c6c 170 $this->datasetdefs = array();
171 // rebuild datasetdefs from old values
aeb15530
PS
172 if ($olddef = optional_param('datasetdef', '', PARAM_RAW)){
173 $calcmin = optional_param('calcmin', '', PARAM_NUMBER);
174 $calclength = optional_param('calclength', '', PARAM_INT);
b003b818 175 $calcmax = optional_param('calcmax', '', PARAM_NUMBER);
aeb15530
PS
176 $oldoptions = optional_param('defoptions', '', PARAM_RAW);
177 $newdatasetvalues = false ;
b692e4aa
AB
178 $sizeofolddef = sizeof($olddef);
179 for($key = 1; $key <= $sizeofolddef; $key++) {
06f80c6c 180 $def = $olddef[$key] ;
181 $this->datasetdefs[$def]= new stdClass ;
182 $this->datasetdefs[$def]->type = 1;
183 $this->datasetdefs[$def]->category = 0;
184 // $this->datasets[$key]->name = $datasetname;
b003b818 185 $this->datasetdefs[$def]->options = $oldoptions[$key] ;
06f80c6c 186 $this->datasetdefs[$def]->calcmin = $calcmin[$key] ;
187 $this->datasetdefs[$def]->calcmax = $calcmax[$key] ;
188 $this->datasetdefs[$def]->calclength = $calclength[$key] ;
189 //then compare with new values
190 if (preg_match('~^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$~', $this->datasetdefs[$def]->options, $regs)) {
191 if( $this->datasetdefs[$def]->calcmin != $regs[2]||
192 $this->datasetdefs[$def]->calcmax != $regs[3] ||
193 $this->datasetdefs[$def]->calclength != $regs[4]){
194 $newdatasetvalues = true ;
aeb15530 195 }
06f80c6c 196 }
197 $this->datasetdefs[$def]->options="uniform:".$this->datasetdefs[$def]->calcmin.":".$this->datasetdefs[$def]->calcmax.":".$this->datasetdefs[$def]->calclength;
198 }
199 }// if (olddef...
aeb15530
PS
200 // detect new datasets
201 $newdataset = false ;
83a15d02 202 foreach ($mandatorydatasets as $datasetname) {
203 if (!isset($this->datasetdefs["1-0-$datasetname"])) {
83a15d02 204 $key = "1-0-$datasetname";
205 $this->datasetdefs[$key]=new stdClass ;//"1-0-$datasetname";
206 $this->datasetdefs[$key]->type = 1;
207 $this->datasetdefs[$key]->category = 0;
208 $this->datasetdefs[$key]->name = $datasetname;
209 $this->datasetdefs[$key]->options = "uniform:1.0:10.0:1";
aeb15530 210 $newdataset = true ;
83a15d02 211 }else {
212 $this->datasetdefs["1-0-$datasetname"]->name = $datasetname ;
213 }
214 }
aeb15530 215 // remove obsolete datasets
83a15d02 216 $datasettoremove = false;
217 foreach ($this->datasetdefs as $defkey => $datasetdef){
218 if(!isset($datasetdef->name )){
83a15d02 219 $datasettoremove = true;
220 unset($this->datasetdefs[$defkey]);
221 }
06f80c6c 222 }
aeb15530 223 }
83a15d02 224 } // handle reload
225 // create items if $newdataset and noofitems > 0 and !$newdatasetvalues
226 // eliminate any items if $newdatasetvalues
227 // eliminate any items if $datasettoremove, $newdataset, $newdatasetvalues
228 if ($datasettoremove ||$newdataset ||$newdatasetvalues ) {
229 foreach ($this->datasetdefs as $defkey => $datasetdef){
230 $datasetdef->itemcount = 0;
231 unset($datasetdef->items);
232 }
233 }
234 $maxnumber = -1 ;
0cd89526 235 if ( "" !=optional_param('addbutton', '', PARAM_TEXT)){
06f80c6c 236 $maxnumber = optional_param('selectadd', '', PARAM_INT); //FIXME: sloppy coding
83a15d02 237 foreach ($this->datasetdefs as $defid => $datasetdef) {
238 $datasetdef->itemcount = $maxnumber;
239 unset($datasetdef->items);
240 for ($numberadded =1 ; $numberadded <= $maxnumber; $numberadded++){
241 $datasetitem = new stdClass;
83a15d02 242 $datasetitem->itemnumber = $numberadded;
243 $datasetitem->id = 0;
244 $datasetitem->value = $this->qtypeobj->generate_dataset_item($datasetdef->options);
245 $this->datasetdefs[$defid]->items[$numberadded]=$datasetitem ;
83a15d02 246 }//for number added
247 }// datasetsdefs end
248 $this->maxnumber = $maxnumber ;
83a15d02 249 }else {
0735b509 250 // Handle reload dataset items
0cd89526 251 if ( "" !=optional_param('definition','', PARAM_NOTAGS)&& !($datasettoremove ||$newdataset ||$newdatasetvalues )){
83a15d02 252 $i = 1;
aeb15530
PS
253 $fromformdefinition = optional_param('definition', '', PARAM_NOTAGS);
254 $fromformnumber = optional_param('number', '', PARAM_INT);
255 $fromformitemid = optional_param('itemid', '', PARAM_INT);
83a15d02 256 ksort($fromformdefinition);
aeb15530 257
83a15d02 258 foreach($fromformdefinition as $key => $defid) {
259 $addeditem = new stdClass();
260 $addeditem->id = $fromformitemid[$i] ;
261 $addeditem->value = $fromformnumber[$i];
262 $addeditem->itemnumber = ceil($i / count($this->datasetdefs));
263 $this->datasetdefs[$defid]->items[$addeditem->itemnumber]=$addeditem ;
264 $this->datasetdefs[$defid]->itemcount = $i ;
265 $i++;
266 }
267 }
268 if (isset($addeditem->itemnumber) && $this->maxnumber < $addeditem->itemnumber){
269 $this->maxnumber = $addeditem->itemnumber;
aeb15530 270 if(!empty($this->datasetdefs)){
83a15d02 271 foreach ($this->datasetdefs as $datasetdef) {
272 $datasetdef->itemcount = $this->maxnumber ;
273 }
274 }
275 }
276 }
277
83a15d02 278 parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
279 }
280
281 function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
aeab3f8d 282 $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
83a15d02 283 $mform->setType('answer', PARAM_NOTAGS);
284 $addrepeated = array();
285 $addrepeated[] =& $mform->createElement('text', 'tolerance', get_string('tolerance', 'qtype_calculated'));
286 $repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
287 $repeatedoptions['tolerance']['default'] = 0.01;
288 $addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
289 $addrepeated[] =& $mform->createElement('select', 'correctanswerlength', get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
290 $repeatedoptions['correctanswerlength']['default'] = 2;
291
292 $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
293 $addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
294 array_splice($repeated, 3, 0, $addrepeated);
295 $repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
296
297 return $repeated;
298 }
299
300 /**
301 * Add question-type specific form fields.
302 *
303 * @param MoodleQuickForm $mform the form being built.
304 */
305 function definition_inner(&$mform) {
306 global $QTYPES;
307 $this->qtypeobj =& $QTYPES[$this->qtype()];
308 $strquestionlabel = $this->qtypeobj->comment_header($this->nonemptyanswer);
2fa83505 309 $label = get_string("sharedwildcards", "qtype_calculated");
b003b818 310 $mform->addElement('hidden', 'synchronize', 0);
83a15d02 311 $mform->addElement('hidden', 'initialcategory', 1);
d18e0fe6 312 $mform->setType('initialcategory', PARAM_INT);
83a15d02 313 $mform->addElement('hidden', 'reload', 1);
d18e0fe6 314 $mform->setType('reload', PARAM_INT);
a31697ba 315 $addfieldsname='updatequestion value';
83a15d02 316 $addstring=get_string("updatecategory", "qtype_calculated");
a31697ba 317 $mform->registerNoSubmitButton($addfieldsname);
fe6ce234
DC
318 // put a submit button to stop supplementary answers on update answers parameters
319 // $mform->insertElementBefore($mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
83a15d02 320
321 $creategrades = get_grade_options();
322 $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
fe6ce234 323 $creategrades->gradeoptions, 1, 1);
83a15d02 324
cf146692 325 $QTYPES['numerical']->add_units_options($mform,$this);
aeb15530 326
cf146692 327 $QTYPES['numerical']->add_units_elements($mform,$this);
83a15d02 328 $label = "<div class='mdl-align'></div><div class='mdl-align'>".get_string('wildcardrole', 'qtype_calculatedsimple')."</div>";
329 $mform->addElement('html', "<div class='mdl-align'>&nbsp;</div>");
330 $mform->addElement('html', $label);// explaining the role of datasets so other strings can be shortened
331
332 $mform->addElement('submit', 'analyzequestion', get_string('findwildcards','qtype_calculatedsimple'));
333 $mform->registerNoSubmitButton('analyzequestion');
334 $mform->closeHeaderBefore('analyzequestion');
335 if ( "" != optional_param('analyzequestion','', PARAM_RAW)) {
336
337 $this->wizarddisplay = true;
83a15d02 338
339 }else {
340 $this->wizwarddisplay = false;
341 }
342 if ($this->maxnumber != -1){
343 $this->noofitems = $this->maxnumber;
344 } else {
345 $this->noofitems = 0;
346 }
a31697ba 347 if(!empty($this->datasetdefs)){//So there are some datadefs
fe6ce234 348 // we put them on the page
0735b509 349 $key = 0;
350 $mform->addElement('header', 'additemhdr', get_string('wildcardparam', 'qtype_calculatedsimple'));
351 $idx = 1;
352 if(!empty($this->datasetdefs)){// unnecessary test
353 $j = (($this->noofitems) * count($this->datasetdefs))+1;//
354 foreach ($this->datasetdefs as $defkey => $datasetdef){
2fa83505 355 $mform->addElement('static', "na[$j]", get_string('param', 'qtype_calculated', $datasetdef->name));
0735b509 356 $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
357 $mform->addElement('hidden', "datasetdef[$idx]");
358 $mform->setType("datasetdef[$idx]", PARAM_RAW);
b003b818 359 $mform->addElement('hidden', "defoptions[$idx]");
aeb15530 360 $mform->setType("defoptions[$idx]", PARAM_RAW);
0735b509 361 $idx++;
362 $mform->addElement('static', "divider[$j]", '', '<hr />');
363 $j++;
364 }
365 }
366 //this should be done before the elements are created and stored as $this->formdata ;
367 //fill out all data sets and also the fields for the next item to add.
fe6ce234
DC
368 /*Here we do already the values error analysis so that
369 * we could force all wild cards values display if there is an error in values.
370 * as using a , in a number */
371 $this->numbererrors = array();
0735b509 372 if(!empty($this->datasetdefs)){
fe6ce234
DC
373 $j = $this->noofitems * count($this->datasetdefs);
374 for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
375 $data = array();
376 $numbererrors = array() ;
377 $comment = new stdClass;
378 $comment->stranswers = array();
379 $comment->outsidelimit = false ;
380 $comment->answers = array();
381
382 foreach ($this->datasetdefs as $defid => $datasetdef){
383 if (isset($datasetdef->items[$itemnumber])){
384 $this->formdata["definition[$j]"] = $defid;
385 $this->formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
386 $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
387 $this->formdata["number[$j]"] = $number = $datasetdef->items[$itemnumber]->value;
388 if(! is_numeric($number)){
389 $a = new stdClass;
390 $a->name = '{'.$datasetdef->name.'}' ;
391 $a->value = $datasetdef->items[$itemnumber]->value ;
392 if (stristr($number,',')){
2fa83505 393 $this->numbererrors["number[$j]"]=get_string('nocommaallowed', 'qtype_calculated');
fe6ce234 394 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
aeb15530 395
fe6ce234 396 }else {
2fa83505 397 $this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
0735b509 398 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
399 //$comment->outsidelimit = false ;
fe6ce234
DC
400 }
401 }else if( stristr($number,'x')){ // hexa will pass the test
402 $a = new stdClass;
403 $a->name = '{'.$datasetdef->name.'}' ;
404 $a->value = $datasetdef->items[$itemnumber]->value ;
405 $this->numbererrors['number['.$j.']']= get_string('hexanotallowed','qtype_calculated',$a);
406 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
407 } else if( is_nan($number)){
408 $a = new stdClass;
409 $a->name = '{'.$datasetdef->name.'}' ;
410 $a->value = $datasetdef->items[$itemnumber]->value ;
411 $this->numbererrors["number[$j]"]= get_string('notvalidnumber','qtype_calculated',$a);
412 $numbererrors .= $this->numbererrors['number['.$j.']']."<br />";
413 // $val = 1.0 ;
0735b509 414 }
0735b509 415 }
fe6ce234
DC
416 $j--;
417 }
418 if($this->noofitems != 0 ) {
419 if (empty($numbererrors)) {
420 if (!isset($this->question->id)) {
421 $this->question->id = 0 ;
422 }
423 $this->question->questiontext = !empty($this->question->questiontext)?$this->question->questiontext:'';
424 $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $this->question->id, $this->question->questiontext, $this->nonemptyanswer, $data, $itemnumber);
425 if ($comment->outsidelimit) {
426 $this->outsidelimit=$comment->outsidelimit ;
0735b509 427 }
fe6ce234
DC
428 $totalcomment='';
429
430 foreach ($this->nonemptyanswer as $key => $answer) {
431 $totalcomment .= $comment->stranswers[$key].'<br/>';
432 }
433
434 $this->formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
435 }
0735b509 436 }
fe6ce234
DC
437 }
438 $this->formdata['selectdelete'] = '1';
439 $this->formdata['selectadd'] = '1';
440 $j = $this->noofitems * count($this->datasetdefs)+1;
441 $data = array(); // data for comment_on_datasetitems later
0735b509 442 $idx =1 ;
443 foreach ($this->datasetdefs as $defid => $datasetdef){
444 $this->formdata["datasetdef[$idx]"] = $defid;
445 $idx++;
446 }
fe6ce234
DC
447 $this->formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $this->formdata);
448 }
449
450
451 $addoptions = Array();
452 $addoptions['1']='1';
453 for ($i=10; $i<=100 ; $i+=10){
454 $addoptions["$i"]="$i";
455 }
456 $showoptions = Array();
457 $showoptions['1']='1';
458 $showoptions['2']='2';
459 $showoptions['5']='5';
460 for ($i=10; $i<=100 ; $i+=10){
461 $showoptions["$i"]="$i";
462 }
463 $mform->closeHeaderBefore('additemhdr');
464 $addgrp = array();
465 $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('generatenewitemsset', 'qtype_calculatedsimple'));
466 $addgrp[] =& $mform->createElement('select', "selectadd", '', $addoptions);
467 $addgrp[] = & $mform->createElement('static',"stat",'',get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
468 $mform->addGroup($addgrp, 'addgrp', '', ' ', false);
469 $mform->registerNoSubmitButton('addbutton');
470 $mform->closeHeaderBefore('addgrp');
471 $addgrp1 = array();
472 $addgrp1[] =& $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculatedsimple'));
473 $addgrp1[] =& $mform->createElement('select', "selectshow",'' , $showoptions);
474 $addgrp1[] = & $mform->createElement('static',"stat",'',get_string('setwildcardvalues', 'qtype_calculatedsimple'));
475 $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
476 $mform->registerNoSubmitButton('showbutton');
477 $mform->closeHeaderBefore('addgrp1');
478 $mform->addElement('static', "divideradd", '', '');
479 if ($this->noofitems == 0) {
480 $mform->addElement('static','warningnoitems','','<span class="error">'.get_string('youmustaddatleastonevalue', 'qtype_calculatedsimple').'</span>');
481 $mform->closeHeaderBefore('warningnoitems');
482 }else {
483 $mform->addElement('header', 'additemhdr1', get_string('wildcardvalues', 'qtype_calculatedsimple'));
484 $mform->closeHeaderBefore('additemhdr1');
485 // $mform->addElement('header', '', get_string('itemno', 'qtype_calculated', ""));
486 if( !empty($this->numbererrors) || $this->outsidelimit) {
487 $mform->addElement('static', "alert", '', '<span class="error">'.get_string('useadvance', 'qtype_calculatedsimple').'</span>');
0735b509 488 }
489
fe6ce234
DC
490 $mform->addElement('submit', 'updatedatasets', get_string('updatewildcardvalues', 'qtype_calculatedsimple'));
491 $mform->registerNoSubmitButton('updatedatasets');
492 $mform->setAdvanced("updatedatasets",true);
aeb15530 493
fe6ce234
DC
494 //------------------------------------------------------------------------------------------------------------------------------
495 $j = $this->noofitems * count($this->datasetdefs);
496 $k = 1 ;
0cd89526 497 if ("" != optional_param('selectshow', '', PARAM_INT)){
fe6ce234
DC
498 $k = optional_param('selectshow', '', PARAM_INT);
499 }
aeb15530 500
fe6ce234
DC
501 for ($i = $this->noofitems; $i >= 1 ; $i--){
502 foreach ($this->datasetdefs as $defkey => $datasetdef){
503 if($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ){
504 $mform->addElement('text',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
505 $mform->setAdvanced("number[$j]",true);
506 if(!empty($this->numbererrors['number['.$j.']']) ){
507 $mform->addElement('static', "numbercomment[$j]",'','<span class="error">'.$this->numbererrors['number['.$j.']'].'</span>');
508 $mform->setAdvanced("numbercomment[$j]",true);
509 }
510 }else {
511 $mform->addElement('hidden',"number[$j]" , get_string('wildcard', 'qtype_calculatedsimple', $datasetdef->name));
512 }
513 $mform->setType("number[$j]", PARAM_NUMBER);
83a15d02 514
fe6ce234
DC
515 $mform->addElement('hidden', "itemid[$j]");
516 $mform->setType("itemid[$j]", PARAM_INT);
a31697ba 517
fe6ce234
DC
518 $mform->addElement('hidden', "definition[$j]");
519 $mform->setType("definition[$j]", PARAM_NOTAGS);
83a15d02 520
fe6ce234
DC
521 $j--;
522 }
523 if (!empty( $strquestionlabel) && ($k > 0 || $this->outsidelimit || !empty($this->numbererrors ) ) ){
524 // $repeated[] =& $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
525 $mform->addElement('static', "answercomment[$i]", "<b>".get_string('setno', 'qtype_calculatedsimple', $i)."</b>&nbsp;&nbsp;".$strquestionlabel);
aeb15530 526
fe6ce234
DC
527 }
528 if($k > 0 || $this->outsidelimit || !empty($this->numbererrors )){
529 $mform->addElement('static', "divider1[$j]", '', '<hr />');
aeb15530 530
fe6ce234
DC
531 }
532 $k-- ;
533 }
534 }
535 // if ($this->outsidelimit){
536 // $mform->addElement('static','outsidelimit','','');
537 // }
538 }else {
539 $mform->addElement('static','warningnowildcards','','<span class="error">'.get_string('atleastonewildcard', 'qtype_calculatedsimple').'</span>');
540 $mform->closeHeaderBefore('warningnowildcards');
83a15d02 541 }
83a15d02 542
b003b818 543
fe6ce234 544 //------------------------------------------------------------------------------------------------------------------------------
83a15d02 545 //non standard name for button element needed so not using add_action_buttons
546 //hidden elements
547
548 $mform->addElement('hidden', 'id');
549 $mform->setType('id', PARAM_INT);
550
551 $mform->addElement('hidden', 'courseid');
552 $mform->setType('courseid', PARAM_INT);
553 $mform->setDefault('courseid', 0);
554
555 $mform->addElement('hidden', 'cmid');
556 $mform->setType('cmid', PARAM_INT);
557 $mform->setDefault('cmid', 0);
558 if (!empty($this->question->id)){
559 if ($this->question->formoptions->cansaveasnew){
fe6ce234
DC
560 $mform->addElement('header', 'additemhdr', get_string('converttocalculated', 'qtype_calculatedsimple'));
561 $mform->closeHeaderBefore('additemhdr');
aeb15530 562
83a15d02 563 $mform->addElement('checkbox', 'convert','' ,get_string('willconverttocalculated', 'qtype_calculatedsimple'));
fe6ce234 564 $mform->setDefault('convert', 0);
83a15d02 565
83a15d02 566 }
fe6ce234 567 }
83a15d02 568 }
569
fe6ce234 570 function data_preprocessing($question) {
a3e153c2 571 global $QTYPES;
fe6ce234
DC
572 $answer = $this->answer;
573 $default_values = array();
574 if (count($answer)) {
575 $key = 0;
576 foreach ($answer as $answer){
577 $default_values['answer['.$key.']'] = $answer->answer; // is necessary ? to-do test it
578 $default_values['fraction['.$key.']'] = $answer->fraction;
579 $default_values['tolerance['.$key.']'] = $answer->tolerance;
580 $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
581 $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
582 $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
583
584 // prepare draft files
585 $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
586 $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
587 $draftid, // draftid
588 $this->context->id, // context
589 'question', // component
590 'answerfeedback', // filarea
591 !empty($answer->id)?(int)$answer->id:null, // itemid
592 $this->fileoptions, // options
593 !empty($answer->feedback)?$answer->feedback:'' // text
594 );
595 $default_values['feedback['.$key.']']['format'] = !empty($answer->feedbackformat)?$answer->feedbackformat:editors_get_preferred_format();
596 $default_values['feedback['.$key.']']['itemid'] = $draftid;
597
598 $key++;
b003b818 599 }
fe6ce234
DC
600 }
601 $default_values['synchronize'] = 0 ;
602 $QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
603 /* if (isset($question->options)){
cf146692
PP
604 $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
605 $default_values['unitpenalty'] = $question->options->unitpenalty ;
606 switch ($question->options->showunits){
607 case 'O' :
fe6ce234 608 case '1' :
cf146692
PP
609 $default_values['showunits0'] = $question->options->showunits ;
610 $default_values['unitrole'] = 0 ;
611 break;
612 case '2' :
fe6ce234 613 case '3' :
cf146692
PP
614 $default_values['showunits1'] = $question->options->showunits ;
615 $default_values['unitrole'] = 1 ;
616 break;
fe6ce234 617 }
cf146692
PP
618 $default_values['unitsleft'] = $question->options->unitsleft ;
619 $default_values['instructions'] = $question->options->instructions ;
620
621 if (isset($question->options->units)){
622 $units = array_values($question->options->units);
623 if (!empty($units)) {
624 foreach ($units as $key => $unit){
625 $default_values['unit['.$key.']'] = $unit->unit;
626 $default_values['multiplier['.$key.']'] = $unit->multiplier;
627 }
83a15d02 628 }
629 }
630 }
fe6ce234
DC
631 */
632 $key = 0 ;
83a15d02 633
634 $formdata = array();
635 $fromform = new stdClass();
a31697ba 636 //this should be done before the elements are created and stored as $this->formdata ;
83a15d02 637 //fill out all data sets and also the fields for the next item to add.
fe6ce234 638 /* if(!empty($this->datasetdefs)){
83a15d02 639 $j = $this->noofitems * count($this->datasetdefs);
fe6ce234 640 for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--){
83a15d02 641 $data = array();
642 foreach ($this->datasetdefs as $defid => $datasetdef){
643 if (isset($datasetdef->items[$itemnumber])){
644 $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
645 $formdata["definition[$j]"] = $defid;
646 $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
647 $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
648 }
649 $j--;
650 }
fe6ce234
DC
651 // echo "<p>answers avant comment <pre>";print_r($answer);echo"</pre></p>";
652 // echo "<p>data avant comment <pre>";print_r($data);echo"</pre></p>";
aeb15530 653
83a15d02 654 if($this->noofitems != 0 ) {
655 if(!isset($question->id)) $question->id = 0 ;
fe6ce234
DC
656 $comment = $this->qtypeobj->comment_on_datasetitems($question->id,$this->nonemptyanswer, $data, $itemnumber);//$this->
657 if ($comment->outsidelimit) {
658 $this->outsidelimit=$comment->outsidelimit ;
659 }
660 $totalcomment='';
661 // echo "<p> comment <pre>";print_r($comment);echo"</pre></p>";
83a15d02 662
fe6ce234
DC
663 foreach ($this->nonemptyanswer as $key => $answer) {
664 $totalcomment .= $comment->stranswers[$key].'<br/>';
665 }
83a15d02 666
fe6ce234
DC
667 $formdata['answercomment['.$itemnumber.']'] = $totalcomment ;
668 }
83a15d02 669 }
fe6ce234
DC
670 // $formdata['reload'] = '1';
671 // $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
83a15d02 672 $formdata['selectdelete'] = '1';
673 $formdata['selectadd'] = '1';
674 $j = $this->noofitems * count($this->datasetdefs)+1;
675 $data = array(); // data for comment_on_datasetitems later
676 $idx =1 ;
677 foreach ($this->datasetdefs as $defid => $datasetdef){
678 $formdata["datasetdef[$idx]"] = $defid;
679 $idx++;
680 }
681 $formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
fe6ce234 682 }*/
a31697ba 683 $question = (object)((array)$question + $default_values+$this->formdata );
83a15d02 684
fe6ce234 685 return $question;
83a15d02 686 }
687
688 function qtype() {
689 return 'calculatedsimple';
690 }
691
692 function validation($data, $files) {
cf146692 693 global $QTYPES;
83a15d02 694 $errors = parent::validation($data, $files);
695 //verifying for errors in {=...} in question text;
696 $qtext = "";
fe6ce234
DC
697 $qtextremaining = $data['questiontext']['text'];
698 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
06f80c6c 699 foreach ($possibledatasets as $name => $value) {
83a15d02 700 $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
701 }
6dbcacee 702 while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
83a15d02 703 $qtextsplits = explode($regs1[0], $qtextremaining, 2);
704 $qtext =$qtext.$qtextsplits[0];
705 $qtextremaining = $qtextsplits[1];
706 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
707 if(!isset($errors['questiontext'])){
708 $errors['questiontext'] = $formulaerrors.':'.$regs1[1] ;
709 }else {
710 $errors['questiontext'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
711 }
712 }
713 }
714 $answers = $data['answer'];
715 $answercount = 0;
716 $maxgrade = false;
fe6ce234 717 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
83a15d02 718 $mandatorydatasets = array();
719 foreach ($answers as $key => $answer){
720 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
721 }
722 if ( count($mandatorydatasets )==0){
a31697ba 723 foreach ($answers as $key => $answer){
2fa83505 724 $errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_calculated');
83a15d02 725 }
726 }
727 foreach ($answers as $key => $answer){
728 //check no of choices
729 // the * for everykind of answer not actually implemented
730 $trimmedanswer = trim($answer);
731 if (($trimmedanswer!='')||$answercount==0){
732 $eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
733 if (FALSE !== $eqerror){
734 $errors['answer['.$key.']'] = $eqerror;
735 }
736 }
737 if ($trimmedanswer!=''){
738 if ('2' == $data['correctanswerformat'][$key]
739 && '0' == $data['correctanswerlength'][$key]) {
740 $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
741 }
742 if (!is_numeric($data['tolerance'][$key])){
743 $errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
744 }
745 if ($data['fraction'][$key] == 1) {
746 $maxgrade = true;
747 }
748
749 $answercount++;
750 }
751 //check grades
752
753 //TODO how should grade checking work here??
754 /*if ($answer != '') {
755 if ($data['fraction'][$key] > 0) {
756 $totalfraction += $data['fraction'][$key];
757 }
758 if ($data['fraction'][$key] > $maxfraction) {
759 $maxfraction = $data['fraction'][$key];
760 }
761 }*/
762 }
763 //grade checking :
764 /// Perform sanity checks on fractional grades
765 /*if ( ) {
766 if ($maxfraction != 1) {
767 $maxfraction = $maxfraction * 100;
768 $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction);
769 }
770 } else {
771 $totalfraction = round($totalfraction,2);
772 if ($totalfraction != 1) {
773 $totalfraction = $totalfraction * 100;
774 $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
775 }
776 }*/
cf146692 777 $QTYPES['numerical']->validate_numerical_options($data, $errors) ;
83a15d02 778 $units = $data['unit'];
779 if (count($units)) {
780 foreach ($units as $key => $unit){
781 if (is_numeric($unit)){
782 $errors['unit['.$key.']'] = get_string('mustnotbenumeric', 'qtype_calculated');
783 }
784 $trimmedunit = trim($unit);
785 $trimmedmultiplier = trim($data['multiplier'][$key]);
786 if (!empty($trimmedunit)){
787 if (empty($trimmedmultiplier)){
788 $errors['multiplier['.$key.']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated');
789 }
790 if (!is_numeric($trimmedmultiplier)){
791 $errors['multiplier['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
792 }
793
794 }
795 }
796 }
797 if ($answercount==0){
798 $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
799 }
800 if ($maxgrade == false) {
801 $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
802 }
803 if (isset($data['backtoquiz']) && ($this->noofitems==0) ){
804 $errors['warning'] = get_string('warning', 'mnet');
aeb15530 805 }
83a15d02 806 if ($this->outsidelimit){
807 // if(!isset($errors['warning'])) $errors['warning']=' ';
808 $errors['outsidelimits'] = get_string('oneanswertrueansweroutsidelimits','qtype_calculated');
809 }
aeb15530 810 /*Here we use the already done the error analysis so that
0735b509 811 * we could force all wild cards values display if there is an error in values.
b003b818 812 * as using a , in a number *//*
83a15d02 813 $numbers = $data['number'];
814 foreach ($numbers as $key => $number){
815 if(! is_numeric($number)){
816 if (stristr($number,',')){
2fa83505 817 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
aeb15530 818 }else {
2fa83505 819 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
83a15d02 820 }
821 }else if( stristr($number,'x')){
2fa83505 822 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
83a15d02 823 } else if( is_nan($number)){
2fa83505 824 $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
aeb15530 825 }
83a15d02 826 }
b003b818 827 */
83a15d02 828 if ( $this->noofitems==0 ){
829 $errors['warning'] = get_string('warning', 'mnet');
830 }
831
832 return $errors;
833 }
834}