ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilTestPlayerDynamicQuestionSetGUI.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
4 require_once 'Modules/Test/classes/class.ilTestPlayerAbstractGUI.php';
5 
31 {
32  const CMD_SHOW_QUESTION_SELECTION = 'showQuestionSelection';
33  const CMD_SHOW_QUESTION = 'showQuestion';
34  const CMD_FROM_PASS_DELETION = 'fromPassDeletion';
35 
39  private $dynamicQuestionSetConfig = null;
40 
44  protected $testSequence;
45 
49  protected $testSession;
50 
54  function executeCommand()
55  {
56  global $ilDB, $lng, $ilPluginAdmin, $ilTabs, $tree;
57 
58  $ilTabs->clearTargets();
59 
60  $this->ctrl->saveParameter($this, "sequence");
61  $this->ctrl->saveParameter($this, "active_id");
62 
63  require_once 'Modules/Test/classes/class.ilObjTestDynamicQuestionSetConfig.php';
64  $this->dynamicQuestionSetConfig = new ilObjTestDynamicQuestionSetConfig($tree, $ilDB, $ilPluginAdmin, $this->object);
65  $this->dynamicQuestionSetConfig->loadFromDb();
66 
67  $testSessionFactory = new ilTestSessionFactory($this->object);
68  $this->testSession = $testSessionFactory->getSession($_GET['active_id']);
69 
70  $this->ensureExistingTestSession($this->testSession);
71  $this->initProcessLocker($this->testSession->getActiveId());
72 
73  $testSequenceFactory = new ilTestSequenceFactory($ilDB, $lng, $ilPluginAdmin, $this->object);
74  $this->testSequence = $testSequenceFactory->getSequence($this->testSession);
75  $this->testSequence->loadFromDb();
76 
77  include_once 'Services/jQuery/classes/class.iljQueryUtil.php';
79  include_once "./Services/YUI/classes/class.ilYuiUtil.php";
81  if( $this->object->getKioskMode() )
82  {
83  include_once 'Services/UIComponent/Overlay/classes/class.ilOverlayGUI.php';
85  }
86 
88 
89  $cmd = $this->ctrl->getCmd();
90  $nextClass = $this->ctrl->getNextClass($this);
91 
92  switch($nextClass)
93  {
94  case 'ilassquestionpagegui':
95 
96  $questionId = $this->testSequence->getQuestionForSequence( $this->calculateSequence() );
97 
98  require_once "./Modules/TestQuestionPool/classes/class.ilAssQuestionPageGUI.php";
99  $page_gui = new ilAssQuestionPageGUI($questionId);
100  $ret = $this->ctrl->forwardCommand($page_gui);
101  break;
102 
103  case 'ilassquestionhintrequestgui':
104 
105  $questionGUI = $this->object->createQuestionGUI(
106  "", $this->testSequenceFactory->getSequence()->getQuestionForSequence( $this->calculateSequence() )
107  );
108 
109  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
110  $gui = new ilAssQuestionHintRequestGUI($this, self::CMD_SHOW_QUESTION, $this->testSession, $questionGUI);
111 
112  $this->ctrl->forwardCommand($gui);
113 
114  break;
115 
116  case 'ildynamicquestionsetstatistictablegui':
117 
118  $this->ctrl->forwardCommand( $this->buildQuestionSetFilteredStatisticTableGUI() );
119 
120  break;
121 
122  case 'iltestpasswordprotectiongui':
123  require_once 'Modules/Test/classes/class.ilTestPasswordProtectionGUI.php';
124  $gui = new ilTestPasswordProtectionGUI($this->ctrl, $this->tpl, $this->lng, $this, $this->passwordChecker);
125  $ret = $this->ctrl->forwardCommand($gui);
126  break;
127 
128  default:
129 
130  $cmd .= 'Cmd';
131  $ret =& $this->$cmd();
132  break;
133  }
134 
135  return $ret;
136  }
137 
141  protected function resumePlayerCmd()
142  {
143  if ($this->object->checkMaximumAllowedUsers() == FALSE)
144  {
146  }
147 
148  $this->handleUserSettings();
149 
150  if( $this->dynamicQuestionSetConfig->isAnyQuestionFilterEnabled() )
151  {
152  $this->ctrl->redirect($this, self::CMD_SHOW_QUESTION_SELECTION);
153  }
154 
155  $this->ctrl->redirect($this, self::CMD_SHOW_QUESTION);
156  }
157 
158  protected function startTestCmd()
159  {
160  global $ilUser;
161 
162  $this->testSession->setCurrentQuestionId(null); // no question "came up" yet
163 
164  $this->testSession->saveToDb();
165 
166  $this->ctrl->setParameter($this, 'active_id', $this->testSession->getActiveId());
167 
168  assQuestion::_updateTestPassResults($this->testSession->getActiveId(), $this->testSession->getPass(), false, null, $this->object->id);
169 
170  $_SESSION['active_time_id'] = $this->object->startWorkingTime(
171  $this->testSession->getActiveId(), $this->testSession->getPass()
172  );
173 
174  $this->ctrl->saveParameter($this, 'tst_javascript');
175 
176  if( $this->dynamicQuestionSetConfig->isAnyQuestionFilterEnabled() )
177  {
178  $this->ctrl->redirect($this, self::CMD_SHOW_QUESTION_SELECTION);
179  }
180 
181  $this->ctrl->redirect($this, self::CMD_SHOW_QUESTION);
182  }
183 
184  protected function showQuestionSelectionCmd()
185  {
186  $this->prepareSummaryPage();
187 
188  $questionId = $this->testSession->getCurrentQuestionId();
189 
190  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
191  {
192  $this->updateWorkingTime();
193  $this->saveQuestionSolution();
195 
196  $this->testSequence->unsetQuestionPostponed($questionId);
197  }
198 
199  $this->testSequence->loadQuestions(
200  $this->dynamicQuestionSetConfig, $this->testSession->getQuestionSetFilterSelection()
201  );
202 
203  $this->testSequence->cleanupQuestions($this->testSession);
204 
205  $this->testSequence->saveToDb();
206 
207  require_once 'Services/UIComponent/Toolbar/classes/class.ilToolbarGUI.php';
208  $toolbarGUI = new ilToolbarGUI();
209 
210  $toolbarGUI->addButton(
211  $this->getEnterTestButtonLangVar(), $this->ctrl->getLinkTarget($this, self::CMD_SHOW_QUESTION),
212  '', '', '', '', 'submit emphsubmit'
213  );
214 
215  if( $this->object->isPassDeletionAllowed() )
216  {
217  require_once 'Modules/Test/classes/confirmations/class.ilTestPassDeletionConfirmationGUI.php';
218 
219  $toolbarGUI->addButton(
220  $this->lng->txt('tst_dyn_test_pass_deletion_button'),
222  );
223  }
224 
225  $filteredData = array($this->buildQuestionSetAnswerStatisticRowArray(
226  $this->testSequence->getFilteredQuestionsData(), $this->getMarkedQuestions()
227  )); #vd($filteredData);
228  $filteredTableGUI = $this->buildQuestionSetFilteredStatisticTableGUI();
229  $filteredTableGUI->setData($filteredData);
230 
231  $completeData = array($this->buildQuestionSetAnswerStatisticRowArray(
232  $this->testSequence->getCompleteQuestionsData(), $this->getMarkedQuestions()
233  )); #vd($completeData);
234  $completeTableGUI = $this->buildQuestionSetCompleteStatisticTableGUI();
235  $completeTableGUI->setData($completeData);
236 
237  $content = $this->ctrl->getHTML($toolbarGUI);
238  $content .= $this->ctrl->getHTML($filteredTableGUI);
239  $content .= $this->ctrl->getHTML($completeTableGUI);
240 
241  $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $content);
242 
243  if( $this->object->getEnableProcessingTime() )
244  {
245  $this->outProcessingTime($this->testSession->getActiveId());
246  }
247  }
248 
249  protected function filterQuestionSelectionCmd()
250  {
251  $tableGUI = $this->buildQuestionSetFilteredStatisticTableGUI();
252  $tableGUI->writeFilterToSession();
253 
254  $taxFilterSelection = array();
255  $answerStatusFilterSelection = ilAssQuestionList::ANSWER_STATUS_FILTER_ALL_NON_CORRECT;
256 
257  foreach( $tableGUI->getFilterItems() as $item )
258  {
259  if( strpos($item->getPostVar(), 'tax_') !== false )
260  {
261  $taxId = substr( $item->getPostVar(), strlen('tax_') );
262  $taxFilterSelection[$taxId] = $item->getValue();
263  }
264  elseif( $item->getPostVar() == 'question_answer_status' )
265  {
266  $answerStatusFilterSelection = $item->getValue();
267  }
268  }
269 
270  $this->testSession->getQuestionSetFilterSelection()->setTaxonomySelection($taxFilterSelection);
271  $this->testSession->getQuestionSetFilterSelection()->setAnswerStatusSelection($answerStatusFilterSelection);
272  $this->testSession->saveToDb();
273 
274  $this->testSequence->resetTrackedQuestionList();
275  $this->testSequence->saveToDb();
276 
277  $this->ctrl->redirect($this, 'showQuestionSelection');
278  }
279 
280  protected function resetQuestionSelectionCmd()
281  {
282  $tableGUI = $this->buildQuestionSetFilteredStatisticTableGUI();
283  $tableGUI->resetFilter();
284 
285  $this->testSession->getQuestionSetFilterSelection()->setTaxonomySelection( array() );
286  $this->testSession->getQuestionSetFilterSelection()->setAnswerStatusSelection( null );
287  $this->testSession->saveToDb();
288 
289  $this->testSequence->resetTrackedQuestionList();
290  $this->testSequence->saveToDb();
291 
292  $this->ctrl->redirect($this, 'showQuestionSelection');
293  }
294 
295  protected function showTrackedQuestionListCmd()
296  {
297  if( !$this->dynamicQuestionSetConfig->isPreviousQuestionsListEnabled() )
298  {
299  $this->ctrl->redirect($this, self::CMD_SHOW_QUESTION);
300  }
301 
302  $this->prepareSummaryPage();
303 
304  $questionId = $this->testSession->getCurrentQuestionId();
305 
306  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
307  {
308  $this->updateWorkingTime();
309  $this->saveQuestionSolution();
311 
312  $this->testSequence->unsetQuestionPostponed($questionId);
313  }
314 
315  $this->testSequence->loadQuestions(
316  $this->dynamicQuestionSetConfig, $this->testSession->getQuestionSetFilterSelection()
317  );
318 
319  $this->testSequence->cleanupQuestions($this->testSession);
320 
321  $this->testSequence->saveToDb();
322 
323  $data = $this->buildQuestionsTableDataArray(
324  $this->testSequence->getTrackedQuestionList( $this->testSession->getCurrentQuestionId() ),
325  $this->getMarkedQuestions()
326  );
327 
328  include_once "./Modules/Test/classes/tables/class.ilTrackedQuestionsTableGUI.php";
329  $table_gui = new ilTrackedQuestionsTableGUI(
330  $this, 'showTrackedQuestionList', $this->object->getSequenceSettings(), $this->object->getShowMarker()
331  );
332 
333  $table_gui->setData($data);
334 
335  $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $table_gui->getHTML());
336 
337  if( $this->object->getEnableProcessingTime() )
338  {
339  $this->outProcessingTime($this->testSession->getActiveId());
340  }
341  }
342 
343  protected function previousQuestionCmd()
344  {
345 
346  }
347 
348  protected function fromPassDeletionCmd()
349  {
350  $this->resetCurrentQuestion();
351  $this->ctrl->redirect($this, 'showQuestion');
352  }
353 
354  protected function nextQuestionCmd()
355  {
356  $questionId = $this->testSession->getCurrentQuestionId();
357 
358  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
359  {
360  $this->updateWorkingTime();
361  $this->saveQuestionSolution();
363 
364  $this->testSequence->unsetQuestionPostponed($questionId);
365  $this->testSequence->saveToDb();
366  }
367 
368  $this->resetCurrentQuestion();
369 
370  $this->ctrl->redirect($this, 'showQuestion');
371  }
372 
373  protected function postponeQuestionCmd()
374  {
375  $questionId = $this->testSession->getCurrentQuestionId();
376 
377  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
378  {
379  $this->updateWorkingTime();
380  $this->saveQuestionSolution();
382 
383  $this->testSequence->setQuestionPostponed($questionId);
384  }
385 
386  $this->testSession->setCurrentQuestionId(null);
387 
388  $this->testSequence->saveToDb();
389  $this->testSession->saveToDb();
390 
391  $this->ctrl->redirect($this, 'showQuestion');
392  }
393 
394  protected function markQuestionCmd()
395  {
396  $questionId = $this->testSession->getCurrentQuestionId();
397 
398  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
399  {
400  $this->updateWorkingTime();
401  $this->saveQuestionSolution();
403 
404  $this->testSequence->unsetQuestionPostponed($questionId);
405  $this->testSequence->saveToDb();
406  }
407 
408  global $ilUser;
409  $this->object->setQuestionSetSolved(1, $this->testSession->getCurrentQuestionId(), $ilUser->getId());
410 
411  $this->ctrl->redirect($this, 'showQuestion');
412  }
413 
414  protected function unmarkQuestionCmd()
415  {
416  $questionId = $this->testSession->getCurrentQuestionId();
417 
418  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
419  {
420  $this->updateWorkingTime();
421  $this->saveQuestionSolution();
423 
424  $this->testSequence->unsetQuestionPostponed($questionId);
425  $this->testSequence->saveToDb();
426  }
427 
428  global $ilUser;
429  $this->object->setQuestionSetSolved(0, $this->testSession->getCurrentQuestionId(), $ilUser->getId());
430 
431  $this->ctrl->redirect($this, 'showQuestion');
432  }
433 
434  protected function gotoQuestionCmd()
435  {
436  $this->testSequence->loadQuestions(
437  $this->dynamicQuestionSetConfig, $this->testSession->getQuestionSetFilterSelection()
438  );
439 
440  $this->testSequence->cleanupQuestions($this->testSession);
441 
442  if( isset($_GET['sequence']) && (int)$_GET['sequence'] )
443  {
444  $this->testSession->setCurrentQuestionId( (int)$_GET['sequence'] );
445  $this->testSession->saveToDb();
446 
447  $this->ctrl->setParameter(
448  $this, 'sequence', $this->testSession->getCurrentQuestionId()
449  );
450  }
451 
452  $this->ctrl->redirect($this, 'showQuestion');
453  }
454 
455  protected function showQuestionCmd()
456  {
458 
459  $this->testSequence->loadQuestions(
460  $this->dynamicQuestionSetConfig, $this->testSession->getQuestionSetFilterSelection()
461  );
462 
463  $this->testSequence->cleanupQuestions($this->testSession);
464 
465  if( !$this->testSession->getCurrentQuestionId() )
466  {
467  $upComingQuestionId = $this->testSequence->getUpcomingQuestionId();
468 
469  $this->testSession->setCurrentQuestionId($upComingQuestionId);
470 
471  if( $this->testSequence->isQuestionChecked($upComingQuestionId) )
472  {
473  $this->testSequence->setQuestionUnchecked($upComingQuestionId);
474  }
475  }
476 
477  if( $this->testSession->getCurrentQuestionId() )
478  {
479  $this->ctrl->setParameter(
480  $this, 'sequence', $this->testSession->getCurrentQuestionId()
481  );
482 
483  $this->outTestPage(false);
484  }
485  else
486  {
487  $this->outCurrentlyFinishedPage();
488  }
489 
490  $this->testSequence->saveToDb();
491  $this->testSession->saveToDb();
492  }
493 
494  protected function showInstantResponseCmd()
495  {
496  $questionId = $this->testSession->getCurrentQuestionId();
497 
498  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
499  {
500  $this->updateWorkingTime();
501  $this->saveQuestionSolution();
503 
504  $this->testSequence->unsetQuestionPostponed($questionId);
505  $this->testSequence->setQuestionChecked($questionId);
506  }
507 
509 
510  $filterSelection = $this->testSession->getQuestionSetFilterSelection();
511 
512  $filterSelection->setForcedQuestionIds(array($this->testSession->getCurrentQuestionId()));
513 
514  $this->testSequence->loadQuestions($this->dynamicQuestionSetConfig, $filterSelection);
515 
516  $this->testSequence->cleanupQuestions($this->testSession);
517 
518  $this->ctrl->setParameter(
519  $this, 'sequence', $this->testSession->getCurrentQuestionId()
520  );
521 
522  $this->outTestPage(true);
523 
524  $this->testSequence->saveToDb();
525  $this->testSession->saveToDb();
526  }
527 
528  protected function handleQuestionActionCmd()
529  {
530  $questionId = $this->testSession->getCurrentQuestionId();
531 
532  if( $questionId && !$this->isParticipantsAnswerFixed($questionId) )
533  {
534  $this->updateWorkingTime();
535  $this->saveQuestionSolution();
537 
538  $this->testSequence->unsetQuestionPostponed($questionId);
539  $this->testSequence->saveToDb();
540  }
541 
542  $this->ctrl->setParameter(
543  $this, 'sequence', $this->testSession->getCurrentQuestionId()
544  );
545 
546  $this->ctrl->redirect($this, 'showQuestion');
547  }
548 
552  protected function outWorkingForm($sequence = "", $test_id, $postpone_allowed, $directfeedback = false)
553  {
554  global $ilUser;
555 
556  $_SESSION["active_time_id"] = $this->object->startWorkingTime(
557  $this->testSession->getActiveId(), $this->testSession->getPass()
558  );
559 
560  $this->populateContentStyleBlock();
561  $this->populateSyntaxStyleBlock();
562 
563  $question_gui = $this->object->createQuestionGUI(
564  "", $this->testSession->getCurrentQuestionId()
565  );
566 
567  if( !is_object($question_gui) )
568  {
569  global $ilLog;
570 
571  $ilLog->write(
572  "INV SEQ: active={$this->testSession->getActiveId()} qId={$this->testSession->getCurrentQuestionId()} "
573  .serialize($this->testSequence)
574  );
575 
576  $ilLog->logStack('INV SEQ');
577 
578  $this->resetCurrentQuestion();
579  $this->ctrl->redirect($this, 'showQuestion');
580  }
581 
582  $question_gui->setTargetGui($this);
583 
584  $question_gui->setQuestionCount(
585  $this->testSequence->getLastPositionIndex()
586  );
587  $question_gui->setSequenceNumber( $this->testSequence->getCurrentPositionIndex(
588  $this->testSession->getCurrentQuestionId()
589  ));
590 
591  $this->ctrl->setParameter($this, 'sequence', $this->testSession->getCurrentQuestionId());
592 
593  if ($this->object->getJavaScriptOutput())
594  {
595  $question_gui->object->setOutputType(OUTPUT_JAVASCRIPT);
596  }
597 
598  $is_postponed = $this->testSequence->isPostponedQuestion($question_gui->object->getId());
599  $formaction = $this->ctrl->getFormAction($this);
600 
601  // output question
602  $user_post_solution = FALSE;
603  if( isset($_SESSION['previouspost']) )
604  {
605  $user_post_solution = $_SESSION['previouspost'];
606  unset($_SESSION['previouspost']);
607  }
608 
609  global $ilNavigationHistory;
610  $ilNavigationHistory->addItem($_GET["ref_id"], $this->ctrl->getLinkTarget($this, "resumePlayer"), "tst");
611 
612  // Determine $answer_feedback: It should hold a boolean stating if answer-specific-feedback is to be given.
613  // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Answer-Specific Feedback"
614  // $directfeedback holds a boolean stating if the instant feedback was requested using the "Check" button.
615  $answer_feedback = FALSE;
616  if (($directfeedback) && ($this->object->getSpecificAnswerFeedback()))
617  {
618  $answer_feedback = TRUE;
619  }
620 
621  if( $this->isParticipantsAnswerFixed($this->testSession->getCurrentQuestionId()) )
622  {
623  $solutionoutput = $question_gui->getSolutionOutput(
624  $this->testSession->getActiveId(), #active_id
625  NULL, #pass
626  FALSE, #graphical_output
627  false, #result_output
628  true, #show_question_only
629  $answer_feedback, #show_feedback
630  false, #show_correct_solution
631  FALSE, #show_manual_scoring
632  true #show_question_text
633  );
634 
635  $pageoutput = $question_gui->outQuestionPage(
636  "", $this->testSequence->isPostponedQuestion($this->testSession->getCurrentQuestionId()),
637  $this->testSession->getActiveId(),
638  $solutionoutput
639  );
640 
641  $this->tpl->setVariable("QUESTION_OUTPUT", $pageoutput);
642  $this->tpl->setVariable("FORMACTION", $formaction);
643 
644  $directfeedback = true;
645  }
646  else
647  {
648  // Answer specific feedback is rendered into the display of the test question with in the concrete question types outQuestionForTest-method.
649  // Notation of the params prior to getting rid of this crap in favor of a class
650  $question_gui->outQuestionForTest(
651  $formaction, #form_action
652  $this->testSession->getActiveId(), #active_id
653  NULL, #pass
654  $is_postponed, #is_postponed
655  $user_post_solution, #user_post_solution
656  $answer_feedback #answer_feedback == inline_specific_feedback
657  );
658  // The display of specific inline feedback and specific feedback in an own block is to honor questions, which
659  // have the possibility to embed the specific feedback into their output while maintaining compatibility to
660  // questions, which do not have such facilities. E.g. there can be no "specific inline feedback" for essay
661  // questions, while the multiple-choice questions do well.
662 
663  $this->fillQuestionRelatedNavigation($question_gui);
664  }
665 
666  if ($directfeedback)
667  {
668  // This controls if the solution should be shown.
669  // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
670  if ($this->object->getInstantFeedbackSolution())
671  {
672  $show_question_inline_score = $this->determineInlineScoreDisplay();
673 
674  // Notation of the params prior to getting rid of this crap in favor of a class
675  $solutionoutput = $question_gui->getSolutionOutput(
676  $this->testSession->getActiveId(), #active_id
677  NULL, #pass
678  TRUE, #graphical_output
679  $show_question_inline_score, #result_output
680  FALSE, #show_question_only
681  FALSE, #show_feedback
682  TRUE, #show_correct_solution
683  FALSE, #show_manual_scoring
684  FALSE #show_question_text
685  );
686  $this->populateSolutionBlock( $solutionoutput );
687  }
688 
689  // This controls if the score should be shown.
690  // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Results (Only Points)"
691  if ($this->object->getAnswerFeedbackPoints())
692  {
693  $reachedPoints = $question_gui->object->getAdjustedReachedPoints($this->testSession->getActiveId(), NULL);
694  $maxPoints = $question_gui->object->getMaximumPoints();
695 
696  $this->populateScoreBlock( $reachedPoints, $maxPoints );
697  }
698 
699  // This controls if the generic feedback should be shown.
700  // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Solutions"
701  if ($this->object->getGenericAnswerFeedback())
702  {
703  $this->populateGenericFeedbackBlock( $question_gui );
704  }
705 
706  // This controls if the specific feedback should be shown.
707  // It gets the parameter "Scoring and Results" -> "Instant Feedback" -> "Show Answer-Specific Feedback"
708  if ($this->object->getSpecificAnswerFeedback())
709  {
710  $this->populateSpecificFeedbackBlock( $question_gui );
711  }
712  }
713 
714  $this->populatePreviousButtons( $this->testSession->getCurrentQuestionId() );
715 
716  if( $postpone_allowed )
717  {
718  $this->populatePostponeButtons();
719  }
720 
721  if ($this->object->getShowCancel())
722  {
723  $this->populateCancelButtonBlock();
724  }
725 
726  if ($this->isLastQuestionInSequence( $question_gui ))
727  {
728  if ($this->object->getListOfQuestionsEnd())
729  {
731  }
732  else
733  {
735  }
736  }
737  else
738  {
740  }
741 
742  if( $this->dynamicQuestionSetConfig->isAnyQuestionFilterEnabled() )
743  {
745  }
746 
747  if ($this->object->getShowMarker())
748  {
749  include_once "./Modules/Test/classes/class.ilObjTest.php";
750  $solved_array = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId(), $question_gui->object->getId());
751  $solved = 0;
752 
753  if (count ($solved_array) > 0)
754  {
755  $solved = array_pop($solved_array);
756  $solved = $solved["solved"];
757  }
758 
759  if ($solved==1)
760  {
762  }
763  else
764  {
766  }
767  }
768 
769  $this->populateCharSelector();
770 
771  if ($this->object->getJavaScriptOutput())
772  {
773  $this->tpl->setVariable("JAVASCRIPT_TITLE", $this->lng->txt("disable_javascript"));
774  $this->ctrl->setParameter($this, "tst_javascript", "0");
775  $this->tpl->setVariable("JAVASCRIPT_URL", $this->ctrl->getLinkTarget($this, "gotoQuestion"));
776  }
777  else
778  {
779  $this->tpl->setVariable("JAVASCRIPT_TITLE", $this->lng->txt("enable_javascript"));
780  $this->ctrl->setParameter($this, "tst_javascript", "1");
781  $this->tpl->setVariable("JAVASCRIPT_URL", $this->ctrl->getLinkTarget($this, "gotoQuestion"));
782  }
783 
784  if ($question_gui->object->supportsJavascriptOutput())
785  {
786  $this->tpl->touchBlock("jsswitch");
787  }
788 
789  $this->tpl->addJavaScript(ilUtil::getJSLocation("autosave.js", "Modules/Test"));
790 
791  $this->tpl->setVariable("AUTOSAVE_URL", $this->ctrl->getFormAction($this, "autosave", "", true));
792 
793  if ($question_gui->isAutosaveable()&& $this->object->getAutosave())
794  {
795  $this->tpl->touchBlock('autosave');
796  //$this->tpl->setVariable("BTN_SAVE", "Zwischenspeichern");
797  //$this->tpl->setVariable("CMD_SAVE", "gotoquestion_{$sequence}");
798  //$this->tpl->setVariable("AUTOSAVEFORMACTION", str_replace("&amp;", "&", $this->ctrl->getFormAction($this)));
799  $this->tpl->setVariable("AUTOSAVEFORMACTION", str_replace("&amp;", "&", $this->ctrl->getLinkTarget($this, "autosave")));
800  $this->tpl->setVariable("AUTOSAVEINTERVAL", $this->object->getAutosaveIval());
801  }
802 
803  if( $this->object->areObligationsEnabled() && ilObjTest::isQuestionObligatory($question_gui->object->getId()) )
804  {
805  $this->tpl->touchBlock('question_obligatory');
806  $this->tpl->setVariable('QUESTION_OBLIGATORY', $this->lng->txt('required_field'));
807  }
808  }
809 
810  private function outCurrentlyFinishedPage()
811  {
812  $this->prepareTestPageOutput();
813 
814  $this->populatePreviousButtons( $this->testSession->getCurrentQuestionId() );
815 
816  if ($this->object->getKioskMode())
817  {
818  $this->populateKioskHead();
819  }
820 
821  if ($this->object->getEnableProcessingTime())
822  {
823  $this->outProcessingTime($this->testSession->getActiveId());
824  }
825 
826  $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
827  $this->tpl->setVariable("FORM_TIMESTAMP", time());
828 
829  $this->tpl->setVariable("PAGETITLE", "- " . $this->object->getTitle());
830 
831  if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode())
832  {
833  $this->tpl->setCurrentBlock('exam_id');
834  $this->tpl->setVariable('EXAM_ID', ilObjTest::lookupExamId(
835  $this->testSession->getActiveId(), $this->testSession->getPass(), $this->object->getId()
836  ));
837  $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
838  $this->tpl->parseCurrentBlock();
839  }
840 
841  if ($this->object->getShowCancel())
842  {
843  $this->populateCancelButtonBlock();
844  }
845 
846  if( $this->dynamicQuestionSetConfig->isAnyQuestionFilterEnabled() )
847  {
849  }
850 
851  if( $this->testSequence->openQuestionExists() )
852  {
853  $message = $this->lng->txt('tst_dyn_test_msg_currently_finished_selection');
854  }
855  else
856  {
857  $message = $this->lng->txt('tst_dyn_test_msg_currently_finished_completely');
858  $message .= "<br /><br />{$this->buildFinishPagePassDeletionLink()}";
859  }
860 
861  $msgHtml = $this->tpl->getMessageHTML($message);
862 
863  $this->tpl->addBlockFile(
864  'QUESTION_OUTPUT', 'test_currently_finished_msg_block',
865  'tpl.test_currently_finished_msg.html', 'Modules/Test'
866  );
867 
868  $this->tpl->setCurrentBlock('test_currently_finished_msg_block');
869  $this->tpl->setVariable('TEST_CURRENTLY_FINISHED_MSG', $msgHtml);
870  $this->tpl->parseCurrentBlock();
871 
872  }
873 
874  protected function isFirstPageInSequence($sequence)
875  {
876  return !$this->testSequence->trackedQuestionExists();
877  }
878 
879  protected function isLastQuestionInSequence(assQuestionGUI $questionGUI)
880  {
881  return false; // always
882  }
883 
884  protected function handleJavascriptActivationStatus()
885  {
886  global $ilUser;
887 
888  if( isset($_GET['tst_javascript']) )
889  {
890  $ilUser->writePref('tst_javascript', $_GET['tst_javascript']);
891  }
892  }
893 
899  protected function canSaveResult()
900  {
901  return !$this->object->endingTimeReached();
902  }
903 
907  public function saveQuestionSolution($force = FALSE)
908  {
909  // what is this formtimestamp ??
910  if (!$force)
911  {
912  $formtimestamp = $_POST["formtimestamp"];
913  if (strlen($formtimestamp) == 0) $formtimestamp = $_GET["formtimestamp"];
914  if ($formtimestamp != $_SESSION["formtimestamp"])
915  {
916  $_SESSION["formtimestamp"] = $formtimestamp;
917  }
918  else
919  {
920  return FALSE;
921  }
922  }
923 
924  // determine current question
925 
926  $qId = $this->testSession->getCurrentQuestionId();
927 
928  if( !$qId || $qId != $_GET["sequence"])
929  {
930  return false;
931  }
932 
933  // save question solution
934 
935  $this->saveResult = FALSE;
936 
937  if ($this->canSaveResult($qId) || $force)
938  {
939  global $ilUser;
940 
941  $questionGUI = $this->object->createQuestionGUI("", $qId);
942 
943  if( $this->object->getJavaScriptOutput() )
944  {
945  $questionGUI->object->setOutputType(OUTPUT_JAVASCRIPT);
946  }
947 
948  $activeId = $this->testSession->getActiveId();
949 
950  $this->saveResult = $questionGUI->object->persistWorkingState(
951  $activeId, $pass = null, $this->object->areObligationsEnabled()
952  );
953  }
954 
955  if ($this->saveResult == FALSE)
956  {
957  $this->ctrl->setParameter($this, "save_error", "1");
958  $_SESSION["previouspost"] = $_POST;
959  }
960 
961  return $this->saveResult;
962  }
963 
964  private function isQuestionAnsweredCorrect($questionId, $activeId, $pass)
965  {
966  $questionGUI = $this->object->createQuestionGUI("", $questionId);
967 
968  $reachedPoints = assQuestion::_getReachedPoints($activeId, $questionId, $pass);
969  $maxPoints = $questionGUI->object->getMaximumPoints();
970 
971  if($reachedPoints < $maxPoints)
972  {
973  return false;
974  }
975 
976  return true;
977  }
978 
979 
980  protected function populatePreviousButtons($sequence)
981  {
982  if( !$this->dynamicQuestionSetConfig->isPreviousQuestionsListEnabled() )
983  {
984  return;
985  }
986 
987  if( $this->isFirstPageInSequence($sequence) )
988  {
989  return;
990  }
991 
993  'showTrackedQuestionList', "&lt;&lt; " . $this->lng->txt( "save_previous" )
994  );
996  'showTrackedQuestionList', "&lt;&lt; " . $this->lng->txt( "save_previous" )
997  );
998  }
999 
1000  protected function buildQuestionsTableDataArray($questions, $marked_questions)
1001  {
1002  $data = array();
1003 
1004  foreach($questions as $key => $value )
1005  {
1006  $this->ctrl->setParameter($this, 'sequence', $value['question_id']);
1007  $href = $this->ctrl->getLinkTarget($this, 'gotoQuestion');
1008  $this->ctrl->setParameter($this, 'sequence', '');
1009 
1010  $description = "";
1011  if( $this->object->getListOfQuestionsDescription() )
1012  {
1013  $description = $value["description"];
1014  }
1015 
1016  $marked = false;
1017  if( count($marked_questions) )
1018  {
1019  if( isset($marked_questions[$value["question_id"]]) )
1020  {
1021  if( $marked_questions[$value["question_id"]]["solved"] == 1 )
1022  {
1023  $marked = true;
1024  }
1025  }
1026  }
1027 
1028  array_push($data, array(
1029  'href' => $href,
1030  'title' => $this->object->getQuestionTitle($value["title"]),
1031  'description' => $description,
1032  'worked_through' => $this->testSequence->isAnsweredQuestion($value["question_id"]),
1033  'postponed' => $this->testSequence->isPostponedQuestion($value["question_id"]),
1034  'marked' => $marked
1035  ));
1036  }
1037 
1038  return $data;
1039  }
1040 
1041  protected function buildQuestionSetAnswerStatisticRowArray($questions, $marked_questions)
1042  {
1043  $questionAnswerStats = array(
1044  'total_all' => count($questions),
1045  'total_open' => 0,
1046  'non_answered' => 0,
1047  'wrong_answered' => 0,
1048  'correct_answered' => 0,
1049  'postponed' => 0,
1050  'marked' => 0
1051  );
1052 
1053  foreach($questions as $key => $value )
1054  {
1055  switch( $value['question_answer_status'] )
1056  {
1058  $questionAnswerStats['non_answered']++;
1059  $questionAnswerStats['total_open']++;
1060  break;
1062  $questionAnswerStats['wrong_answered']++;
1063  $questionAnswerStats['total_open']++;
1064  break;
1066  $questionAnswerStats['correct_answered']++;
1067  break;
1068  }
1069 
1070  if( $this->testSequence->isPostponedQuestion($value["question_id"]) )
1071  {
1072  $questionAnswerStats['postponed']++;
1073  }
1074 
1075  if( isset($marked_questions[$value["question_id"]]) )
1076  {
1077  if( $marked_questions[$value["question_id"]]["solved"] == 1 )
1078  {
1079  $questionAnswerStats['marked']++;
1080  }
1081  }
1082  }
1083 
1084  return $questionAnswerStats;
1085  }
1086 
1088  {
1089  require_once 'Modules/Test/classes/tables/class.ilTestDynamicQuestionSetStatisticTableGUI.php';
1090  $gui = $this->buildQuestionSetStatisticTableGUI(
1092  );
1093 
1094  $gui->initTitle('tst_dynamic_question_set_complete');
1095  $gui->initColumns('tst_num_all_questions');
1096 
1097  return $gui;
1098  }
1099 
1101  {
1102  require_once 'Modules/Test/classes/tables/class.ilTestDynamicQuestionSetStatisticTableGUI.php';
1103  $gui = $this->buildQuestionSetStatisticTableGUI(
1105  );
1106 
1107  $gui->initTitle('tst_dynamic_question_set_selection');
1108  $gui->initColumns('tst_num_selected_questions');
1109 
1110  require_once 'Services/Taxonomy/classes/class.ilObjTaxonomy.php';
1111  $gui->setTaxIds(ilObjTaxonomy::getUsageOfObject(
1112  $this->dynamicQuestionSetConfig->getSourceQuestionPoolId()
1113  ));
1114 
1115  $gui->setTaxonomyFilterEnabled($this->dynamicQuestionSetConfig->isTaxonomyFilterEnabled());
1116  $gui->setAnswerStatusFilterEnabled($this->dynamicQuestionSetConfig->isAnswerStatusFilterEnabled());
1117 
1118  $gui->initFilter();
1119  $gui->setFilterCommand('filterQuestionSelection');
1120  $gui->setResetCommand('resetQuestionSelection');
1121 
1122  return $gui;
1123  }
1124 
1125  private function buildQuestionSetStatisticTableGUI($tableId)
1126  {
1127  require_once 'Modules/Test/classes/tables/class.ilTestDynamicQuestionSetStatisticTableGUI.php';
1129  $this->ctrl, $this->lng, $this, 'showQuestionSelection', $tableId
1130  );
1131 
1132  $gui->setShowNumMarkedQuestionsEnabled($this->object->getShowMarker());
1133  $gui->setShowNumPostponedQuestionsEnabled($this->object->getSequenceSettings());
1134 
1135  return $gui;
1136  }
1137 
1138  private function getEnterTestButtonLangVar()
1139  {
1140  if( $this->testSequence->trackedQuestionExists() )
1141  {
1142  return $this->lng->txt('tst_resume_dyn_test_with_cur_quest_sel');
1143  }
1144 
1145  return $this->lng->txt('tst_start_dyn_test_with_cur_quest_sel');
1146  }
1147 
1148  protected function persistQuestionAnswerStatus()
1149  {
1150  $questionId = $this->testSession->getCurrentQuestionId();
1151  $activeId = $this->testSession->getActiveId();
1152  $pass = $this->testSession->getPass();
1153 
1154  if($this->isQuestionAnsweredCorrect($questionId, $activeId, $pass))
1155  {
1156  $this->testSequence->setQuestionAnsweredCorrect($questionId);
1157  }
1158  else
1159  {
1160  $this->testSequence->setQuestionAnsweredWrong($questionId);
1161  }
1162  }
1163 
1164  private function resetCurrentQuestion()
1165  {
1166  $this->testSession->setCurrentQuestionId(null);
1167 
1168  $this->testSequence->saveToDb();
1169  $this->testSession->saveToDb();
1170 
1171  $this->ctrl->setParameter($this, 'sequence', $this->testSession->getCurrentQuestionId());
1172  }
1173 
1178  {
1179  $href = $this->getPassDeletionTarget();
1180 
1181  $label = $this->lng->txt('tst_dyn_test_msg_pass_deletion_link');
1182 
1183  return "<a href=\"{$href}\">{$label}</a>";
1184  }
1185 
1189  private function getPassDeletionTarget()
1190  {
1191  require_once 'Modules/Test/classes/confirmations/class.ilTestPassDeletionConfirmationGUI.php';
1192 
1193  $this->ctrl->setParameterByClass('ilTestEvaluationGUI', 'context', ilTestPassDeletionConfirmationGUI::CONTEXT_DYN_TEST_PLAYER);
1194  $this->ctrl->setParameterByClass('ilTestEvaluationGUI', 'active_id', $this->testSession->getActiveId());
1195  $this->ctrl->setParameterByClass('ilTestEvaluationGUI', 'pass', $this->testSession->getPass());
1196 
1197  return $this->ctrl->getLinkTargetByClass('ilTestEvaluationGUI', 'confirmDeletePass');
1198  }
1199 }