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