Typos in comments
[moodle.git] / question / type / calculatedmulti / edit_calculatedmulti_form.php
CommitLineData
2d279432
PP
1<?php
2/**
3 * Defines the editing form for the calculated question 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 * calculated editing form definition.
14 */
15class question_edit_calculatedmulti_form extends question_edit_form {
16 /**
17 * Handle to the question type for this question.
18 *
19 * @var question_calculatedmulti_qtype
20 */
21 var $qtypeobj;
22 function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
23 global $QTYPES, $SESSION, $CFG, $DB;
24 $this->regenerate = true;
25 $this->question = $question;
26 $this->qtypeobj =& $QTYPES[$this->question->qtype];
27 parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
28 }
29
30 /**
31 * Get the list of form elements to repeat, one for each answer.
32 * @param object $mform the form being built.
33 * @param $label the label to use for each option.
34 * @param $gradeoptions the possible grades for each answer.
35 * @param $repeatedoptions reference to array of repeated options to fill
36 * @param $answersoption reference to return the name of $question->options field holding an array of answers
37 * @return array of form fields.
38 */
39 /* function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
40 $repeated = array();
41 $repeated[] =& $mform->createElement('header', 'answerhdr', $label);
42 $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
43 $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
44 $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
45 array('course' => $this->coursefilesid));
46 $repeatedoptions['answer']['type'] = PARAM_RAW;
47 $repeatedoptions['fraction']['default'] = 0;
48 $answersoption = 'answers';
49 return $repeated;
50 }*/
51 function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
52 // $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
53 $repeated = array();
54 $repeated[] =& $mform->createElement('header', 'answerhdr', $label);
55 // if ($this->editasmultichoice == 1){
56 $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
57 $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
58 $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'),
59 array('course' => $this->coursefilesid));
60 $repeatedoptions['answer']['type'] = PARAM_RAW;
61 $repeatedoptions['fraction']['default'] = 0;
62 $answersoption = 'answers';
63
64 $mform->setType('answer', PARAM_NOTAGS);
65
66 $addrepeated = array();
67 $addrepeated[] =& $mform->createElement('hidden', 'tolerance');
68 $addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
69 $repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
70 $repeatedoptions['tolerance']['default'] = 0.01;
71
72 $addrepeated[] =& $mform->createElement('select', 'correctanswerlength', get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
73 $repeatedoptions['correctanswerlength']['default'] = 2;
74
75 $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
76 $addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
77 array_splice($repeated, 3, 0, $addrepeated);
78 $repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
79
80 return $repeated;
81 }
82
83 /**
84 * Add question-type specific form fields.
85 *
86 * @param MoodleQuickForm $mform the form being built.
87 */
88 function definition_inner(&$mform) {
89 global $QTYPES;
90 $this->qtypeobj =& $QTYPES[$this->qtype()];
91 // echo code left for testing period
92 // echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
d7be65a3 93 $label = get_string("sharedwildcards", "qtype_calculated");
2d279432
PP
94 $mform->addElement('hidden', 'initialcategory', 1);
95 $mform->setType('initialcategory', PARAM_INT);
96
97 // $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
98 $html2 ="";
99 $mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
100 $addfieldsname='updatecategory';
101 $addstring=get_string("updatecategory", "qtype_calculated");
102 $mform->registerNoSubmitButton($addfieldsname);
103 $this->editasmultichoice = 1 ;
104
105
106 $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
107 $mform->registerNoSubmitButton('createoptionbutton');
108 $mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
109 $mform->setType('multichoice', PARAM_INT);
110
111
d7be65a3 112// $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
2d279432
PP
113 $menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
114 $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu);
115 $mform->setDefault('single', 1);
116
117 $mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1));
118 $mform->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'qtype_multichoice'));
119 $mform->setDefault('shuffleanswers', 1);
120
121 $numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
122 $menu = array();
123 foreach ($numberingoptions as $numberingoption) {
124 $menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
125 }
126 $mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu);
127 $mform->setDefault('answernumbering', 'abc');
128
129 $creategrades = get_grade_options();
130 $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
131 $creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
132
133
134 $repeated = array();
135 // if ($this->editasmultichoice == 1){
136 $nounits = optional_param('nounits', 1, PARAM_INT);
137 $mform->addElement('hidden', 'nounits', $nounits);
138 $mform->setType('nounits', PARAM_INT);
139 $mform->setConstants(array('nounits'=>$nounits));
140 for ($i=0; $i< $nounits; $i++) {
141 $mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
142 $mform->setType('unit'."[$i]", PARAM_NOTAGS);
143 $mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
144 $mform->setType('multiplier'."[$i]", PARAM_NUMBER);
145 }
146 $mform->addElement('hidden','unitgradingtype',optional_param('unitgradingtype', '', PARAM_INT)) ;
147 $mform->addElement('hidden','unitpenalty',optional_param('unitpenalty', '', PARAM_NUMBER)) ;
148 $mform->addElement('hidden','showunits',optional_param('showunits', '', PARAM_INT)) ;
149 $mform->addElement('hidden','unitsleft',optional_param('unitsleft', '', PARAM_INT)) ;
150 $mform->addElement('hidden','instructions',optional_param('instructions', '', PARAM_RAW)) ;
151
152 $mform->setType('addunits','hidden');
153 $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
154
155 foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
156 $mform->addElement('htmleditor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'),
157 array('course' => $this->coursefilesid));
158 $mform->setType($feedbackname, PARAM_RAW);
159 }
160 //hidden elements
161 $mform->addElement('hidden', 'synchronize', '');
162 $mform->setType('synchronize', PARAM_INT);
163 if (isset($this->question->options)&& isset($this->question->options->synchronize) ){
164 $mform->setDefault("synchronize", $this->question->options->synchronize);
165 } else {
166 $mform->setDefault("synchronize", 0 );
167 }
168 $mform->addElement('hidden', 'wizard', 'datasetdefinitions');
169 $mform->setType('wizard', PARAM_ALPHA);
170
171
172 }
173
174 function set_data($question) {
175 $default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
176 if (isset($question->options)){
177 $answers = $question->options->answers;
178 if (count($answers)) {
179 $key = 0;
180 foreach ($answers as $answer){
181 $default_values['answer['.$key.']'] = $answer->answer;
182 $default_values['fraction['.$key.']'] = $answer->fraction;
183 $default_values['tolerance['.$key.']'] = $answer->tolerance;
184 $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
185 $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
186 $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
187 $default_values['feedback['.$key.']'] = $answer->feedback;
188 $key++;
189 }
190 }
191 // $default_values['unitgradingtype'] = $question->options->unitgradingtype ;
192 // $default_values['unitpenalty'] = $question->options->unitpenalty ;
193 // $default_values['showunits'] = $question->options->showunits ;
194 // $default_values['unitsleft'] = $question->options->unitsleft ;
195 // $default_values['instructions'] = $question->options->instructions ;
196 $default_values['synchronize'] = $question->options->synchronize ;
197
198 if (isset($question->options->units)){
199 $units = array_values($question->options->units);
200 // make sure the default unit is at index 0
201 usort($units, create_function('$a, $b',
202 'if (1.0 === (float)$a->multiplier) { return -1; } else '.
203 'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
204 if (count($units)) {
205 $key = 0;
206 foreach ($units as $unit){
207 $default_values['unit['.$key.']'] = $unit->unit;
208 $default_values['multiplier['.$key.']'] = $unit->multiplier;
209 $key++;
210 }
211 }
212 }
213 }
214 if (isset($question->options->single)){
215 $default_values['single'] = $question->options->single;
216 $default_values['answernumbering'] = $question->options->answernumbering;
217 $default_values['shuffleanswers'] = $question->options->shuffleanswers;
218 $default_values['correctfeedback'] = $question->options->correctfeedback;
219 $default_values['partiallycorrectfeedback'] = $question->options->partiallycorrectfeedback;
220 $default_values['incorrectfeedback'] = $question->options->incorrectfeedback;
221 }
222 $default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
223 $default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
224 /* set the wild cards category display given that on loading the category element is
225 unselected when processing this function but have a valid value when processing the
226 update category button. The value can be obtain by
227 $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
228 but is coded using existing functions
229 */
230 $qu = new stdClass;
231 $el = new stdClass;
232 /* no need to call elementExists() here */
233 if ($this->_form->elementExists('category')){
234 $el=$this->_form->getElement('category');
235 } else {
236 $el=$this->_form->getElement('categorymoveto');
237 }
238 if($value =$el->getSelected()) {
239 $qu->category =$value[0];
240 }else {
241 $qu->category=$question->category;// on load $question->category is set by question.php
242 }
243 $html2 = $this->qtypeobj->print_dataset_definitions_category($qu);
244 $this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
245 $question = (object)((array)$question + $default_values);
246
247 parent::set_data($question);
248 }
249
250 function qtype() {
251 return 'calculatedmulti';
252 }
253
254 function validation($data, $files) {
255 // echo code left for testing period
256
257 // echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
258 // echo "<p>data <pre>";print_r($data);echo "</pre></p>";
259
260 $errors = parent::validation($data, $files);
261 //verifying for errors in {=...} in question text;
262 $qtext = "";
263 $qtextremaining = $data['questiontext'] ;
264 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
265 foreach ($possibledatasets as $name => $value) {
266 $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
267 }
268 // echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
269 while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
270 $qtextsplits = explode($regs1[0], $qtextremaining, 2);
271 $qtext =$qtext.$qtextsplits[0];
272 $qtextremaining = $qtextsplits[1];
273 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
274 if(!isset($errors['questiontext'])){
275 $errors['questiontext'] = $formulaerrors.':'.$regs1[1] ;
276 }else {
277 $errors['questiontext'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
278 }
279 }
280 }
281 $answers = $data['answer'];
282 $answercount = 0;
283 $maxgrade = false;
284 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']);
285 $mandatorydatasets = array();
286 foreach ($answers as $key => $answer){
287 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
288 }
289 if ( count($mandatorydatasets )==0){
290 // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
291 foreach ($answers as $key => $answer){
292 $errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
293 }
294 }
295 if ($data['multichoice']== 1 ){
296 foreach ($answers as $key => $answer){
297 $trimmedanswer = trim($answer);
298 if (($trimmedanswer!='')||$answercount==0){
299 //verifying for errors in {=...} in answer text;
300 $qanswer = "";
301 $qanswerremaining = $trimmedanswer ;
302 $possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
303 foreach ($possibledatasets as $name => $value) {
304 $qanswerremaining = str_replace('{'.$name.'}', '1', $qanswerremaining);
305 }
306 // echo "numericalquestion qanswerremaining <pre>";print_r($possibledatasets);
307 while (preg_match('~\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) {
308 $qanswersplits = explode($regs1[0], $qanswerremaining, 2);
309 $qanswer =$qanswer.$qanswersplits[0];
310 $qanswerremaining = $qanswersplits[1];
311 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
312 if(!isset($errors['answer['.$key.']'])){
313 $errors['answer['.$key.']'] = $formulaerrors.':'.$regs1[1] ;
314 }else {
315 $errors['answer['.$key.']'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
316 }
317 }
318 }
319 }
320 if ($trimmedanswer!=''){
321 if ('2' == $data['correctanswerformat'][$key]
322 && '0' == $data['correctanswerlength'][$key]) {
323 $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
324 }
325 if (!is_numeric($data['tolerance'][$key])){
326 $errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
327 }
328 if ($data['fraction'][$key] == 1) {
329 $maxgrade = true;
330 }
331
332 $answercount++;
333 }
334 //check grades
335 $totalfraction = 0 ;
336 $maxfraction = 0 ;
337 if ($answer != '') {
338 if ($data['fraction'][$key] > 0) {
339 $totalfraction += $data['fraction'][$key];
340 }
341 if ($data['fraction'][$key] > $maxfraction) {
342 $maxfraction = $data['fraction'][$key];
343 }
344 }
345 }
346 if ($answercount==0){
347 $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
348 $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
349 } elseif ($answercount==1){
350 $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
351
352 }
353
354 /// Perform sanity checks on fractional grades
355 if ($data['single']) {
356 if ($maxfraction > 0.999 ) {
357 $maxfraction = $maxfraction * 100;
358 $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction);
359 }
360 } else {
361 $totalfraction = round($totalfraction,2);
362 if ($totalfraction != 1) {
363 $totalfraction = $totalfraction * 100;
364 $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
365 }
366 }
367
368
369 if ($answercount==0){
370 $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
371 }
372 if ($maxgrade == false) {
373 $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
374 }
375
376 }
377 return $errors;
378 }
379}
380