ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
class.ilTestPlayerAbstractGUI.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/inc.AssessmentConstants.php';
5 require_once './Modules/Test/classes/class.ilTestServiceGUI.php';
6 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
7 require_once './Services/UIComponent/Button/classes/class.ilSubmitButton.php';
8 
26 {
27  var $ref_id;
29  var $sequence;
30  var $cmdCtrl;
33 
37  protected $passwordChecker;
38 
42  protected $processLocker;
43 
47  protected $testSession;
48 
54  public function __construct($a_object)
55  {
56  parent::ilTestServiceGUI($a_object);
57  $this->ref_id = $_GET["ref_id"];
58 
59  global $rbacsystem, $ilUser;
60  require_once 'Modules/Test/classes/class.ilTestPasswordChecker.php';
61  $this->passwordChecker = new ilTestPasswordChecker($rbacsystem, $ilUser, $this->object);
62 
63  $this->processLocker = null;
64  $this->testSession = null;
65  }
66 
68  {
69  if( $testSession->getActiveId() )
70  {
71  return;
72  }
73 
74  global $ilUser;
75 
76  $testSession->setUserId($ilUser->getId());
77 
78  if( $testSession->isAnonymousUser() )
79  {
80  if( !$testSession->doesAccessCodeInSessionExists() )
81  {
82  return;
83  }
84 
85  $testSession->setAnonymousId($testSession->getAccessCodeFromSession());
86  }
87 
88  $testSession->saveToDb();
89  }
90 
91  protected function initProcessLocker($activeId)
92  {
93  global $ilDB;
94 
95  $settings = new ilSetting('assessment');
96 
97  require_once 'Modules/Test/classes/class.ilTestProcessLockerFactory.php';
98  $processLockerFactory = new ilTestProcessLockerFactory($settings, $ilDB);
99 
100  $processLockerFactory->setActiveId($activeId);
101 
102  $this->processLocker = $processLockerFactory->getLocker();
103  }
104 
111  function saveTagsCmd()
112  {
113  include_once("./Services/Tagging/classes/class.ilTaggingGUI.php");
114  $tagging_gui = new ilTaggingGUI();
115  $tagging_gui->setObject($this->object->getId(), $this->object->getType());
116  $tagging_gui->saveInput();
117  $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
118  }
119 
120  public function outResultsToplistCmd()
121  {
122  global $ilCtrl;
123  $ilCtrl->redirectByClass('ilTestToplistGUI', 'outResultsToplist');
124  }
125 
129  function updateWorkingTime()
130  {
131  if ($_SESSION["active_time_id"])
132  {
133  $this->object->updateWorkingTime($_SESSION["active_time_id"]);
134  }
135  }
136 
140  abstract public function saveQuestionSolution($force = FALSE);
141 
142  abstract protected function canSaveResult();
143 
144  abstract protected function outWorkingForm($sequence = "", $test_id, $postpone_allowed, $directfeedback = false);
145 
151  public function outIntroductionPageCmd()
152  {
153  if( $this->customRedirectRequired() )
154  {
155  $this->performCustomRedirect();
156  }
157 
158  $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
159  }
160 
168  public function isMaxProcessingTimeReached()
169  {
170  global $ilUser;
171  $active_id = $this->testSession->getActiveId();
172  $starting_time = $this->object->getStartingTimeOfUser($active_id);
173  if ($starting_time === FALSE)
174  {
175  return FALSE;
176  }
177  else
178  {
179  return $this->object->isMaxProcessingTimeReached($starting_time, $active_id);
180  }
181  }
182 
183  protected function determineInlineScoreDisplay()
184  {
185  $show_question_inline_score = FALSE;
186  if ($this->object->getAnswerFeedbackPoints())
187  {
188  $show_question_inline_score = TRUE;
189  return $show_question_inline_score;
190  }
191  return $show_question_inline_score;
192  }
193 
194  protected function populatePreviousButtons($sequence)
195  {
196  if ($this->isFirstPageInSequence( $sequence ))
197  {
199  }
200  else
201  {
203  }
204  }
205 
207  {
208  $this->tpl->setCurrentBlock( "isnotmarked" );
209  $this->tpl->setVariable( "CMD_UNMARKED", 'markQuestion' );
210  $this->tpl->setVariable( "IMAGE_UNMARKED", ilUtil::getImagePath( "marked_.svg" ) );
211  $this->tpl->setVariable( "TEXT_UNMARKED", $this->lng->txt( "tst_question_mark" ) );
212  $this->tpl->parseCurrentBlock();
213  }
214 
216  {
217  $this->tpl->setCurrentBlock( "ismarked" );
218  $this->tpl->setVariable( "CMD_MARKED", 'unmarkQuestion' );
219  $this->tpl->setVariable( "IMAGE_MARKED", ilUtil::getImagePath( "marked.svg" ) );
220  $this->tpl->setVariable( "TEXT_MARKED", $this->lng->txt( "tst_remove_mark" ) );
221  $this->tpl->parseCurrentBlock();
222  }
223 
225  {
228  }
229 
231  {
232  $button = ilSubmitButton::getInstance();
233  $button->setPrimary( true );
234  $button->setCommand( 'nextQuestion' );
235  $button->setCaption( 'save_next' );
236  $button->setId( 'bottomnextbutton' );
237 
238  $this->tpl->setCurrentBlock( "next_bottom" );
239  $this->tpl->setVariable( "BTN_NEXT", $button->render());
240  $this->tpl->parseCurrentBlock();
241  }
242 
244  {
245  $button = ilSubmitButton::getInstance();
246  $button->setPrimary( true );
247  $button->setCommand( 'nextQuestion' );
248  $button->setCaption( 'save_next' );
249  $button->setId( 'nextbutton' );
250 
251  $this->tpl->setCurrentBlock( "next" );
252  $this->tpl->setVariable( "BTN_NEXT", $button->render());
253  $this->tpl->parseCurrentBlock();
254  }
255 
257  {
260  }
261 
263  {
264  $button = ilSubmitButton::getInstance();
265  $button->setPrimary( true );
266  $button->setCommand( 'nextQuestion' );
267  $button->setCaption( 'save_finish' );
268  $button->setId( 'bottomnextbutton' );
269 
270  $this->tpl->setCurrentBlock( "next_bottom" );
271  $this->tpl->setVariable( "BTN_NEXT", $button->render());
272  $this->tpl->parseCurrentBlock();
273  }
274 
276  {
277  $button = ilSubmitButton::getInstance();
278  $button->setPrimary( true );
279  $button->setCommand( 'nextQuestion' );
280  $button->setCaption( 'save_finish' );
281  $button->setId( 'nextbutton' );
282 
283  $this->tpl->setCurrentBlock( "next" );
284  $this->tpl->setVariable( "BTN_NEXT", $button->render());
285  $this->tpl->parseCurrentBlock();
286  }
287 
289  {
292  }
293 
295  {
296  $button = ilSubmitButton::getInstance();
297  $button->setPrimary( true );
298  $button->setCommand( 'nextQuestion' );
299  $button->setCaption( 'question_summary' );
300  $button->setId( 'bottomnextbutton' );
301 
302  $this->tpl->setCurrentBlock( "next_bottom" );
303  $this->tpl->setVariable( "BTN_NEXT", $button->render());
304  $this->tpl->parseCurrentBlock();
305  }
306 
308  {
309  $button = ilSubmitButton::getInstance();
310  $button->setPrimary( true );
311  $button->setCommand( 'nextQuestion' );
312  $button->setCaption( 'question_summary' );
313  $button->setId( 'nextbutton' );
314 
315  $this->tpl->setCurrentBlock( "next" );
316  $this->tpl->setVariable( "BTN_NEXT", $button->render());
317  $this->tpl->parseCurrentBlock();
318  }
319 
320  protected function populateCancelButtonBlock()
321  {
322  $this->tpl->setCurrentBlock('cancel_test');
323  $this->tpl->setVariable('TEXT_CANCELTEST', $this->lng->txt('cancel_test'));
324  $this->ctrl->setParameterByClass(get_class($this), 'cancelTest', 'true');
325  $this->tpl->setVariable('HREF_CANCELTEXT', $this->ctrl->getLinkTargetByClass(get_class($this), 'outIntroductionPage'));
326  $this->ctrl->setParameterByClass(get_class($this), 'cancelTest', null);
327  $this->tpl->parseCurrentBlock();
328  }
329 
330  protected function populateSummaryButtons()
331  {
334  }
335 
336  protected function populateLowerSummaryButtonBlock()
337  {
338  $this->tpl->setCurrentBlock( "summary_bottom" );
339  $this->tpl->setVariable( "CMD_SUMMARY", 'showQuestionList' );
340  $this->tpl->setVariable( "BTN_SUMMARY", $this->lng->txt( "question_summary" ) );
341  $this->tpl->parseCurrentBlock();
342  }
343 
344  protected function populateUpperSummaryButtonBlock()
345  {
346  $this->tpl->setCurrentBlock( "summary" );
347  $this->tpl->setVariable( "CMD_SUMMARY", 'showQuestionList' );
348  $this->tpl->setVariable( "BTN_SUMMARY", $this->lng->txt( "question_summary" ) );
349  $this->tpl->parseCurrentBlock();
350  }
351 
352  protected function populateQuestionSelectionButtons()
353  {
356  }
357 
359  {
360  $this->tpl->setCurrentBlock( "summary_bottom" );
361  $this->tpl->setVariable( "CMD_SUMMARY", 'showQuestionSelection' );
362  $this->tpl->setVariable( "BTN_SUMMARY", $this->lng->txt( "tst_change_dyn_test_question_selection" ) );
363  $this->tpl->parseCurrentBlock();
364  }
365 
367  {
368  $this->tpl->setCurrentBlock( "summary" );
369  $this->tpl->setVariable( "CMD_SUMMARY", 'showQuestionSelection' );
370  $this->tpl->setVariable( "BTN_SUMMARY", $this->lng->txt( "tst_change_dyn_test_question_selection" ) );
371  $this->tpl->parseCurrentBlock();
372  }
373 
374  protected function populatePostponeButtons()
375  {
378  }
379 
380  protected function populateLowerPostponeButtonBlock()
381  {
382  $this->tpl->setCurrentBlock( "postpone_bottom" );
383  $this->tpl->setVariable( "CMD_POSTPONE", 'postponeQuestion' );
384  $this->tpl->setVariable( "BTN_POSTPONE", $this->lng->txt( "postpone" ) );
385  $this->tpl->parseCurrentBlock();
386  }
387 
388  protected function populateUpperPostponeButtonBlock()
389  {
390  $this->tpl->setCurrentBlock( "postpone" );
391  $this->tpl->setVariable( "CMD_POSTPONE", 'postponeQuestion' );
392  $this->tpl->setVariable( "BTN_POSTPONE", $this->lng->txt( "postpone" ) );
393  $this->tpl->parseCurrentBlock();
394  }
395 
397  {
399  'previousQuestion', $this->lng->txt( "save_previous" )
400  );
402  'previousQuestion', $this->lng->txt( "save_previous" )
403  );
404  }
405 
407  {
409  'previousQuestion', $this->getIntroductionPageButtonLabel()
410  );
412  'previousQuestion', $this->getIntroductionPageButtonLabel()
413  );
414  }
415 
416  protected function populateLowerPreviousButtonBlock($cmd, $label)
417  {
418  $this->tpl->setCurrentBlock( "prev_bottom" );
419  $this->tpl->setVariable("CMD_PREV", $cmd);
420  $this->tpl->setVariable("BTN_PREV", $label);
421  $this->tpl->parseCurrentBlock();
422  }
423 
424  protected function populateUpperPreviousButtonBlock($cmd, $label)
425  {
426  $this->tpl->setCurrentBlock( "prev" );
427  $this->tpl->setVariable("CMD_PREV", $cmd);
428  $this->tpl->setVariable("BTN_PREV", $label);
429  $this->tpl->parseCurrentBlock();
430  }
431 
432  protected function populateSpecificFeedbackBlock($question_gui)
433  {
434  $this->tpl->setCurrentBlock( "specific_feedback" );
435  $this->tpl->setVariable( "SPECIFIC_FEEDBACK",
436  $question_gui->getSpecificFeedbackOutput(
437  $this->testSession->getActiveId(),
438  NULL
439  )
440  );
441  $this->tpl->parseCurrentBlock();
442  }
443 
444  protected function populateGenericFeedbackBlock($question_gui)
445  {
446  $this->tpl->setCurrentBlock( "answer_feedback" );
447  $this->tpl->setVariable( "ANSWER_FEEDBACK",
448  $question_gui->getAnswerFeedbackOutput( $this->testSession->getActiveId(),
449  NULL
450  )
451  );
452  $this->tpl->parseCurrentBlock();
453  }
454 
455  protected function populateScoreBlock($reachedPoints, $maxPoints)
456  {
457  $scoreInformation = sprintf(
458  $this->lng->txt( "you_received_a_of_b_points" ), $reachedPoints, $maxPoints
459  );
460 
461  $this->tpl->setCurrentBlock( "received_points_information" );
462  $this->tpl->setVariable("RECEIVED_POINTS_INFORMATION", $scoreInformation);
463  $this->tpl->parseCurrentBlock();
464  }
465 
466  protected function populateSolutionBlock($solutionoutput)
467  {
468  $this->tpl->setCurrentBlock( "solution_output" );
469  $this->tpl->setVariable( "CORRECT_SOLUTION", $this->lng->txt( "tst_best_solution_is" ) );
470  $this->tpl->setVariable( "QUESTION_FEEDBACK", $solutionoutput );
471  $this->tpl->parseCurrentBlock();
472  }
473 
474  protected function populateCharSelector()
475  {
476  global $ilSetting;
477  if ($ilSetting->get('char_selector_availability') > 0)
478  {
479  require_once 'Services/UIComponent/CharSelector/classes/class.ilCharSelectorGUI.php';
480  $char_selector = ilCharSelectorGUI::_getCurrentGUI($this->object);
481  if ($char_selector->getConfig()->getAvailability() == ilCharSelectorConfig::ENABLED)
482  {
483  $char_selector->addToPage();
484  $this->tpl->setCurrentBlock('char_selector');
485  $this->tpl->setVariable("CHAR_SELECTOR_IMAGE", ilUtil::getImagePath('icon_omega_test.svg','Services/UIComponent/CharSelector'));
486  $this->tpl->setVariable("CHAR_SELECTOR_TEXT", $this->lng->txt('char_selector'));
487  $this->tpl->setVariable("CHAR_SELECTOR_TEMPLATE", $char_selector->getSelectorHtml());
488  $this->tpl->parseCurrentBlock();
489  }
490  }
491  }
492 
493  protected function showSideList()
494  {
495  global $ilUser;
496 
497  $show_side_list = $ilUser->getPref('side_list_of_questions');
498  $this->tpl->setCurrentBlock('view_sidelist');
499  $this->tpl->setVariable('IMAGE_SIDELIST',
500  ($show_side_list) ? ilUtil::getImagePath('view_remove.png'
501  ) : ilUtil::getImagePath('view_choose.png')
502  );
503  $this->tpl->setVariable('TEXT_SIDELIST',
504  ($show_side_list) ? $this->lng->txt('tst_hide_side_list'
505  ) : $this->lng->txt('tst_show_side_list')
506  );
507  $this->tpl->parseCurrentBlock();
508  if($show_side_list)
509  {
510  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "ta_split.css", "Modules/Test"), "screen");
511  $this->outQuestionSummaryCmd(false);
512  }
513  }
514 
515  protected function populateSyntaxStyleBlock()
516  {
517  $this->tpl->setCurrentBlock( "SyntaxStyle" );
518  $this->tpl->setVariable( "LOCATION_SYNTAX_STYLESHEET",
520  );
521  $this->tpl->parseCurrentBlock();
522  }
523 
524  protected function populateContentStyleBlock()
525  {
526  include_once("./Services/Style/classes/class.ilObjStyleSheet.php");
527  $this->tpl->setCurrentBlock( "ContentStyle" );
528  $this->tpl->setVariable( "LOCATION_CONTENT_STYLESHEET",
530  );
531  $this->tpl->parseCurrentBlock();
532  }
533 
539  public function setAnonymousIdCmd()
540  {
541  if( $this->testSession->isAnonymousUser() )
542  {
543  $this->testSession->setAccessCodeToSession($_POST['anonymous_id']);
544  }
545 
546  $this->ctrl->redirectByClass("ilobjtestgui", "infoScreen");
547  }
548 
555  protected function startPlayerCmd()
556  {
557  $testStartLock = $this->getLockParameter();
558  $isFirstTestStartRequest = false;
559 
560  $this->processLocker->requestTestStartLockCheckLock();
561 
562  if( $this->testSession->lookupTestStartLock() != $testStartLock )
563  {
564  $this->testSession->persistTestStartLock($testStartLock);
565  $isFirstTestStartRequest = true;
566  }
567 
568  $this->processLocker->releaseTestStartLockCheckLock();
569 
570  if( $isFirstTestStartRequest )
571  {
572  $this->handleUserSettings();
573  $this->ctrl->redirect($this, "initTest");
574  }
575 
576  $this->ctrl->setParameterByClass('ilObjTestGUI', 'lock', $testStartLock);
577  $this->ctrl->redirectByClass("ilobjtestgui", "redirectToInfoScreen");
578  }
579 
580  public function getLockParameter()
581  {
582  if( isset($_POST['lock']) && strlen($_POST['lock']) )
583  {
584  return $_POST['lock'];
585  }
586  elseif( isset($_GET['lock']) && strlen($_GET['lock']) )
587  {
588  return $_GET['lock'];
589  }
590 
591  return null;
592  }
593 
597  protected function resumePlayerCmd()
598  {
599  $this->handleUserSettings();
600 
601  $this->ctrl->setParameter($this, "activecommand", "resume");
602  $this->ctrl->redirect($this, "redirectQuestion");
603  }
604 
608  protected function initTestCmd()
609  {
610  if ($this->object->checkMaximumAllowedUsers() == FALSE)
611  {
613  }
614 
615  if( $this->testSession->isAnonymousUser() && !$this->testSession->getActiveId() )
616  {
617  $accessCode = $this->testSession->createNewAccessCode();
618 
619  $this->testSession->setAccessCodeToSession($accessCode);
620  $this->testSession->setAnonymousId($accessCode);
621  $this->testSession->saveToDb();
622 
623  $this->ctrl->redirect($this, 'displayCode');
624  }
625 
626  $this->ctrl->redirect($this, 'startTest');
627  }
628 
629  function displayCodeCmd()
630  {
631  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_anonymous_code_presentation.html", "Modules/Test");
632  $this->tpl->setCurrentBlock("adm_content");
633  $this->tpl->setVariable("TEXT_ANONYMOUS_CODE_CREATED", $this->lng->txt("tst_access_code_created"));
634  $this->tpl->setVariable("TEXT_ANONYMOUS_CODE", $this->testSession->getAccessCodeFromSession());
635  $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
636  $this->tpl->setVariable("CONTINUE", $this->lng->txt("continue_work"));
637  $this->tpl->parseCurrentBlock();
638  }
639 
640  function codeConfirmedCmd()
641  {
642  $this->ctrl->setParameter($this, "activecommand", "start");
643  $this->ctrl->redirect($this, "redirectQuestion");
644  }
645 
649  public function handleUserSettings()
650  {
651  global $ilUser;
652 
653  if ($_POST["chb_javascript"])
654  {
655  $ilUser->writePref("tst_javascript", 1);
656  }
657  else
658  {
659  $ilUser->writePref("tst_javascript", 0);
660  }
661 
662  // hide previous results
663  if ($this->object->getNrOfTries() != 1)
664  {
665  if ($this->object->getUsePreviousAnswers() == 1)
666  {
667  if ($_POST["chb_use_previous_answers"])
668  {
669  $ilUser->writePref("tst_use_previous_answers", 1);
670  }
671  else
672  {
673  $ilUser->writePref("tst_use_previous_answers", 0);
674  }
675  }
676  }
677  }
678 
682  public function calculateSequence()
683  {
684  $sequence = $_GET["sequence"];
685  if (!$sequence) $sequence = $this->testSequence->getFirstSequence();
686  if (array_key_exists("save_error", $_GET))
687  {
688  if ($_GET["save_error"] == 1)
689  {
690  return $sequence;
691  }
692  }
693  switch ($_GET["activecommand"])
694  {
695  case "next":
696  $sequence = $this->testSequence->getNextSequence($sequence);
697  break;
698  case "previous":
699  $sequence = $this->testSequence->getPreviousSequence($sequence);
700  break;
701  }
702  return $sequence;
703  }
704 
706  {
707  $active_id = $this->testSession->getActiveId();
708  $actualpass = $this->object->_getPass($active_id);
709 
710  $this->performTestPassFinishedTasks($actualpass);
711 
712  $this->testSession->setLastFinishedPass($this->testSession->getPass());
713  $this->testSession->increaseTestPass();
714 
715  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_redirect_autosave.html", "Modules/Test");
716  $this->tpl->setVariable("TEXT_REDIRECT", $this->lng->txt("redirectAfterSave"));
717  $this->tpl->setCurrentBlock("HeadContent");
718  $this->tpl->setVariable("CONTENT_BLOCK", "<meta http-equiv=\"refresh\" content=\"5; url=" . $this->ctrl->getLinkTarget($this, "afterTestPassFinished") . "\">");
719  $this->tpl->parseCurrentBlock();
720  }
721 
722  function autosaveCmd()
723  {
724  $result = "";
725  if (is_array($_POST) && count($_POST) > 0)
726  {
727  $res = $this->saveQuestionSolution(TRUE);
728  if ($res)
729  {
730  $result = $this->lng->txt("autosave_success");
731  }
732  else
733  {
734  $result = $this->lng->txt("autosave_failed");
735  }
736  }
737  if (!$this->canSaveResult())
738  {
739  // this was the last action in the test, saving is no longer allowed
740  $result = $this->ctrl->getLinkTarget($this, "redirectAfterAutosave", "", true);
741  }
742  echo $result;
743  exit;
744  }
745 
749  public function togglesidelistCmd()
750  {
751  global $ilUser;
752 
753  $show_side_list = $ilUser->getPref('side_list_of_questions');
754  $ilUser->writePref('side_list_of_questions', !$show_side_list);
755  $this->saveQuestionSolution();
756  $this->ctrl->redirect($this, "redirectQuestion");
757  }
758 
762  protected function markQuestionCmd()
763  {
764  $this->saveQuestionSolution();
765  $this->ctrl->setParameter($this, "activecommand", "setmarked");
766  $this->ctrl->redirect($this, "redirectQuestion");
767  }
768 
772  protected function unmarkQuestionCmd()
773  {
774  $this->saveQuestionSolution();
775  $this->ctrl->setParameter($this, "activecommand", "resetmarked");
776  $this->ctrl->redirect($this, "redirectQuestion");
777  }
778 
782  protected function gotoQuestionCmd()
783  {
784  if (is_array($_POST) && count($_POST) > 0) $this->saveQuestionSolution();
785  $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
786  $this->ctrl->setParameter($this, "activecommand", "gotoquestion");
787  $this->ctrl->saveParameter($this, "tst_javascript");
788  if (strlen($_GET['qst_selection'])) $_SESSION['qst_selection'] = $_GET['qst_selection'];
789  $this->ctrl->redirect($this, "redirectQuestion");
790  }
791 
797  public function backFromSummaryCmd()
798  {
799  $this->ctrl->setParameter($this, "activecommand", "back");
800  $this->ctrl->redirect($this, "redirectQuestion");
801  }
802 
806  protected function confirmFinishCmd()
807  {
808  $this->finishTestCmd(false);
809  }
810 
814  protected function confirmFinishTestCmd()
815  {
819  global $ilUser;
820 
821  require_once 'Services/Utilities/classes/class.ilConfirmationGUI.php';
822  $confirmation = new ilConfirmationGUI();
823  $confirmation->setFormAction($this->ctrl->getFormAction($this, 'confirmFinish'));
824  $confirmation->setHeaderText($this->lng->txt("tst_finish_confirmation_question"));
825  $confirmation->setConfirm($this->lng->txt("tst_finish_confirm_button"), 'confirmFinish');
826  $confirmation->setCancel($this->lng->txt("tst_finish_confirm_cancel_button"), 'backConfirmFinish');
827 
828  if($this->object->getKioskMode())
829  {
830  $this->tpl->addBlockfile($this->getContentBlockName(), 'content', "tpl.il_as_tst_kiosk_mode_content.html", "Modules/Test");
831  $this->tpl->setContent($confirmation->getHtml());
832  }
833  else
834  {
835  $this->tpl->setVariable($this->getContentBlockName(), $confirmation->getHtml());
836  }
837  }
838 
839  function finishTestCmd($requires_confirmation = true)
840  {
841  global $ilUser, $ilAuth;
842 
843  unset($_SESSION["tst_next"]);
844 
845  $active_id = $this->testSession->getActiveId();
846  $actualpass = $this->object->_getPass($active_id);
847 
848  $allObligationsAnswered = ilObjTest::allObligationsAnswered($this->testSession->getTestId(), $active_id, $actualpass);
849 
850  /*
851  * The following "endgames" are possible prior to actually finishing the test:
852  * - Obligations (Ability to finish the test.)
853  * If not all obligatory questions are answered, the user is presented a list
854  * showing the deficits.
855  * - Examview (Will to finish the test.)
856  * With the examview, the participant can review all answers given in ILIAS or a PDF prior to
857  * commencing to the finished test.
858  * - Last pass allowed (Reassuring the will to finish the test.)
859  * If passes are limited, on the last pass, an additional confirmation is to be displayed.
860  */
861 
862  // Obligations fulfilled? redirectQuestion : one or the other summary -> no finish
863  if( $this->object->areObligationsEnabled() && !$allObligationsAnswered )
864  {
865  if( $this->object->getListOfQuestions() )
866  {
867  $_GET['activecommand'] = 'summary_obligations';
868  }
869  else
870  {
871  $_GET['activecommand'] = 'summary_obligations_only';
872  }
873 
874  $this->redirectQuestionCmd();
875  return;
876  }
877 
878  // Examview enabled & !reviewed & requires_confirmation? test_submission_overview (review gui)
879  if ($this->object->getEnableExamview() && !isset($_GET['reviewed']) && $requires_confirmation)
880  {
881  $_GET['activecommand'] = 'test_submission_overview';
882  $this->redirectQuestionCmd();
883  return;
884  }
885 
886  // Last try in limited tries & !confirmed
887  if (($requires_confirmation) && ($actualpass == $this->object->getNrOfTries() - 1))
888  {
889  // show confirmation page
890  return $this->confirmFinishTestCmd();
891  }
892 
893  // Last try in limited tries & confirmed?
894  if(($actualpass == $this->object->getNrOfTries() - 1) && (!$requires_confirmation))
895  {
896  $ilAuth->setIdle(ilSession::getIdleValue(), false);
897  $ilAuth->setExpire(0);
898  switch($this->object->getMailNotification())
899  {
900  case 1:
901  $this->object->sendSimpleNotification($active_id);
902  break;
903  case 2:
904  $this->object->sendAdvancedNotification($active_id);
905  break;
906  }
907  }
908 
909  // Non-last try finish
910  if(!$_SESSION['tst_pass_finish'])
911  {
912  if(!$_SESSION['tst_pass_finish']) $_SESSION['tst_pass_finish'] = 1;
913  if($this->object->getMailNotificationType() == 1)
914  {
915  switch($this->object->getMailNotification())
916  {
917  case 1:
918  $this->object->sendSimpleNotification($active_id);
919  break;
920  case 2:
921  $this->object->sendAdvancedNotification($active_id);
922  break;
923  }
924  }
925  }
926 
927  // no redirect request loops after test pass finished tasks has been performed
928 
929  $this->performTestPassFinishedTasks($actualpass);
930 
931  $this->testSession->setLastFinishedPass($this->testSession->getPass());
932  $this->testSession->increaseTestPass();
933 
934  $this->ctrl->redirect($this, 'afterTestPassFinished');
935  }
936 
937  protected function performTestPassFinishedTasks($finishedPass)
938  {
939  if( !$this->testSession->isSubmitted() )
940  {
941  $this->testSession->setSubmitted(1);
942  $this->testSession->setSubmittedTimestamp(date('Y-m-d H:i:s'));
943  $this->testSession->saveToDb();
944  }
945 
946  if( $this->object->getEnableArchiving() )
947  {
948  $this->archiveParticipantSubmission($this->testSession->getActiveId(), $finishedPass);
949  }
950  }
951 
952  protected function afterTestPassFinishedCmd()
953  {
954  $activeId = $this->testSession->getActiveId();
955  $lastFinishedPass = $this->testSession->getLastFinishedPass();
956 
957  // handle test signature
958 
959  if ( $this->isTestSignRedirectRequired($activeId, $lastFinishedPass) )
960  {
961  $this->ctrl->redirectByClass('ilTestSignatureGUI', 'invokeSignaturePlugin');
962  }
963 
964  if(!$_GET['skipfinalstatement'])
965  {
966  if ($this->object->getShowFinalStatement())
967  {
968  $this->ctrl->redirect($this, 'showFinalStatement');
969  }
970  }
971 
972  // redirect after test
973  $redirection_mode = $this->object->getRedirectionMode();
974  $redirection_url = $this->object->getRedirectionUrl();
975  if( $redirection_url && $redirection_mode && !$this->object->canViewResults() )
976  {
977  if( $redirection_mode == REDIRECT_KIOSK )
978  {
979  if( $this->object->getKioskMode() )
980  {
981  ilUtil::redirect($redirection_url);
982  }
983  }
984  else
985  {
986  ilUtil::redirect($redirection_url);
987  }
988  }
989 
990  // custom after test redirect (ilTestOutput - objective oriented sessions)
991  if( $this->customRedirectRequired() )
992  {
993  $this->performCustomRedirect();
994  }
995 
996  // default redirect (pass results)
997  $this->redirectBackCmd();
998  }
999 
1000  protected function isTestSignRedirectRequired($activeId, $lastFinishedPass)
1001  {
1002  if( !$this->object->getSignSubmission() )
1003  {
1004  return false;
1005  }
1006 
1007  if( !is_null(ilSession::get("signed_{$activeId}_{$lastFinishedPass}")) )
1008  {
1009  return false;
1010  }
1011 
1012  global $ilPluginAdmin;
1013 
1014  $activePlugins = $ilPluginAdmin->getActivePluginsForSlot(IL_COMP_MODULE, 'Test', 'tsig');
1015 
1016  if( !count($activePlugins) )
1017  {
1018  return false;
1019  }
1020 
1021  return true;
1022  }
1023 
1029  protected function archiveParticipantSubmission( $active, $pass )
1030  {
1031  require_once 'class.ilTestEvaluationGUI.php';
1032  $testevaluationgui = new ilTestEvaluationGUI($this->object);
1033  $results = $this->object->getTestResult($active,$pass);
1034  $results_output = $testevaluationgui->getPassListOfAnswers($results, $active, $pass, false, false, false, false);
1035 
1036  require_once './Modules/Test/classes/class.ilTestArchiver.php';
1037  global $ilSetting;
1038  $inst_id = $ilSetting->get('inst_id', null);
1039  $archiver = new ilTestArchiver($this->object->getId());
1040 
1041  $path = ilUtil::getWebspaceDir() . '/assessment/'. $this->object->getId() . '/exam_pdf';
1042  if (!is_dir($path))
1043  {
1044  ilUtil::makeDirParents($path);
1045  }
1046  $filename = $path . '/exam_N' . $inst_id . '-' . $this->object->getId()
1047  . '-' . $active . '-' . $pass . '.pdf';
1048 
1049  require_once 'class.ilTestPDFGenerator.php';
1051  //$template->setVariable("PDF_FILE_LOCATION", $filename);
1052  // Participant submission
1053  $archiver->handInParticipantSubmission( $active, $pass, $filename, $results_output );
1054  //$archiver->handInParticipantMisc( $active, $pass, 'signature_gedoens.sig', $filename );
1055  //$archiver->handInParticipantQuestionMaterial( $active, $pass, 123, 'file_upload.pdf', $filename );
1056 
1057  global $ilias;
1058  $questions = $this->object->getQuestions();
1059  foreach ($questions as $question_id)
1060  {
1061  $question_object = $this->object->getQuestionDataset( $question_id );
1062  if ($question_object->type_tag == 'assFileUpload')
1063  {
1064  // Pfad: /data/default/assessment/tst_2/14/21/files/file_14_4_1370417414.png
1065  // /data/ - klar
1066  // /assessment/ - Konvention
1067  // /tst_2/ = /tst_<test_id> (ilObjTest)
1068  // /14/ = /<active_fi>/
1069  // /21/ = /<question_id>/ (question_object)
1070  // /files/ - Konvention
1071  // file_14_4_1370417414.png = file_<active_fi>_<pass>_<some timestamp>.<ext>
1072 
1073  $candidate_path =
1074  $ilias->ini_ilias->readVariable( 'server', 'absolute_path' ) . ilTestArchiver::DIR_SEP
1075  . $ilias->ini_ilias->readVariable( 'clients', 'path' ) . ilTestArchiver::DIR_SEP
1076  . $ilias->client_id . ilTestArchiver::DIR_SEP
1077  . 'assessment' . ilTestArchiver::DIR_SEP
1078  . 'tst_' . $this->object->test_id . ilTestArchiver::DIR_SEP
1079  . $active . ilTestArchiver::DIR_SEP
1080  . $question_id . ilTestArchiver::DIR_SEP
1081  . 'files' . ilTestArchiver::DIR_SEP;
1082  $handle = opendir( $candidate_path );
1083  while ($handle !== false && ($file = readdir( $handle )) !== false)
1084  {
1085  if ($file != null)
1086  {
1087  $filename_start = 'file_' . $active . '_' . $pass . '_';
1088 
1089  if (strpos( $file, $filename_start ) === 0)
1090  {
1091  $archiver->handInParticipantQuestionMaterial( $active, $pass, $question_id, $file, $file );
1092  }
1093  }
1094  }
1095  }
1096  }
1097  $passdata = $this->object->getTestResult($active, $pass);
1098  $overview = $testevaluationgui->getPassListOfAnswers($passdata, $active, $pass, true, false, false, true);
1099  $filename = ilUtil::getWebspaceDir() . '/assessment/scores-'.$this->object->getId() . '-' . $active . '-' . $pass . '.pdf';
1101  $archiver->handInTestResult($active, $pass, $filename);
1102  unlink($filename);
1103 
1104  return;
1105  }
1106 
1107  public function redirectBackCmd()
1108  {
1109  if(!$this->object->canViewResults())
1110  {
1111  $this->outIntroductionPageCmd();
1112  }
1113  else
1114  {
1115  $this->ctrl->redirectByClass("ilTestEvaluationGUI", "outUserResultsOverview");
1116  }
1117  }
1118 
1119  /*
1120  * Presents the final statement of a test
1121  */
1122  public function showFinalStatementCmd()
1123  {
1124  $template = new ilTemplate("tpl.il_as_tst_final_statement.html", TRUE, TRUE, "Modules/Test");
1125  $this->ctrl->setParameter($this, "skipfinalstatement", 1);
1126  $template->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "afterTestPassFinished"));
1127  $template->setVariable("FINALSTATEMENT", $this->object->prepareTextareaOutput($this->object->getFinalStatement(), true));
1128  $template->setVariable("BUTTON_CONTINUE", $this->lng->txt("btn_next"));
1129  $this->tpl->setVariable($this->getContentBlockName(), $template->get());
1130  }
1131 
1132  public function getKioskHead()
1133  {
1134  global $ilUser;
1135 
1136  $template = new ilTemplate('tpl.il_as_tst_kiosk_head.html', true, true, 'Modules/Test');
1137  if ($this->object->getShowKioskModeTitle())
1138  {
1139  $template->setCurrentBlock("kiosk_show_title");
1140  $template->setVariable("TEST_TITLE", $this->object->getTitle());
1141  $template->parseCurrentBlock();
1142  }
1143  if ($this->object->getShowKioskModeParticipant())
1144  {
1145  $template->setCurrentBlock("kiosk_show_participant");
1146  $template->setVariable("PARTICIPANT_NAME_TXT", $this->lng->txt("login_as"));
1147  $template->setVariable("PARTICIPANT_NAME", $ilUser->getFullname());
1148  $template->setVariable("PARTICIPANT_LOGIN", $ilUser->getLogin());
1149  $template->setVariable("PARTICIPANT_MATRICULATION", $ilUser->getMatriculation());
1150  $template->setVariable("PARTICIPANT_EMAIL", $ilUser->getEmail());
1151  $template->parseCurrentBlock();
1152  }
1153  if ($this->object->isShowExamIdInTestPassEnabled())
1154  {
1155  $exam_id = ilObjTest::buildExamId(
1156  $this->testSession->getActiveId() , $this->testSession->getPass(), $this->object->getId()
1157  );
1158 
1159  $template->setCurrentBlock("kiosk_show_exam_id");
1160  $template->setVariable("EXAM_ID_TXT", $this->lng->txt("exam_id"));
1161  $template->setVariable( "EXAM_ID", $exam_id);
1162  $template->parseCurrentBlock();
1163  }
1164  return $template->get();
1165  }
1166 
1170  function outTestPage($directfeedback)
1171  {
1172  global $rbacsystem, $ilUser;
1173 
1174  $this->prepareTestPageOutput();
1175 
1176  if (!$rbacsystem->checkAccess("read", $this->object->getRefId()))
1177  {
1178  // only with read access it is possible to run the test
1179  $this->ilias->raiseError($this->lng->txt("cannot_execute_test"),$this->ilias->error_obj->MESSAGE);
1180  }
1181 
1182  if ($this->isMaxProcessingTimeReached())
1183  {
1184  $this->maxProcessingTimeReached();
1185  return;
1186  }
1187 
1188  if ($this->object->endingTimeReached())
1189  {
1190  $this->endingTimeReached();
1191  return;
1192  }
1193 
1194  if ($this->object->getKioskMode())
1195  {
1196  $this->populateKioskHead();
1197  }
1198 
1199  $this->tpl->setVariable("TEST_ID", $this->object->getTestId());
1200  $this->tpl->setVariable("LOGIN", $ilUser->getLogin());
1201  $this->tpl->setVariable("SEQ_ID", $this->sequence);
1202  $this->tpl->setVariable("QUEST_ID", $this->testSequence->questions[$this->sequence]);
1203 
1204  if ($this->object->getEnableProcessingTime())
1205  {
1206  $this->outProcessingTime($this->testSession->getActiveId());
1207  }
1208 
1209  $this->tpl->setVariable("FORM_TIMESTAMP", time());
1210 
1211  $this->tpl->setVariable("PAGETITLE", "- " . $this->object->getTitle());
1212 
1213  $postpone = ( $this->object->getSequenceSettings() == TEST_POSTPONE );
1214 
1215  if ($this->object->isShowExamIdInTestPassEnabled() && !$this->object->getKioskMode())
1216  {
1217  $this->tpl->setCurrentBlock('exam_id_footer');
1218  $this->tpl->setVariable('EXAM_ID_VAL', ilObjTest::lookupExamId(
1219  $this->testSession->getActiveId(), $this->testSession->getPass(), $this->object->getId()
1220  ));
1221  $this->tpl->setVariable('EXAM_ID_TXT', $this->lng->txt('exam_id'));
1222  $this->tpl->parseCurrentBlock();
1223  }
1224 
1225  $this->outWorkingForm($this->sequence, $this->object->getTestId(), $postpone, $directfeedback);
1226  }
1227 
1236  {
1237  global $ilUser;
1238 
1239  // check if user is invited to participate
1240  $user = $this->object->getInvitedUsers($ilUser->getId());
1241  if (!is_array ($user) || count($user)!=1)
1242  {
1243  ilUtil::sendInfo($this->lng->txt("user_not_invited"), true);
1244  $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1245  }
1246 
1247  $user = array_pop($user);
1248  // check if client ip is set and if current remote addr is equal to stored client-ip
1249  if (strcmp($user["clientip"],"")!=0 && strcmp($user["clientip"],$_SERVER["REMOTE_ADDR"])!=0)
1250  {
1251  ilUtil::sendInfo($this->lng->txt("user_wrong_clientip"), true);
1252  $this->ctrl->redirectByClass("ilobjtestgui", "backToRepository");
1253  }
1254  }
1255 
1256 
1260  function isTestAccessible()
1261  {
1262  return !$this->isNrOfTriesReached()
1263  and !$this->isMaxProcessingTimeReached()
1264  and $this->object->startingTimeReached()
1265  and !$this->object->endingTimeReached();
1266  }
1267 
1272  {
1273  return $this->object->hasNrOfTriesRestriction() && $this->object->isNrOfTriesReached($this->testSession->getPass());
1274  }
1275 
1283  function passDetails()
1284  {
1285  if (array_key_exists("pass", $_GET) && (strlen($_GET["pass"]) > 0))
1286  {
1287  $this->ctrl->saveParameter($this, "pass");
1288  $this->ctrl->saveParameter($this, "active_id");
1289  $this->outTestResults(false, $_GET["pass"]);
1290  }
1291  else
1292  {
1293  $this->outTestResults(false);
1294  }
1295  }
1296 
1302  function endingTimeReached()
1303  {
1304  ilUtil::sendInfo(sprintf($this->lng->txt("detail_ending_time_reached"), ilFormat::ftimestamp2datetimeDB($this->object->getEndingTime())));
1305  $this->testSession->increasePass();
1306  $this->testSession->setLastSequence(0);
1307  $this->testSession->saveToDb();
1308  if (!$this->object->canViewResults())
1309  {
1310  $this->outIntroductionPage();
1311  }
1312  else
1313  {
1314  $this->ctrl->redirectByClass("ilTestEvaluationGUI", "outUserResultsOverview");
1315  }
1316  }
1317 
1326  {
1327  $this->outIntroductionPage();
1328  }
1329 
1336  {
1337  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_submit_answers_confirm.html", "Modules/Test");
1338  $this->tpl->setCurrentBlock("adm_content");
1339  if ($this->object->isTestFinished($this->testSession->getActiveId()))
1340  {
1341  $this->tpl->setCurrentBlock("not_submit_allowed");
1342  $this->tpl->setVariable("TEXT_ALREADY_SUBMITTED", $this->lng->txt("tst_already_submitted"));
1343  $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_show_answer_sheet"));
1344  } else
1345  {
1346  $this->tpl->setCurrentBlock("submit_allowed");
1347  $this->tpl->setVariable("TEXT_CONFIRM_SUBMIT_RESULTS", $this->lng->txt("tst_confirm_submit_answers"));
1348  $this->tpl->setVariable("BTN_OK", $this->lng->txt("tst_submit_results"));
1349  }
1350  $this->tpl->setVariable("BTN_BACK", $this->lng->txt("back"));
1351  $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this, "finalSubmission"));
1352  $this->tpl->parseCurrentBlock();
1353  }
1354 
1355  function outProcessingTime($active_id)
1356  {
1357  global $ilUser;
1358 
1359  $starting_time = $this->object->getStartingTimeOfUser($active_id);
1360  $processing_time = $this->object->getProcessingTimeInSeconds($active_id);
1361  $processing_time_minutes = floor($processing_time / 60);
1362  $processing_time_seconds = $processing_time - $processing_time_minutes * 60;
1363  $str_processing_time = "";
1364  if ($processing_time_minutes > 0)
1365  {
1366  $str_processing_time = $processing_time_minutes . " " . ($processing_time_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1367  }
1368  if ($processing_time_seconds > 0)
1369  {
1370  if (strlen($str_processing_time) > 0) $str_processing_time .= " " . $this->lng->txt("and") . " ";
1371  $str_processing_time .= $processing_time_seconds . " " . ($processing_time_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1372  }
1373  $time_left = $starting_time + $processing_time - mktime();
1374  $time_left_minutes = floor($time_left / 60);
1375  $time_left_seconds = $time_left - $time_left_minutes * 60;
1376  $str_time_left = "";
1377  if ($time_left_minutes > 0)
1378  {
1379  $str_time_left = $time_left_minutes . " " . ($time_left_minutes == 1 ? $this->lng->txt("minute") : $this->lng->txt("minutes"));
1380  }
1381  if ($time_left < 300)
1382  {
1383  if ($time_left_seconds > 0)
1384  {
1385  if (strlen($str_time_left) > 0) $str_time_left .= " " . $this->lng->txt("and") . " ";
1386  $str_time_left .= $time_left_seconds . " " . ($time_left_seconds == 1 ? $this->lng->txt("second") : $this->lng->txt("seconds"));
1387  }
1388  }
1389  $date = getdate($starting_time);
1390  $formattedStartingTime = ilDatePresentation::formatDate(new ilDateTime($date,IL_CAL_FKT_GETDATE));
1391  /*
1392  $formattedStartingTime = ilFormat::formatDate(
1393  $date["year"]."-".
1394  sprintf("%02d", $date["mon"])."-".
1395  sprintf("%02d", $date["mday"])." ".
1396  sprintf("%02d", $date["hours"]).":".
1397  sprintf("%02d", $date["minutes"]).":".
1398  sprintf("%02d", $date["seconds"])
1399  );
1400  */
1401  $datenow = getdate();
1402  $this->tpl->setCurrentBlock("enableprocessingtime");
1403  $this->tpl->setVariable("USER_WORKING_TIME",
1404  sprintf(
1405  $this->lng->txt("tst_time_already_spent"),
1406  $formattedStartingTime,
1407  $str_processing_time
1408  )
1409  );
1410  $this->tpl->setVariable("USER_REMAINING_TIME", sprintf($this->lng->txt("tst_time_already_spent_left"), $str_time_left));
1411  $this->tpl->parseCurrentBlock();
1412  $template = new ilTemplate("tpl.workingtime.js.html", TRUE, TRUE, 'Modules/Test');
1413  $template->setVariable("STRING_MINUTE", $this->lng->txt("minute"));
1414  $template->setVariable("STRING_MINUTES", $this->lng->txt("minutes"));
1415  $template->setVariable("STRING_SECOND", $this->lng->txt("second"));
1416  $template->setVariable("STRING_SECONDS", $this->lng->txt("seconds"));
1417  $template->setVariable("STRING_TIMELEFT", $this->lng->txt("tst_time_already_spent_left"));
1418  $template->setVariable("AND", strtolower($this->lng->txt("and")));
1419  $template->setVariable("YEAR", $date["year"]);
1420  $template->setVariable("MONTH", $date["mon"]-1);
1421  $template->setVariable("DAY", $date["mday"]);
1422  $template->setVariable("HOUR", $date["hours"]);
1423  $template->setVariable("MINUTE", $date["minutes"]);
1424  $template->setVariable("SECOND", $date["seconds"]);
1425  if ($this->object->isEndingTimeEnabled() && preg_match("/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/", $this->object->getEndingTime(), $matches))
1426  {
1427  $template->setVariable("ENDYEAR", $matches[1]);
1428  $template->setVariable("ENDMONTH", $matches[2]-1);
1429  $template->setVariable("ENDDAY", $matches[3]);
1430  $template->setVariable("ENDHOUR", $matches[4]);
1431  $template->setVariable("ENDMINUTE", $matches[5]);
1432  $template->setVariable("ENDSECOND", $matches[6]);
1433  }
1434  $template->setVariable("YEARNOW", $datenow["year"]);
1435  $template->setVariable("MONTHNOW", $datenow["mon"]-1);
1436  $template->setVariable("DAYNOW", $datenow["mday"]);
1437  $template->setVariable("HOURNOW", $datenow["hours"]);
1438  $template->setVariable("MINUTENOW", $datenow["minutes"]);
1439  $template->setVariable("SECONDNOW", $datenow["seconds"]);
1440  $template->setVariable("PTIME_M", $processing_time_minutes);
1441  $template->setVariable("PTIME_S", $processing_time_seconds);
1442 
1443  $this->tpl->setCurrentBlock("HeadContent");
1444  $this->tpl->setVariable("CONTENT_BLOCK", $template->get());
1445  $this->tpl->parseCurrentBlock();
1446  }
1447 
1451  public function outQuestionSummaryCmd($fullpage = true, $contextFinishTest = false, $obligationsNotAnswered = false, $obligationsFilter = false)
1452  {
1453  if( $fullpage )
1454  {
1455  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_question_summary.html", "Modules/Test");
1456  }
1457 
1458  if( $obligationsNotAnswered )
1459  {
1460  ilUtil::sendFailure($this->lng->txt('not_all_obligations_answered'));
1461  }
1462 
1463  $active_id = $this->testSession->getActiveId();
1464  $result_array = & $this->testSequence->getSequenceSummary($obligationsFilter);
1465 
1466  $marked_questions = array();
1467 
1468  if( $this->object->getKioskMode() && $fullpage )
1469  {
1470  $head = $this->getKioskHead();
1471  if( strlen($head) )
1472  {
1473  $this->tpl->setCurrentBlock("kiosk_options");
1474  $this->tpl->setVariable("KIOSK_HEAD", $head);
1475  $this->tpl->parseCurrentBlock();
1476  }
1477  }
1478 
1479  if( $this->object->getShowMarker() )
1480  {
1481  include_once "./Modules/Test/classes/class.ilObjTest.php";
1482  $marked_questions = ilObjTest::_getSolvedQuestions($active_id);
1483  }
1484 
1485  $data = array();
1486 
1487  foreach( $result_array as $key => $value )
1488  {
1489  $this->ctrl->setParameter($this, "sequence", $value["sequence"]);
1490 
1491  $href = $this->ctrl->getLinkTargetByClass(get_class($this), "gotoQuestion");
1492 
1493  $this->tpl->setVariable("VALUE_QUESTION_TITLE", "<a href=\"".$this->ctrl->getLinkTargetByClass(get_class($this), "gotoQuestion")."\">" . $this->object->getQuestionTitle($value["title"]) . "</a>");
1494 
1495  $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
1496 
1497  $description = "";
1498  if( $this->object->getListOfQuestionsDescription() )
1499  {
1500  $description = $value["description"];
1501  }
1502 
1503  $points = "";
1504  if( !$this->object->getTitleOutput() )
1505  {
1506  $points = $value["points"]."&nbsp;".$this->lng->txt("points_short");
1507  }
1508 
1509  $marked = false;
1510  if( count($marked_questions) )
1511  {
1512  if( array_key_exists($value["qid"], $marked_questions) )
1513  {
1514  $obj = $marked_questions[$value["qid"]];
1515  if( $obj["solved"] == 1 )
1516  {
1517  $marked = true;
1518  }
1519  }
1520  }
1521 
1522  array_push($data, array(
1523  'order' => $value["nr"],
1524  'href' => $href,
1525  'title' => $this->object->getQuestionTitle($value["title"]),
1526  'description' => $description,
1527  'worked_through' => ($value["worked_through"]) ? true : false,
1528  'postponed' => ($value["postponed"]) ? $this->lng->txt("postponed") : '',
1529  'points' => $points,
1530  'marked' => $marked,
1531  'sequence' => $value["sequence"],
1532  'obligatory' => $value['obligatory'],
1533  'isAnswered' => $value['isAnswered']
1534  ));
1535  }
1536 
1537  $this->ctrl->setParameter($this, "sequence", $_GET["sequence"]);
1538 
1539  if( $fullpage )
1540  {
1541  include_once "./Modules/Test/classes/tables/class.ilListOfQuestionsTableGUI.php";
1542  $table_gui = new ilListOfQuestionsTableGUI($this, 'backFromSummary');
1543 
1544  $table_gui->setShowPointsEnabled( !$this->object->getTitleOutput() );
1545  $table_gui->setShowMarkerEnabled( $this->object->getShowMarker() );
1546  $table_gui->setObligationsNotAnswered( $obligationsNotAnswered );
1547  $table_gui->setShowObligationsEnabled( $this->object->areObligationsEnabled() );
1548  $table_gui->setObligationsFilterEnabled( $obligationsFilter );
1549 
1550  $table_gui->init();
1551 
1552  $table_gui->setData($data);
1553 
1554  $this->tpl->setVariable('TABLE_LIST_OF_QUESTIONS', $table_gui->getHTML());
1555 
1556  if( $this->object->getEnableProcessingTime() )
1557  {
1558  $this->outProcessingTime($active_id);
1559  }
1560  }
1561  else
1562  {
1563  $template = new ilTemplate('tpl.il_as_tst_list_of_questions_short.html', true, true, 'Modules/Test');
1564 
1565  foreach( $data as $row )
1566  {
1567  if( strlen($row['description']) )
1568  {
1569  $template->setCurrentBlock('description');
1570  $template->setVariable("DESCRIPTION", $row['description']);
1571  $template->parseCurrentBlock();
1572  }
1573 
1574  $active = ($row['sequence'] == $this->sequence) ? ' active' : '';
1575 
1576  $template->setCurrentBlock('item');
1577  $template->setVariable('CLASS', ($row['walked_through']) ? ('answered'.$active) : ('unanswered'.$active));
1578  $template->setVariable('ITEM', ilUtil::prepareFormOutput($row['title']));
1579  $template->setVariable('SEQUENCE', $row['sequence']);
1580  $template->parseCurrentBlock();
1581  }
1582 
1583  require_once 'Services/UIComponent/Panel/classes/class.ilPanelGUI.php';
1584  $panel = ilPanelGUI::getInstance();
1585  $panel->setHeadingStyle(ilPanelGUI::HEADING_STYLE_SUBHEADING);
1586  $panel->setPanelStyle(ilPanelGUI::PANEL_STYLE_SECONDARY);
1587  $panel->setHeading($this->lng->txt('list_of_questions'));
1588  $panel->setBody($template->get());
1589 
1590  $this->tpl->setVariable('LIST_OF_QUESTIONS', $panel->getHTML());
1591  }
1592  }
1593 
1595  {
1596  return $this->outQuestionSummaryCmd(true, true, true, false);
1597  }
1598 
1600  {
1601  return $this->outQuestionSummaryCmd(true, true, true, true);
1602  }
1603 
1605  {
1606  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_max_allowed_users_reached.html", "Modules/Test");
1607  $this->tpl->setCurrentBlock("adm_content");
1608  $this->tpl->setVariable("MAX_ALLOWED_USERS_MESSAGE", sprintf($this->lng->txt("tst_max_allowed_users_message"), $this->object->getAllowedUsersTimeGap()));
1609  $this->tpl->setVariable("MAX_ALLOWED_USERS_HEADING", sprintf($this->lng->txt("tst_max_allowed_users_heading"), $this->object->getAllowedUsersTimeGap()));
1610  $this->tpl->setVariable("BACK_TO_INTRODUCTION", $this->lng->txt("tst_results_back_introduction"));
1611  $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1612  $this->tpl->parseCurrentBlock();
1613  }
1614 
1616  {
1617  $this->ctrl->redirect($this, 'gotoQuestion');
1618  }
1619 
1626  {
1627  $this->tpl->addBlockFile("ADM_CONTENT", "adm_content", "tpl.il_as_tst_correct_solution.html", "Modules/Test");
1628 
1629  include_once("./Services/Style/classes/class.ilObjStyleSheet.php");
1630  $this->tpl->setCurrentBlock("ContentStyle");
1631  $this->tpl->setVariable("LOCATION_CONTENT_STYLESHEET", ilObjStyleSheet::getContentStylePath(0));
1632  $this->tpl->parseCurrentBlock();
1633 
1634  $this->tpl->setCurrentBlock("SyntaxStyle");
1635  $this->tpl->setVariable("LOCATION_SYNTAX_STYLESHEET", ilObjStyleSheet::getSyntaxStylePath());
1636  $this->tpl->parseCurrentBlock();
1637 
1638  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1639  if ($this->object->getShowSolutionAnswersOnly())
1640  {
1641  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1642  }
1643 
1644  $this->tpl->setCurrentBlock("adm_content");
1645  $solution = $this->getCorrectSolutionOutput($_GET["evaluation"], $_GET["active_id"], $_GET["pass"]);
1646  $this->tpl->setVariable("OUTPUT_SOLUTION", $solution);
1647  $this->tpl->setVariable("TEXT_BACK", $this->lng->txt("back"));
1648  $this->ctrl->saveParameter($this, "pass");
1649  $this->ctrl->saveParameter($this, "active_id");
1650  $this->tpl->setVariable("URL_BACK", $this->ctrl->getLinkTarget($this, "outUserResultsOverview"));
1651  $this->tpl->parseCurrentBlock();
1652  }
1653 
1663  function showListOfAnswers($active_id, $pass = NULL, $top_data = "", $bottom_data = "")
1664  {
1665  global $ilUser;
1666 
1667  $this->tpl->addBlockFile($this->getContentBlockName(), "adm_content", "tpl.il_as_tst_finish_list_of_answers.html", "Modules/Test");
1668 
1669  $result_array =& $this->object->getTestResult($active_id, $pass);
1670 
1671  $counter = 1;
1672  // output of questions with solutions
1673  foreach ($result_array as $question_data)
1674  {
1675  $question = $question_data["qid"];
1676  if (is_numeric($question))
1677  {
1678  $this->tpl->setCurrentBlock("printview_question");
1679  $question_gui = $this->object->createQuestionGUI("", $question);
1680  $template = new ilTemplate("tpl.il_as_qpl_question_printview.html", TRUE, TRUE, "Modules/TestQuestionPool");
1681  $template->setVariable("COUNTER_QUESTION", $counter.". ");
1682  $template->setVariable("QUESTION_TITLE", $question_gui->object->getTitle());
1683 
1684  $show_question_only = ($this->object->getShowSolutionAnswersOnly()) ? TRUE : FALSE;
1685  $result_output = $question_gui->getSolutionOutput($active_id, $pass, FALSE, FALSE, $show_question_only, $this->object->getShowSolutionFeedback());
1686  $template->setVariable("SOLUTION_OUTPUT", $result_output);
1687  $this->tpl->setVariable("QUESTION_OUTPUT", $template->get());
1688  $this->tpl->parseCurrentBlock();
1689  $counter ++;
1690  }
1691  }
1692 
1693  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print.css", "Modules/Test"), "print");
1694  if ($this->object->getShowSolutionAnswersOnly())
1695  {
1696  $this->tpl->addCss(ilUtil::getStyleSheetLocation("output", "test_print_hide_content.css", "Modules/Test"), "print");
1697  }
1698  if (strlen($top_data))
1699  {
1700  $this->tpl->setCurrentBlock("top_data");
1701  $this->tpl->setVariable("TOP_DATA", $top_data);
1702  $this->tpl->parseCurrentBlock();
1703  }
1704 
1705  if (strlen($bottom_data))
1706  {
1707  $this->tpl->setCurrentBlock("bottom_data");
1708  $this->tpl->setVariable("FORMACTION", $this->ctrl->getFormAction($this));
1709  $this->tpl->setVariable("BOTTOM_DATA", $bottom_data);
1710  $this->tpl->parseCurrentBlock();
1711  }
1712 
1713  $this->tpl->setCurrentBlock("adm_content");
1714  $this->tpl->setVariable("TXT_ANSWER_SHEET", $this->lng->txt("tst_list_of_answers"));
1715  $user_data = $this->getResultsUserdata($this->testSession, $active_id, TRUE);
1716  $signature = $this->getResultsSignature();
1717  $this->tpl->setVariable("USER_DETAILS", $user_data);
1718  $this->tpl->setVariable("SIGNATURE", $signature);
1719  $this->tpl->setVariable("TITLE", $this->object->getTitle());
1720  $this->tpl->setVariable("TXT_TEST_PROLOG", $this->lng->txt("tst_your_answers"));
1721  $invited_user =& $this->object->getInvitedUsers($ilUser->getId());
1722  $pagetitle = $this->object->getTitle() . " - " . $this->lng->txt("clientip") .
1723  ": " . $invited_user[$ilUser->getId()]["clientip"] . " - " .
1724  $this->lng->txt("matriculation") . ": " .
1725  $invited_user[$ilUser->getId()]["matriculation"];
1726  $this->tpl->setVariable("PAGETITLE", $pagetitle);
1727  $this->tpl->parseCurrentBlock();
1728  }
1729 
1735  public function getContentBlockName()
1736  {
1737  if ($this->object->getKioskMode())
1738  {
1739  $this->tpl->setBodyClass("kiosk");
1740  $this->tpl->setAddFooter(FALSE);
1741  return "CONTENT";
1742  }
1743  else
1744  {
1745  return "ADM_CONTENT";
1746  }
1747  }
1748 
1750  {
1751  $this->ctrl->redirectByClass(
1752  array('ilRepositoryGUI', 'ilObjTestGUI', 'ilTestEvaluationGUI'), "outUserResultsOverview"
1753  );
1754  }
1755 
1757  {
1758  $this->ctrl->redirectByClass(
1759  array('ilRepositoryGUI', 'ilObjTestGUI', 'ilTestEvaluationGUI'), "outUserListOfAnswerPasses"
1760  );
1761  }
1762 
1766  protected function showRequestedHintListCmd()
1767  {
1768  $this->saveQuestionSolution();
1769 
1770  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1771  $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_SHOW_LIST);
1772  }
1773 
1777  protected function confirmHintRequestCmd()
1778  {
1779  $this->saveQuestionSolution();
1780 
1781  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintRequestGUI.php';
1782  $this->ctrl->redirectByClass('ilAssQuestionHintRequestGUI', ilAssQuestionHintRequestGUI::CMD_CONFIRM_REQUEST);
1783  }
1784 
1793  protected function fillQuestionRelatedNavigation(assQuestionGUI $questionGUI)
1794  {
1795  global $tpl, $lng;
1796 
1797  $parseQuestionRelatedNavigation = false;
1798 
1799  switch( 1 )
1800  {
1801  case $this->object->getSpecificAnswerFeedback():
1802  case $this->object->getGenericAnswerFeedback():
1803  case $this->object->getAnswerFeedbackPoints():
1804  case $this->object->getInstantFeedbackSolution():
1805 
1806  $tpl->setCurrentBlock("direct_feedback");
1807  $tpl->setVariable("CMD_SHOW_INSTANT_RESPONSE", 'showInstantResponse');
1808  $tpl->setVariable("TEXT_SHOW_INSTANT_RESPONSE", $lng->txt("check"));
1809  $tpl->parseCurrentBlock();
1810 
1811  $parseQuestionRelatedNavigation = true;
1812  }
1813 
1814  if( $this->object->isOfferingQuestionHintsEnabled() )
1815  {
1816  $questionId = $questionGUI->object->getId();
1817  $activeId = $this->testSession->getActiveId();
1818  $pass = $this->testSession->getPass();
1819 
1820  require_once 'Modules/TestQuestionPool/classes/class.ilAssQuestionHintTracking.php';
1821  $questionHintTracking = new ilAssQuestionHintTracking($questionId, $activeId, $pass);
1822 
1823  $requestsExist = $questionHintTracking->requestsExist();
1824  $requestsPossible = $questionHintTracking->requestsPossible();
1825 
1826  if( $requestsPossible )
1827  {
1828  if( $requestsExist )
1829  {
1830  $buttonText = $lng->txt("button_request_next_question_hint");
1831  }
1832  else
1833  {
1834  $buttonText = $lng->txt("button_request_question_hint");
1835  }
1836 
1837  $tpl->setCurrentBlock("button_request_next_question_hint");
1838  $tpl->setVariable("CMD_REQUEST_NEXT_QUESTION_HINT", 'confirmHintRequest');
1839  $tpl->setVariable("TEXT_REQUEST_NEXT_QUESTION_HINT", $buttonText);
1840  $tpl->parseCurrentBlock();
1841 
1842  $parseQuestionRelatedNavigation = true;
1843  }
1844 
1845  if( $requestsExist )
1846  {
1847  $tpl->setCurrentBlock("button_show_requested_question_hints");
1848  $tpl->setVariable("CMD_SHOW_REQUESTED_QUESTION_HINTS", 'showRequestedHintList');
1849  $tpl->setVariable("TEXT_SHOW_REQUESTED_QUESTION_HINTS", $lng->txt("button_show_requested_question_hints"));
1850  $tpl->parseCurrentBlock();
1851 
1852  $parseQuestionRelatedNavigation = true;
1853  }
1854  }
1855 
1856  if( $parseQuestionRelatedNavigation )
1857  {
1858  $tpl->setCurrentBlock("question_related_navigation");
1859  $tpl->parseCurrentBlock();
1860  }
1861  }
1862 
1863  abstract protected function isFirstPageInSequence($sequence);
1864 
1865  abstract protected function isLastQuestionInSequence(assQuestionGUI $questionGUI);
1866 
1867 
1868  abstract protected function handleQuestionActionCmd();
1869 
1870  abstract protected function showInstantResponseCmd();
1871 
1872  abstract protected function nextQuestionCmd();
1873 
1874  abstract protected function previousQuestionCmd();
1875 
1876  abstract protected function postponeQuestionCmd();
1877 
1878 
1879 
1880  protected function getMarkedQuestions()
1881  {
1882  if( $this->object->getShowMarker() )
1883  {
1884  include_once "./Modules/Test/classes/class.ilObjTest.php";
1885  $marked_questions = ilObjTest::_getSolvedQuestions($this->testSession->getActiveId());
1886  }
1887  else
1888  {
1889  $marked_questions = array();
1890  }
1891 
1892  return $marked_questions;
1893  }
1894 
1895  protected function prepareSummaryPage()
1896  {
1897  $this->tpl->addBlockFile(
1898  $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_question_summary.html', 'Modules/Test'
1899  );
1900 
1901  if ($this->object->getShowCancel())
1902  {
1903  $this->populateCancelButtonBlock();
1904  }
1905 
1906  if ($this->object->getKioskMode())
1907  {
1908  $this->populateKioskHead();
1909  }
1910  }
1911 
1912  protected function prepareTestPageOutput()
1913  {
1914  $this->tpl->addBlockFile(
1915  $this->getContentBlockName(), 'adm_content', 'tpl.il_as_tst_output.html', 'Modules/Test'
1916  );
1917  }
1918 
1919  protected function populateKioskHead()
1920  {
1921  ilUtil::sendInfo(); // ???
1922 
1923  $head = $this->getKioskHead();
1924 
1925  if (strlen($head))
1926  {
1927  $this->tpl->setCurrentBlock("kiosk_options");
1928  $this->tpl->setVariable("KIOSK_HEAD", $head);
1929  $this->tpl->parseCurrentBlock();
1930  }
1931  }
1932 
1934  {
1935  if( $this->ctrl->getNextClass() == 'iltestpasswordprotectiongui' )
1936  {
1937  return;
1938  }
1939 
1940  if( !$this->passwordChecker->isPasswordProtectionPageRedirectRequired() )
1941  {
1942  return;
1943  }
1944 
1945  $this->ctrl->setParameter($this, 'lock', $this->getLockParameter());
1946 
1947  $nextCommand = $this->ctrl->getCmdClass().'::'.$this->ctrl->getCmd();
1948  $this->ctrl->setParameterByClass('ilTestPasswordProtectionGUI', 'nextCommand', $nextCommand);
1949  $this->ctrl->redirectByClass('ilTestPasswordProtectionGUI', 'showPasswordForm');
1950  }
1951 
1952  protected function isParticipantsAnswerFixed($questionId)
1953  {
1954  if( !$this->object->isInstantFeedbackAnswerFixationEnabled() )
1955  {
1956  return false;
1957  }
1958 
1959  if( !$this->testSequence->isQuestionChecked($questionId) )
1960  {
1961  return false;
1962  }
1963 
1964  return true;
1965  }
1966 
1967  protected function customRedirectRequired()
1968  {
1969  return false;
1970  }
1971 
1972  protected function performCustomRedirect()
1973  {
1974  return;
1975  }
1976 
1980  protected function getIntroductionPageButtonLabel()
1981  {
1982  if( $this->testSession->isObjectiveOriented() )
1983  {
1984  return $this->lng->txt("save_back_to_objective_container");
1985  }
1986 
1987  return $this->lng->txt("save_introduction");
1988  }
1989 }