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