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