2021-10-26 09:23:06 +02:00
|
|
|
|
// swad_test_print.c: test prints made by users
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
SWAD (Shared Workspace At a Distance),
|
|
|
|
|
is a web platform developed at the University of Granada (Spain),
|
|
|
|
|
and used to support university teaching.
|
|
|
|
|
|
|
|
|
|
This file is part of SWAD core.
|
2021-02-09 12:43:45 +01:00
|
|
|
|
Copyright (C) 1999-2021 Antonio Ca<EFBFBD>as Vargas
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU Affero General Public License as
|
|
|
|
|
published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
*/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********************************** Headers *********************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#define _GNU_SOURCE // For asprintf
|
2021-11-26 01:53:31 +01:00
|
|
|
|
#include <math.h> // For fabs
|
2020-04-02 03:28:08 +02:00
|
|
|
|
#include <stdbool.h> // For boolean type
|
|
|
|
|
#include <stddef.h> // For NULL
|
|
|
|
|
#include <stdio.h> // For asprintf
|
|
|
|
|
#include <stdlib.h> // For free
|
|
|
|
|
#include <string.h> // For string functions
|
|
|
|
|
|
|
|
|
|
#include "swad_action.h"
|
|
|
|
|
#include "swad_database.h"
|
2021-04-26 15:27:27 +02:00
|
|
|
|
#include "swad_error.h"
|
2020-04-02 03:28:08 +02:00
|
|
|
|
#include "swad_form.h"
|
|
|
|
|
#include "swad_global.h"
|
|
|
|
|
#include "swad_HTML.h"
|
|
|
|
|
#include "swad_ID.h"
|
2020-04-14 17:15:17 +02:00
|
|
|
|
#include "swad_photo.h"
|
2021-10-25 10:24:43 +02:00
|
|
|
|
#include "swad_question.h"
|
2021-10-27 21:40:19 +02:00
|
|
|
|
#include "swad_question_database.h"
|
2020-04-02 03:28:08 +02:00
|
|
|
|
#include "swad_test.h"
|
2021-10-26 09:23:06 +02:00
|
|
|
|
#include "swad_test_database.h"
|
2020-05-07 18:33:26 +02:00
|
|
|
|
#include "swad_test_print.h"
|
2020-04-02 03:28:08 +02:00
|
|
|
|
#include "swad_test_visibility.h"
|
|
|
|
|
#include "swad_user.h"
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************************* Private types *******************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-06-23 18:10:20 +02:00
|
|
|
|
struct TstRes_ICanView
|
|
|
|
|
{
|
|
|
|
|
bool Result;
|
|
|
|
|
bool Score;
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************** External global variables from others modules ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
extern struct Globals Gbl;
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************************** Private prototypes ****************************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-11 02:28:38 +02:00
|
|
|
|
static void TstPrn_ResetPrintExceptPrnCod (struct TstPrn_Print *Print);
|
2020-04-16 21:03:22 +02:00
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteQstAndAnsToFill (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteAnswersToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
static void TstPrn_WriteIntAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteFltAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteTF_AnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteChoAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static void TstPrn_WriteTxtAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
static void TstPrn_PutCheckBoxAllowTeachers (bool AllowTeachers);
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
struct TstPrn_PrintedQuestion PrintedQuestions[TstCfg_MAX_QUESTIONS_PER_TEST],
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
time_t TimeUTC[Dat_NUM_START_END_TIME],
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-05-07 19:54:24 +02:00
|
|
|
|
bool QuestionExists,
|
2020-04-03 19:13:00 +02:00
|
|
|
|
unsigned Visibility);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question);
|
2020-05-16 02:04:36 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteIntAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback);
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteFltAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback);
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteTF_AnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback);
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteChoAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
const char *ClassTxt,
|
|
|
|
|
const char *ClassFeedback);
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteTxtAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback);
|
2020-05-16 02:04:36 +02:00
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
static void TstPrn_WriteHeadUserCorrect (struct UsrData *UsrDat);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_PutFormToSelectUsrsToViewUsrsPrints (__attribute__((unused)) void *Args);
|
2020-04-09 21:36:21 +02:00
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_ShowUsrsPrints (__attribute__((unused)) void *Args);
|
2020-06-24 20:10:57 +02:00
|
|
|
|
static void TstPrn_ShowHeaderPrints (Usr_MeOrOther_t MeOrOther);
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat);
|
|
|
|
|
static void TstPrn_ShowPrintsSummaryRow (bool ItsMe,
|
|
|
|
|
unsigned NumPrints,
|
2020-06-24 02:15:50 +02:00
|
|
|
|
struct TstPrn_NumQuestions *NumTotalQsts,
|
|
|
|
|
double TotalScore);
|
2020-06-23 18:10:20 +02:00
|
|
|
|
|
|
|
|
|
static void TstRes_CheckIfICanSeePrintResult (const struct TstPrn_Print *Print,
|
|
|
|
|
long UsrCod,
|
|
|
|
|
struct TstRes_ICanView *ICanView);
|
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
static void TstPrn_ShowTagsPresentInAPrint (long PrnCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-03 01:55:39 +02:00
|
|
|
|
/*****************************************************************************/
|
2020-06-24 20:10:57 +02:00
|
|
|
|
/***************************** Reset test print ******************************/
|
2020-04-03 01:55:39 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-11 02:28:38 +02:00
|
|
|
|
void TstPrn_ResetPrint (struct TstPrn_Print *Print)
|
2020-04-03 01:55:39 +02:00
|
|
|
|
{
|
2020-05-07 18:33:26 +02:00
|
|
|
|
Print->PrnCod = -1L;
|
2020-05-11 02:28:38 +02:00
|
|
|
|
TstPrn_ResetPrintExceptPrnCod (Print);
|
2020-04-16 21:03:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-11 02:28:38 +02:00
|
|
|
|
static void TstPrn_ResetPrintExceptPrnCod (struct TstPrn_Print *Print)
|
2020-04-16 21:03:22 +02:00
|
|
|
|
{
|
2021-09-18 18:22:26 +02:00
|
|
|
|
Print->TimeUTC[Dat_STR_TIME] =
|
|
|
|
|
Print->TimeUTC[Dat_END_TIME] = (time_t) 0;
|
2020-06-24 02:15:50 +02:00
|
|
|
|
Print->NumQsts.All =
|
|
|
|
|
Print->NumQsts.NotBlank = 0;
|
|
|
|
|
Print->Sent = false; // After creating an exam, it's not sent
|
|
|
|
|
Print->AllowTeachers = false; // Teachers can't seen the exam if student don't allow it
|
|
|
|
|
Print->Score = 0.0;
|
2020-04-03 01:55:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/********************* Show a test print to be answered **********************/
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
|
2021-10-26 09:23:06 +02:00
|
|
|
|
unsigned NumPrintsGeneratedByMe,
|
2020-06-17 02:31:42 +02:00
|
|
|
|
TstPrn_RequestOrConfirm_t RequestOrConfirm)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests;
|
|
|
|
|
extern const char *Txt_Test;
|
|
|
|
|
extern const char *Txt_Continue;
|
|
|
|
|
extern const char *Txt_Send;
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question Question;
|
2020-06-17 02:31:42 +02:00
|
|
|
|
static const Act_Action_t Action[Tst_NUM_REQUEST_OR_CONFIRM] =
|
|
|
|
|
{
|
|
|
|
|
[TstPrn_REQUEST] = ActReqAssTst,
|
|
|
|
|
[TstPrn_CONFIRM] = ActAssTst,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***** Begin box *****/
|
|
|
|
|
Box_BoxBegin (NULL,Txt_Test,
|
|
|
|
|
NULL,NULL,
|
|
|
|
|
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
|
|
|
|
|
Lay_WriteHeaderClassPhoto (false,false,
|
|
|
|
|
Gbl.Hierarchy.Ins.InsCod,
|
|
|
|
|
Gbl.Hierarchy.Deg.DegCod,
|
|
|
|
|
Gbl.Hierarchy.Crs.CrsCod);
|
|
|
|
|
|
2020-06-24 02:15:50 +02:00
|
|
|
|
if (Print->NumQsts.All)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Begin form *****/
|
2021-03-02 00:54:26 +01:00
|
|
|
|
Frm_BeginForm (Action[RequestOrConfirm]);
|
2021-12-01 01:43:13 +01:00
|
|
|
|
TstPrn_PutParamPrnCod (Print->PrnCod);
|
|
|
|
|
Par_PutHiddenParamUnsigned (NULL,"NumTst",NumPrintsGeneratedByMe);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginWideMarginPadding (10);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** Write one row for each question *****/
|
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < Print->NumQsts.All;
|
2022-03-24 01:18:19 +01:00
|
|
|
|
QstInd++, The_ChangeRowColor ())
|
2021-04-26 17:29:04 +02:00
|
|
|
|
{
|
|
|
|
|
/* Create test question */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstConstructor (&Question);
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Question.QstCod = Print->PrintedQuestions[QstInd].QstCod;
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Show question */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
if (!Qst_GetQstDataFromDB (&Question)) // Question exists
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Err_WrongQuestionExit ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Write question and answers */
|
|
|
|
|
TstPrn_WriteQstAndAnsToFill (&Print->PrintedQuestions[QstInd],QstInd,&Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Destroy test question */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstDestructor (&Question);
|
2021-04-26 17:29:04 +02:00
|
|
|
|
}
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** Button *****/
|
|
|
|
|
switch (RequestOrConfirm)
|
|
|
|
|
{
|
|
|
|
|
case TstPrn_REQUEST:
|
|
|
|
|
/* Send button */
|
|
|
|
|
Btn_PutConfirmButton (Txt_Continue);
|
|
|
|
|
break;
|
|
|
|
|
case TstPrn_CONFIRM:
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/* Will the test be visible by teachers? */
|
2021-04-26 17:29:04 +02:00
|
|
|
|
TstPrn_PutCheckBoxAllowTeachers (true);
|
|
|
|
|
|
|
|
|
|
/* Send button */
|
|
|
|
|
Btn_PutCreateButton (Txt_Send);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** End form *****/
|
2020-06-17 02:31:42 +02:00
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** End box *****/
|
|
|
|
|
Box_BoxEnd ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********** Write a row of a test, with one question and its answer **********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteQstAndAnsToFill (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Begin row *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** Number of question and answer type *****/
|
2022-03-19 02:05:53 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s\"",The_GetColorRows ());
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_WriteNumQst (QstInd + 1,"BIG_INDEX");
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Qst_WriteAnswerType (Question->Answer.Type,"DAT_SMALL");
|
2021-04-26 17:29:04 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/***** Stem, media and answers *****/
|
2022-03-19 02:05:53 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ());
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Write parameter with question code */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_WriteParamQstCod (QstInd,Question->QstCod);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Stem */
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Qst_WriteQstStem (Question->Stem,"Qst_TXT",true);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Media */
|
|
|
|
|
Med_ShowMedia (&Question->Media,
|
2022-03-24 20:31:18 +01:00
|
|
|
|
"Tst_MED_SHOW_CONT",
|
|
|
|
|
"Tst_MED_SHOW");
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
/* Answers */
|
|
|
|
|
TstPrn_WriteAnswersToFill (PrintedQuestion,QstInd,Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
|
|
|
|
/***** End row *****/
|
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Write answers of a question to fill them ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteAnswersToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
void (*TstPrn_WriteAnsBank[Qst_NUM_ANS_TYPES]) (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question) =
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
[Qst_ANS_INT ] = TstPrn_WriteIntAnsToFill,
|
|
|
|
|
[Qst_ANS_FLOAT ] = TstPrn_WriteFltAnsToFill,
|
|
|
|
|
[Qst_ANS_TRUE_FALSE ] = TstPrn_WriteTF_AnsToFill,
|
|
|
|
|
[Qst_ANS_UNIQUE_CHOICE ] = TstPrn_WriteChoAnsToFill,
|
|
|
|
|
[Qst_ANS_MULTIPLE_CHOICE] = TstPrn_WriteChoAnsToFill,
|
|
|
|
|
[Qst_ANS_TEXT ] = TstPrn_WriteTxtAnsToFill,
|
2020-06-17 02:31:42 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***** Write answers *****/
|
2021-04-26 17:29:04 +02:00
|
|
|
|
TstPrn_WriteAnsBank[Question->Answer.Type] (PrintedQuestion,QstInd,Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Write integer answer when seeing a test ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteIntAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
|
|
|
|
|
|
|
|
|
|
/***** Write input field for the answer *****/
|
2021-04-26 17:29:04 +02:00
|
|
|
|
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
HTM_INPUT_TEXT (StrAns,11,PrintedQuestion->StrAnswers,
|
|
|
|
|
HTM_DONT_SUBMIT_ON_CHANGE,
|
2022-03-30 00:46:18 +02:00
|
|
|
|
"size=\"11\" class=\"INPUT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2020-06-17 02:31:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Write float answer when seeing a test ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteFltAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
|
|
|
|
|
|
|
|
|
|
/***** Write input field for the answer *****/
|
2021-04-26 17:29:04 +02:00
|
|
|
|
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
|
2021-10-24 21:35:42 +02:00
|
|
|
|
HTM_INPUT_TEXT (StrAns,Qst_MAX_BYTES_FLOAT_ANSWER,PrintedQuestion->StrAnswers,
|
2020-06-17 02:31:42 +02:00
|
|
|
|
HTM_DONT_SUBMIT_ON_CHANGE,
|
2022-03-30 00:46:18 +02:00
|
|
|
|
"size=\"11\" class=\"INPUT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2020-06-17 02:31:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************** Write false / true answer when seeing a test ****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteTF_AnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_TF_QST[2];
|
|
|
|
|
|
|
|
|
|
/***** Write selector for the answer *****/
|
2021-10-30 13:28:48 +02:00
|
|
|
|
/* Initially user has not answered the question ==> initially all answers will be blank.
|
2020-06-17 02:31:42 +02:00
|
|
|
|
If the user does not confirm the submission of their exam ==>
|
|
|
|
|
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
|
|
|
|
|
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
|
2022-03-30 00:46:18 +02:00
|
|
|
|
"name=\"Ans%010u\" class=\"INPUT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
QstInd,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_OPTION (HTM_Type_STRING,"" ,PrintedQuestion->StrAnswers[0] == '\0',false," ");
|
|
|
|
|
HTM_OPTION (HTM_Type_STRING,"T",PrintedQuestion->StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]);
|
|
|
|
|
HTM_OPTION (HTM_Type_STRING,"F",PrintedQuestion->StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
HTM_SELECT_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******** Write single or multiple choice answer when seeing a test **********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteChoAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOpt;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
unsigned Indexes[Qst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
|
|
|
|
|
bool UsrAnswers[Qst_MAX_OPTIONS_PER_QUESTION];
|
2020-06-17 02:31:42 +02:00
|
|
|
|
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
|
|
|
|
|
|
|
|
|
|
/***** Change format of answers text *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_ChangeFormatAnswersText (Question);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
|
|
|
|
/***** Get indexes for this question from string *****/
|
|
|
|
|
TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes);
|
|
|
|
|
|
|
|
|
|
/***** Get the user's answers for this question from string *****/
|
|
|
|
|
TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers);
|
|
|
|
|
|
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
/***** Indexes are 0 1 2 3... if no shuffle
|
|
|
|
|
or 3 1 0 2... (example) if shuffle *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write selectors and letter of this option *****/
|
2021-10-30 13:28:48 +02:00
|
|
|
|
/* Initially user has not answered the question ==> initially all answers will be blank.
|
2021-10-27 00:58:37 +02:00
|
|
|
|
If the user does not confirm the submission of their exam ==>
|
|
|
|
|
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
|
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
|
|
|
|
|
|
|
|
|
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
|
|
|
|
|
if (Question->Answer.Type == Qst_ANS_UNIQUE_CHOICE)
|
|
|
|
|
HTM_INPUT_RADIO (StrAns,false,
|
|
|
|
|
"id=\"Ans%010u_%u\" value=\"%u\"%s"
|
|
|
|
|
" onclick=\"selectUnselectRadio(this,this.form.Ans%010u,%u);\"",
|
|
|
|
|
QstInd,NumOpt,
|
|
|
|
|
Indexes[NumOpt],
|
|
|
|
|
UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" :
|
|
|
|
|
"",
|
|
|
|
|
QstInd,Question->Answer.NumOptions);
|
|
|
|
|
else // Answer.Type == Tst_ANS_MULTIPLE_CHOICE
|
|
|
|
|
HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE,
|
|
|
|
|
"id=\"Ans%010u_%u\" value=\"%u\"%s",
|
|
|
|
|
QstInd,NumOpt,
|
|
|
|
|
Indexes[NumOpt],
|
|
|
|
|
UsrAnswers[Indexes[NumOpt]] ? " checked=\"checked\"" :
|
|
|
|
|
"");
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"Qst_TXT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
QstInd,NumOpt,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtF ("%c) ",'a' + (char) NumOpt);
|
|
|
|
|
HTM_LABEL_End ();
|
|
|
|
|
HTM_TD_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the option text *****/
|
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_LABEL_Begin ("for=\"Ans%010u_%u\" class=\"Qst_TXT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
QstInd,NumOpt,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text);
|
|
|
|
|
HTM_LABEL_End ();
|
|
|
|
|
Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media,
|
2022-03-24 20:31:18 +01:00
|
|
|
|
"Tst_MED_SHOW_CONT",
|
|
|
|
|
"Tst_MED_SHOW");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
2020-06-17 02:31:42 +02:00
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******************** Write text answer when seeing a test *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_WriteTxtAnsToFill (const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
__attribute__((unused)) struct Qst_Question *Question)
|
2020-06-17 02:31:42 +02:00
|
|
|
|
{
|
|
|
|
|
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
|
|
|
|
|
|
|
|
|
|
/***** Write input field for the answer *****/
|
2021-04-26 17:29:04 +02:00
|
|
|
|
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
|
2021-10-24 21:35:42 +02:00
|
|
|
|
HTM_INPUT_TEXT (StrAns,Qst_MAX_CHARS_ANSWERS_ONE_QST,PrintedQuestion->StrAnswers,
|
2020-06-17 02:31:42 +02:00
|
|
|
|
HTM_DONT_SUBMIT_ON_CHANGE,
|
2022-03-30 00:46:18 +02:00
|
|
|
|
"size=\"40\" class=\"INPUT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2020-06-17 02:31:42 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/**************** Put checkbox to allow teachers to see test *****************/
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstPrn_PutCheckBoxAllowTeachers (bool AllowTeachers)
|
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Allow_teachers_to_consult_this_test;
|
|
|
|
|
|
|
|
|
|
/***** Test exam will be available for teachers? *****/
|
|
|
|
|
HTM_DIV_Begin ("class=\"CM\"");
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_LABEL_Begin ("class=\"FORM_IN_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_INPUT_CHECKBOX ("AllowTchs",HTM_DONT_SUBMIT_ON_CHANGE,
|
|
|
|
|
"value=\"Y\"%s",
|
|
|
|
|
AllowTeachers ? " checked=\"checked\"" : // Teachers can see test exam
|
|
|
|
|
"");
|
|
|
|
|
HTM_TxtF (" %s",Txt_Allow_teachers_to_consult_this_test);
|
|
|
|
|
HTM_LABEL_End ();
|
2020-06-17 02:31:42 +02:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/************************ Show test after assessing it ***********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question Question;
|
2020-05-07 19:54:24 +02:00
|
|
|
|
bool QuestionExists;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginWideMarginPadding (10);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Initialize score and number of questions not blank *****/
|
|
|
|
|
Print->NumQsts.NotBlank = 0;
|
|
|
|
|
Print->Score = 0.0;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < Print->NumQsts.All;
|
2022-03-24 01:18:19 +01:00
|
|
|
|
QstInd++, The_ChangeRowColor ())
|
2021-10-27 00:58:37 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Create test question *****/
|
|
|
|
|
Qst_QstConstructor (&Question);
|
|
|
|
|
Question.QstCod = Print->PrintedQuestions[QstInd].QstCod;
|
2020-04-03 19:13:00 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Get question data *****/
|
|
|
|
|
QuestionExists = Qst_GetQstDataFromDB (&Question);
|
2020-05-07 19:54:24 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write question and answers *****/
|
|
|
|
|
TstPrn_WriteQstAndAnsExam (&Gbl.Usrs.Me.UsrDat,
|
|
|
|
|
Print->PrintedQuestions,QstInd,
|
|
|
|
|
Print->TimeUTC,
|
|
|
|
|
&Question,QuestionExists,
|
|
|
|
|
TstCfg_GetConfigVisibility ());
|
2020-05-07 19:54:24 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Store test question in database *****/
|
|
|
|
|
Tst_DB_StoreOneQstOfPrint (Print,QstInd);
|
2020-05-07 19:54:24 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Compute total score *****/
|
|
|
|
|
Print->Score += Print->PrintedQuestions[QstInd].Score;
|
|
|
|
|
if (Print->PrintedQuestions[QstInd].StrAnswers[0]) // User's answer is not blank
|
|
|
|
|
Print->NumQsts.NotBlank++;
|
2020-05-07 19:54:24 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Update the number of accesses and the score of this question *****/
|
|
|
|
|
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
|
2021-10-27 21:40:19 +02:00
|
|
|
|
Qst_DB_UpdateQstScore (Print->PrintedQuestions[QstInd].QstCod,
|
|
|
|
|
Print->PrintedQuestions[QstInd].StrAnswers[0] != '\0',
|
|
|
|
|
Print->PrintedQuestions[QstInd].Score);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Destroy test question *****/
|
|
|
|
|
Qst_QstDestructor (&Question);
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********** Write a row of a test, with one question and its answer **********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
struct TstPrn_PrintedQuestion PrintedQuestions[TstCfg_MAX_QUESTIONS_PER_TEST],
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
time_t TimeUTC[Dat_NUM_START_END_TIME],
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-05-07 19:54:24 +02:00
|
|
|
|
bool QuestionExists,
|
2020-04-03 19:13:00 +02:00
|
|
|
|
unsigned Visibility)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-04-03 19:13:00 +02:00
|
|
|
|
extern const char *Txt_Score;
|
|
|
|
|
extern const char *Txt_Question_removed;
|
|
|
|
|
extern const char *Txt_Question_modified;
|
|
|
|
|
bool QuestionUneditedAfterExam = false;
|
2020-05-23 19:08:59 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY];
|
2020-05-22 20:10:45 +02:00
|
|
|
|
|
|
|
|
|
/***** Check if I can view each part of the question *****/
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_STD:
|
2020-05-23 19:08:59 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_QST_ANS_TXT ] = TstVis_IsVisibleQstAndAnsTxt (Visibility);
|
|
|
|
|
ICanView[TstVis_VISIBLE_FEEDBACK_TXT ] = TstVis_IsVisibleFeedbackTxt (Visibility);
|
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] = TstVis_IsVisibleCorrectAns (Visibility);
|
|
|
|
|
ICanView[TstVis_VISIBLE_EACH_QST_SCORE] = TstVis_IsVisibleEachQstScore (Visibility);
|
2020-05-22 20:10:45 +02:00
|
|
|
|
break;
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_DEG_ADM:
|
|
|
|
|
case Rol_CTR_ADM:
|
|
|
|
|
case Rol_INS_ADM:
|
|
|
|
|
case Rol_SYS_ADM:
|
2020-05-23 19:08:59 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_QST_ANS_TXT ] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_FEEDBACK_TXT ] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_EACH_QST_SCORE] = true;
|
2020-05-22 20:10:45 +02:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2020-05-23 19:08:59 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_QST_ANS_TXT ] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_FEEDBACK_TXT ] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] =
|
|
|
|
|
ICanView[TstVis_VISIBLE_EACH_QST_SCORE] = false;
|
2020-05-22 20:10:45 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-03 19:13:00 +02:00
|
|
|
|
/***** If this question has been edited later than test time
|
|
|
|
|
==> don't show question ****/
|
|
|
|
|
if (QuestionExists)
|
2021-09-18 18:22:26 +02:00
|
|
|
|
QuestionUneditedAfterExam = (Question->EditTime < TimeUTC[Dat_STR_TIME]);
|
2020-04-03 19:13:00 +02:00
|
|
|
|
else
|
|
|
|
|
QuestionUneditedAfterExam = false;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Begin row *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Number of question and answer type *****/
|
2022-03-19 02:05:53 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s\"",The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_WriteNumQst (QstInd + 1,"BIG_INDEX");
|
|
|
|
|
if (QuestionUneditedAfterExam)
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Qst_WriteAnswerType (Question->Answer.Type,"DAT_SMALL");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-04-03 19:13:00 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Stem, media and answers *****/
|
2022-03-19 02:05:53 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LT %s\"",The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (QuestionExists)
|
|
|
|
|
{
|
|
|
|
|
if (QuestionUneditedAfterExam)
|
|
|
|
|
{
|
|
|
|
|
/* Stem */
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Qst_WriteQstStem (Question->Stem,"Qst_TXT",
|
|
|
|
|
ICanView[TstVis_VISIBLE_QST_ANS_TXT]);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
|
|
|
|
|
/* Media */
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_QST_ANS_TXT])
|
|
|
|
|
Med_ShowMedia (&Question->Media,
|
2022-03-24 20:31:18 +01:00
|
|
|
|
"Tst_MED_SHOW_CONT",
|
|
|
|
|
"Tst_MED_SHOW");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
|
|
|
|
|
/* Answers */
|
|
|
|
|
TstPrn_ComputeAnswerScore (&PrintedQuestions[QstInd],Question);
|
|
|
|
|
TstPrn_WriteAnswersExam (UsrDat,&PrintedQuestions[QstInd],Question,
|
2022-03-24 20:31:18 +01:00
|
|
|
|
ICanView,"Qst_TXT","Qst_TXT_LIGHT");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ale_ShowAlert (Ale_WARNING,Txt_Question_modified);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ale_ShowAlert (Ale_WARNING,Txt_Question_removed);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write score retrieved from database */
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_EACH_QST_SCORE])
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"LM DAT_SMALL_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColonNBSP (Txt_Score);
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_SPAN_Begin ("class=\"%s_%s\"",
|
2021-10-27 00:58:37 +02:00
|
|
|
|
PrintedQuestions[QstInd].StrAnswers[0] ?
|
2022-03-24 20:31:18 +01:00
|
|
|
|
(PrintedQuestions[QstInd].Score > 0 ? "Qst_ANS_OK" : // Correct
|
|
|
|
|
"Qst_ANS_BAD") : // Wrong
|
|
|
|
|
"Qst_ANS_0", // Blank answer
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Double2Decimals (PrintedQuestions[QstInd].Score);
|
|
|
|
|
HTM_SPAN_End ();
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
2020-04-03 19:13:00 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Question feedback */
|
|
|
|
|
if (QuestionUneditedAfterExam)
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_FEEDBACK_TXT])
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Qst_WriteQstFeedback (Question->Feedback,"Qst_TXT_LIGHT");
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End row *****/
|
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-26 17:33:20 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/******** Get questions and answers from form to assess a test print *********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print)
|
|
|
|
|
{
|
|
|
|
|
unsigned QstInd;
|
|
|
|
|
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
|
|
|
|
|
|
|
|
|
|
/***** Loop for every question getting user's answers *****/
|
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < Print->NumQsts.All;
|
|
|
|
|
QstInd++)
|
|
|
|
|
{
|
|
|
|
|
/* Get answers selected by user for this question */
|
|
|
|
|
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
|
|
|
|
|
Par_GetParMultiToText (StrAns,Print->PrintedQuestions[QstInd].StrAnswers,
|
|
|
|
|
Qst_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */
|
|
|
|
|
Par_ReplaceSeparatorMultipleByComma (Print->PrintedQuestions[QstInd].StrAnswers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/*********** Compute score of each question and store in database ************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-09 01:37:00 +02:00
|
|
|
|
void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
|
|
|
|
|
bool UpdateQstScore)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question Question;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Initialize total score *****/
|
2020-05-07 18:33:26 +02:00
|
|
|
|
Print->Score = 0.0;
|
2020-06-24 02:15:50 +02:00
|
|
|
|
Print->NumQsts.NotBlank = 0;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Compute and store scores of all questions *****/
|
2021-04-26 17:29:04 +02:00
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < Print->NumQsts.All;
|
|
|
|
|
QstInd++)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
/* Compute question score */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstConstructor (&Question);
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Question.QstCod = Print->PrintedQuestions[QstInd].QstCod;
|
2021-10-29 00:32:19 +02:00
|
|
|
|
Question.Answer.Type = Qst_DB_GetQstAnswerType (Question.QstCod);
|
2021-04-26 17:29:04 +02:00
|
|
|
|
TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[QstInd],&Question);
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstDestructor (&Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/* Store test question in database */
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Tst_DB_StoreOneQstOfPrint (Print,
|
2021-10-27 20:47:01 +02:00
|
|
|
|
QstInd); // 0, 1, 2, 3...
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/* Accumulate total score */
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Print->Score += Print->PrintedQuestions[QstInd].Score;
|
|
|
|
|
if (Print->PrintedQuestions[QstInd].StrAnswers[0]) // User's answer is not blank
|
2020-06-24 02:15:50 +02:00
|
|
|
|
Print->NumQsts.NotBlank++;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/* Update the number of hits and the score of this question in tests database */
|
|
|
|
|
if (UpdateQstScore)
|
2021-10-27 21:40:19 +02:00
|
|
|
|
Qst_DB_UpdateQstScore (Print->PrintedQuestions[QstInd].QstCod,
|
|
|
|
|
Print->PrintedQuestions[QstInd].StrAnswers[0] != '\0',
|
|
|
|
|
Print->PrintedQuestions[QstInd].Score);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/******************* Get correct answer and compute score ********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-09 01:37:00 +02:00
|
|
|
|
void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
void (*TstPrn_GetCorrectAndComputeAnsScore[Qst_NUM_ANS_TYPES]) (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
|
|
|
|
struct Qst_Question *Question) =
|
2020-05-13 13:13:03 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
[Qst_ANS_INT ] = TstPrn_GetCorrectAndComputeIntAnsScore,
|
|
|
|
|
[Qst_ANS_FLOAT ] = TstPrn_GetCorrectAndComputeFltAnsScore,
|
|
|
|
|
[Qst_ANS_TRUE_FALSE ] = TstPrn_GetCorrectAndComputeTF_AnsScore,
|
|
|
|
|
[Qst_ANS_UNIQUE_CHOICE ] = TstPrn_GetCorrectAndComputeChoAnsScore,
|
|
|
|
|
[Qst_ANS_MULTIPLE_CHOICE] = TstPrn_GetCorrectAndComputeChoAnsScore,
|
|
|
|
|
[Qst_ANS_TEXT ] = TstPrn_GetCorrectAndComputeTxtAnsScore,
|
2020-05-13 13:13:03 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***** Get correct answer and compute answer score depending on type *****/
|
|
|
|
|
TstPrn_GetCorrectAndComputeAnsScore[Question->Answer.Type] (PrintedQuestion,Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/******* Get correct answer and compute score for each type of answer ********/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-05-13 13:37:15 +02:00
|
|
|
|
/***** Get the numerical value of the correct answer,
|
|
|
|
|
and compute score *****/
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_GetCorrectIntAnswerFromDB (Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
TstPrn_ComputeIntAnsScore (PrintedQuestion,Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
static void TstPrn_GetCorrectAndComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-05-13 13:37:15 +02:00
|
|
|
|
/***** Get the numerical value of the minimum and maximum correct answers,
|
|
|
|
|
and compute score *****/
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_GetCorrectFltAnswerFromDB (Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
TstPrn_ComputeFltAnsScore (PrintedQuestion,Question);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TstPrn_GetCorrectAndComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-05-13 13:37:15 +02:00
|
|
|
|
/***** Get answer true or false,
|
|
|
|
|
and compute score *****/
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_GetCorrectTF_AnswerFromDB (Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
TstPrn_ComputeTF_AnsScore (PrintedQuestion,Question);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TstPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-05-13 13:37:15 +02:00
|
|
|
|
/***** Get correct options of test question from database,
|
|
|
|
|
and compute score *****/
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_GetCorrectChoAnswerFromDB (Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
TstPrn_ComputeChoAnsScore (PrintedQuestion,Question);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void TstPrn_GetCorrectAndComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-05-13 13:37:15 +02:00
|
|
|
|
/***** Get correct text answers for this question from database,
|
|
|
|
|
and compute score *****/
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_GetCorrectTxtAnswerFromDB (Question);
|
2020-05-13 12:53:27 +02:00
|
|
|
|
TstPrn_ComputeTxtAnsScore (PrintedQuestion,Question);
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/************** Compute answer score for each type of answer *****************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
void TstPrn_ComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
const struct Qst_Question *Question)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-05-13 12:53:27 +02:00
|
|
|
|
long AnswerUsr;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_BLANK;
|
2020-05-22 20:10:45 +02:00
|
|
|
|
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2020-05-22 20:10:45 +02:00
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_ZERO;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
if (sscanf (PrintedQuestion->StrAnswers,"%ld",&AnswerUsr) == 1)
|
|
|
|
|
if (AnswerUsr == Question->Answer.Integer) // Correct answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
PrintedQuestion->Score = 1.0;
|
2020-06-22 19:27:23 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 12:53:27 +02:00
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
void TstPrn_ComputeFltAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
const struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
|
|
|
|
double AnswerUsr;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_BLANK;
|
2020-05-22 20:10:45 +02:00
|
|
|
|
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2020-05-22 20:10:45 +02:00
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the answer
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_ZERO;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
AnswerUsr = Str_GetDoubleFromStr (PrintedQuestion->StrAnswers);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
// A bad formatted floating point answer will interpreted as 0.0
|
2020-06-22 19:27:23 +02:00
|
|
|
|
if (AnswerUsr >= Question->Answer.FloatingPoint[0] &&
|
|
|
|
|
AnswerUsr <= Question->Answer.FloatingPoint[1])
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
|
|
|
|
PrintedQuestion->Score = 1.0; // Correct (inside the interval)
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
void TstPrn_ComputeTF_AnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
const struct Qst_Question *Question)
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_BLANK;
|
|
|
|
|
PrintedQuestion->Score = 0.0;
|
|
|
|
|
|
2020-05-22 20:10:45 +02:00
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has selected T or F
|
2020-06-22 19:27:23 +02:00
|
|
|
|
{
|
|
|
|
|
if (PrintedQuestion->StrAnswers[0] == Question->Answer.TF)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
|
|
|
|
PrintedQuestion->Score = 1.0; // Correct
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_NEGATIVE;
|
|
|
|
|
PrintedQuestion->Score = -1.0; // Wrong
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-05-13 12:53:27 +02:00
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
void TstPrn_ComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
const struct Qst_Question *Question)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
unsigned Indexes[Qst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
|
|
|
|
|
bool UsrAnswers[Qst_MAX_OPTIONS_PER_QUESTION];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
unsigned NumOpt;
|
|
|
|
|
unsigned NumOptTotInQst = 0;
|
|
|
|
|
unsigned NumOptCorrInQst = 0;
|
|
|
|
|
unsigned NumAnsGood = 0;
|
|
|
|
|
unsigned NumAnsBad = 0;
|
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_BLANK;
|
|
|
|
|
PrintedQuestion->Score = 0.0;
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/***** Get indexes for this question from string *****/
|
|
|
|
|
TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes);
|
|
|
|
|
|
|
|
|
|
/***** Get the user's answers for this question from string *****/
|
|
|
|
|
TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers);
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Compute the total score of this question *****/
|
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
NumOptTotInQst++;
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Correct)
|
|
|
|
|
NumOptCorrInQst++;
|
|
|
|
|
|
|
|
|
|
if (UsrAnswers[Indexes[NumOpt]]) // This answer has been selected by the user
|
|
|
|
|
{
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Correct)
|
|
|
|
|
NumAnsGood++;
|
|
|
|
|
else
|
|
|
|
|
NumAnsBad++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
/* The answer is not blank? */
|
2020-05-22 20:10:45 +02:00
|
|
|
|
if (NumAnsGood || NumAnsBad) // If user has answered the answer
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
/* Compute the score */
|
2021-10-24 21:35:42 +02:00
|
|
|
|
if (Question->Answer.Type == Qst_ANS_UNIQUE_CHOICE)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
if (NumOptTotInQst >= 2) // It should be 2 options at least
|
2020-06-22 19:27:23 +02:00
|
|
|
|
{
|
|
|
|
|
if (NumAnsGood == 1 && NumAnsBad == 0)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
|
|
|
|
PrintedQuestion->Score = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (NumAnsGood == 0 && NumAnsBad == 1)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_NEGATIVE;
|
|
|
|
|
PrintedQuestion->Score = -1.0 / (double) (NumOptTotInQst - 1);
|
|
|
|
|
}
|
|
|
|
|
// other case should be impossible
|
|
|
|
|
}
|
|
|
|
|
// other case should be impossible
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
else // AnswerType == Tst_ANS_MULTIPLE_CHOICE
|
|
|
|
|
{
|
|
|
|
|
if (NumOptCorrInQst) // There are correct options in the question
|
|
|
|
|
{
|
2020-06-22 19:27:23 +02:00
|
|
|
|
if (NumAnsGood == NumOptCorrInQst && NumAnsBad == 0)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
|
|
|
|
PrintedQuestion->Score = 1.0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (NumOptCorrInQst < NumOptTotInQst) // If there are correct options and wrong options (typical case)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->Score = (double) NumAnsGood / (double) NumOptCorrInQst -
|
|
|
|
|
(double) NumAnsBad / (double) (NumOptTotInQst - NumOptCorrInQst);
|
|
|
|
|
if (PrintedQuestion->Score > 0.000001)
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_POSITIVE;
|
|
|
|
|
else if (PrintedQuestion->Score < -0.000001)
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_NEGATIVE;
|
|
|
|
|
else // Score is 0
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_ZERO;
|
|
|
|
|
}
|
|
|
|
|
else // If all options are correct (extrange case)
|
|
|
|
|
{
|
|
|
|
|
if (NumAnsGood == 0)
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_ZERO;
|
|
|
|
|
PrintedQuestion->Score = 0.0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_POSITIVE;
|
|
|
|
|
PrintedQuestion->Score = (double) NumAnsGood / (double) NumOptCorrInQst;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
2020-06-22 19:27:23 +02:00
|
|
|
|
// other case should be impossible
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
void TstPrn_ComputeTxtAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
const struct Qst_Question *Question)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOpt;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
char TextAnsUsr[Qst_MAX_BYTES_ANSWERS_ONE_QST + 1];
|
|
|
|
|
char TextAnsOK[Qst_MAX_BYTES_ANSWERS_ONE_QST + 1];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_BLANK;
|
2020-05-09 01:37:00 +02:00
|
|
|
|
PrintedQuestion->Score = 0.0; // Default score for blank or wrong answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2020-05-22 20:10:45 +02:00
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the answer
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
/* Filter the user answer */
|
2021-02-15 16:25:55 +01:00
|
|
|
|
Str_Copy (TextAnsUsr,PrintedQuestion->StrAnswers,sizeof (TextAnsUsr) - 1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/* In order to compare student answer to stored answer,
|
|
|
|
|
the text answers are stored avoiding two or more consecurive spaces */
|
|
|
|
|
Str_ReplaceSeveralSpacesForOne (TextAnsUsr);
|
|
|
|
|
Str_ConvertToComparable (TextAnsUsr);
|
|
|
|
|
|
2020-06-22 19:27:23 +02:00
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_WRONG_ZERO;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
/* Filter this correct answer */
|
2021-02-15 16:25:55 +01:00
|
|
|
|
Str_Copy (TextAnsOK,Question->Answer.Options[NumOpt].Text,sizeof (TextAnsOK) - 1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
Str_ConvertToComparable (TextAnsOK);
|
|
|
|
|
|
|
|
|
|
/* Check is user answer is correct */
|
|
|
|
|
if (!strcoll (TextAnsUsr,TextAnsOK))
|
2020-06-22 19:27:23 +02:00
|
|
|
|
{
|
|
|
|
|
PrintedQuestion->AnswerIsCorrect = TstPrn_ANSWER_IS_CORRECT;
|
2020-05-09 01:37:00 +02:00
|
|
|
|
PrintedQuestion->Score = 1.0; // Correct answer
|
2020-06-22 19:27:23 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********** Get vector of unsigned indexes from string with indexes **********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-10-24 21:35:42 +02:00
|
|
|
|
void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[Qst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
|
|
|
|
|
unsigned Indexes[Qst_MAX_OPTIONS_PER_QUESTION])
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOpt;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
const char *Ptr;
|
|
|
|
|
char StrOneIndex[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
/***** Get indexes from string *****/
|
|
|
|
|
for (NumOpt = 0, Ptr = StrIndexesOneQst;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
NumOpt < Qst_MAX_OPTIONS_PER_QUESTION && *Ptr;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
Par_GetNextStrUntilComma (&Ptr,StrOneIndex,Cns_MAX_DECIMAL_DIGITS_UINT);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
if (sscanf (StrOneIndex,"%u",&(Indexes[NumOpt])) != 1)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongAnswerIndexExit ();
|
2020-05-13 12:53:27 +02:00
|
|
|
|
|
2021-10-24 21:35:42 +02:00
|
|
|
|
if (Indexes[NumOpt] >= Qst_MAX_OPTIONS_PER_QUESTION)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongAnswerIndexExit ();
|
2020-05-13 12:53:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Initialize remaining to 0 *****/
|
|
|
|
|
for (;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
NumOpt < Qst_MAX_OPTIONS_PER_QUESTION;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
NumOpt++)
|
|
|
|
|
Indexes[NumOpt] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************ Get vector of bool answers from string with answers ************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-10-24 21:35:42 +02:00
|
|
|
|
void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[Qst_MAX_BYTES_ANSWERS_ONE_QST + 1],
|
|
|
|
|
bool UsrAnswers[Qst_MAX_OPTIONS_PER_QUESTION])
|
2020-05-13 12:53:27 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOpt;
|
|
|
|
|
const char *Ptr;
|
|
|
|
|
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
|
|
|
|
|
unsigned AnsUsr;
|
|
|
|
|
|
|
|
|
|
/***** Initialize all answers to false *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
for (NumOpt = 0;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
NumOpt < Qst_MAX_OPTIONS_PER_QUESTION;
|
2020-05-13 12:53:27 +02:00
|
|
|
|
NumOpt++)
|
|
|
|
|
UsrAnswers[NumOpt] = false;
|
|
|
|
|
|
|
|
|
|
/***** Set selected answers to true *****/
|
|
|
|
|
for (NumOpt = 0, Ptr = StrAnswersOneQst;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
NumOpt < Qst_MAX_OPTIONS_PER_QUESTION && *Ptr;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
2020-05-13 12:53:27 +02:00
|
|
|
|
Par_GetNextStrUntilComma (&Ptr,StrOneAnswer,Cns_MAX_DECIMAL_DIGITS_UINT);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
if (sscanf (StrOneAnswer,"%u",&AnsUsr) != 1)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongAnswerExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-24 21:35:42 +02:00
|
|
|
|
if (AnsUsr >= Qst_MAX_OPTIONS_PER_QUESTION)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongAnswerExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-13 12:53:27 +02:00
|
|
|
|
UsrAnswers[AnsUsr] = true;
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************ Compute and show total grade out of maximum grade **************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
void TstPrn_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-05-07 18:33:26 +02:00
|
|
|
|
TstPrn_ShowGrade (TstPrn_ComputeGrade (NumQsts,Score,MaxGrade),MaxGrade);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**************** Compute total grade out of maximum grade *******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
double TstPrn_ComputeGrade (unsigned NumQsts,double Score,double MaxGrade)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
double MaxScore;
|
|
|
|
|
double Grade;
|
|
|
|
|
|
|
|
|
|
/***** Compute grade *****/
|
|
|
|
|
if (NumQsts)
|
|
|
|
|
{
|
|
|
|
|
MaxScore = (double) NumQsts;
|
|
|
|
|
Grade = Score * MaxGrade / MaxScore;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Grade = 0.0;
|
|
|
|
|
|
|
|
|
|
return Grade;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Show total grade out of maximum grade ********************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
void TstPrn_ShowGrade (double Grade,double MaxGrade)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
/***** Write grade over maximum grade *****/
|
|
|
|
|
HTM_Double2Decimals (Grade);
|
|
|
|
|
HTM_Txt ("/");
|
|
|
|
|
HTM_Double2Decimals (MaxGrade);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/************* Write answers of a question when assessing a test *************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-16 02:04:36 +02:00
|
|
|
|
void TstPrn_WriteAnswersExam (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
const char *ClassTxt,
|
|
|
|
|
const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
void (*TstPrn_WriteAnsExam[Qst_NUM_ANS_TYPES]) (struct UsrData *UsrDat,
|
2020-05-16 02:04:36 +02:00
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
const char *ClassTxt,
|
|
|
|
|
const char *ClassFeedback) =
|
2020-05-16 02:04:36 +02:00
|
|
|
|
{
|
2021-10-24 21:35:42 +02:00
|
|
|
|
[Qst_ANS_INT ] = TstPrn_WriteIntAnsPrint,
|
|
|
|
|
[Qst_ANS_FLOAT ] = TstPrn_WriteFltAnsPrint,
|
|
|
|
|
[Qst_ANS_TRUE_FALSE ] = TstPrn_WriteTF_AnsPrint,
|
|
|
|
|
[Qst_ANS_UNIQUE_CHOICE ] = TstPrn_WriteChoAnsPrint,
|
|
|
|
|
[Qst_ANS_MULTIPLE_CHOICE] = TstPrn_WriteChoAnsPrint,
|
|
|
|
|
[Qst_ANS_TEXT ] = TstPrn_WriteTxtAnsPrint,
|
2020-05-16 02:04:36 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***** Get correct answer and compute answer score depending on type *****/
|
2020-05-22 20:10:45 +02:00
|
|
|
|
TstPrn_WriteAnsExam[Question->Answer.Type] (UsrDat,PrintedQuestion,Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
ICanView,ClassTxt,ClassFeedback);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/******************* Write integer answer in a test print ********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteIntAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
long IntAnswerUsr;
|
2020-04-03 19:13:00 +02:00
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Check if number of rows is correct *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_CheckIfNumberOfAnswersIsOne (Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin table *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header with the title of each column *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
TstPrn_WriteHeadUserCorrect (UsrDat);
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the user answer *****/
|
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the question
|
|
|
|
|
{
|
|
|
|
|
if (sscanf (PrintedQuestion->StrAnswers,"%ld",&IntAnswerUsr) == 1)
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CM %s_%s\"",
|
2021-10-27 00:58:37 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] ?
|
2022-03-24 20:31:18 +01:00
|
|
|
|
(IntAnswerUsr == Question->Answer.Integer ? "Qst_ANS_OK" : // Correct
|
|
|
|
|
"Qst_ANS_BAD") : // Wrong
|
|
|
|
|
"Qst_ANS_0", // Blank answer
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Long (IntAnswerUsr);
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CM Qst_ANS_0_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt ("?");
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else // If user has omitted the answer
|
|
|
|
|
HTM_TD_Empty (1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the correct answer *****/
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"CM Qst_ANS_0_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
HTM_Long (Question->Answer.Integer);
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/******************** Write float answer in an test print ********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteFltAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-04-03 19:13:00 +02:00
|
|
|
|
double FloatAnsUsr = 0.0;
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Check if number of rows is correct *****/
|
|
|
|
|
if (Question->Answer.NumOptions != 2)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongAnswerExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin table *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header with the title of each column *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
TstPrn_WriteHeadUserCorrect (UsrDat);
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the user answer *****/
|
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the question
|
|
|
|
|
{
|
|
|
|
|
FloatAnsUsr = Str_GetDoubleFromStr (PrintedQuestion->StrAnswers);
|
|
|
|
|
// A bad formatted floating point answer will interpreted as 0.0
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CM %s_%s\"",
|
2021-10-27 00:58:37 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] ?
|
|
|
|
|
((FloatAnsUsr >= Question->Answer.FloatingPoint[0] &&
|
2022-03-24 20:31:18 +01:00
|
|
|
|
FloatAnsUsr <= Question->Answer.FloatingPoint[1]) ? "Qst_ANS_OK" : // Correct
|
|
|
|
|
"Qst_ANS_BAD") : // Wrong
|
|
|
|
|
"Qst_ANS_0", // Blank answer
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Double (FloatAnsUsr);
|
2021-10-27 20:47:01 +02:00
|
|
|
|
HTM_TD_End ();
|
2021-10-27 00:58:37 +02:00
|
|
|
|
}
|
|
|
|
|
else // If user has omitted the answer
|
2021-10-27 20:47:01 +02:00
|
|
|
|
HTM_TD_Empty (1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the correct answer *****/
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"CM Qst_ANS_0_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
{
|
|
|
|
|
HTM_Txt ("[");
|
|
|
|
|
HTM_Double (Question->Answer.FloatingPoint[0]);
|
|
|
|
|
HTM_Txt ("; ");
|
|
|
|
|
HTM_Double (Question->Answer.FloatingPoint[1]);
|
|
|
|
|
HTM_Txt ("]");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/***************** Write false / true answer in a test print *****************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteTF_AnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-04-03 19:13:00 +02:00
|
|
|
|
char AnsTFUsr;
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Check if number of rows is correct *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_CheckIfNumberOfAnswersIsOne (Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Get answer true or false *****/
|
2020-05-16 02:04:36 +02:00
|
|
|
|
AnsTFUsr = PrintedQuestion->StrAnswers[0];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin table *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header with the title of each column *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
TstPrn_WriteHeadUserCorrect (UsrDat);
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the user answer *****/
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CM %s_%s\"",
|
2021-10-27 00:58:37 +02:00
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] ?
|
2022-03-24 20:31:18 +01:00
|
|
|
|
(AnsTFUsr == Question->Answer.TF ? "Qst_ANS_OK" : // Correct
|
|
|
|
|
"Qst_ANS_BAD") : // Wrong
|
|
|
|
|
"Qst_ANS_0", // Blank answer
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Qst_WriteAnsTF (AnsTFUsr);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the correct answer *****/
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"CM Qst_ANS_0_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
Qst_WriteAnsTF (Question->Answer.TF);
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/********** Write single or multiple choice answer in a test print ***********/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteChoAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
const char *ClassTxt,
|
|
|
|
|
const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_TST_Answer_given_by_the_user;
|
|
|
|
|
extern const char *Txt_TST_Answer_given_by_the_teachers;
|
|
|
|
|
unsigned NumOpt;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
unsigned Indexes[Qst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
|
|
|
|
|
bool UsrAnswers[Qst_MAX_OPTIONS_PER_QUESTION];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
char *Class;
|
|
|
|
|
char *Str;
|
|
|
|
|
} Ans;
|
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/***** Change format of answers text *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_ChangeFormatAnswersText (Question);
|
2020-05-22 20:10:45 +02:00
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/***** Change format of answers feedback *****/
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_FEEDBACK_TXT])
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_ChangeFormatAnswersFeedback (Question);
|
2020-05-22 20:10:45 +02:00
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Get indexes for this question from string *****/
|
2020-05-16 02:04:36 +02:00
|
|
|
|
TstPrn_GetIndexesFromStr (PrintedQuestion->StrIndexes,Indexes);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Get the user's answers for this question from string *****/
|
2020-05-16 02:04:36 +02:00
|
|
|
|
TstPrn_GetAnswersFromStr (PrintedQuestion->StrAnswers,UsrAnswers);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
TstPrn_WriteHeadUserCorrect (UsrDat);
|
|
|
|
|
HTM_TD_Empty (2);
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write answers (one row per answer) *****/
|
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Draw icon depending on user's answer */
|
|
|
|
|
if (UsrAnswers[Indexes[NumOpt]] == true) // This answer has been selected by the user
|
|
|
|
|
{
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
{
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Correct)
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Ans.Class = "Qst_ANS_OK"; // Correct
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Ans.Str = "✓";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Ans.Class = "Qst_ANS_BAD"; // Wrong
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Ans.Str = "✗";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Ans.Class = "Qst_ANS_0"; // Blank answer
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Ans.Str = "•";
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CT %s_%s\" title=\"%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
Ans.Class,The_GetSuffix (),
|
2022-03-24 20:31:18 +01:00
|
|
|
|
Txt_TST_Answer_given_by_the_user);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Ans.Str);
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
else // This answer has NOT been selected by the user
|
|
|
|
|
HTM_TD_Empty (1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Draw icon that indicates whether the answer is correct */
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
{
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Correct)
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CT Qst_ANS_0_%s\" title=\"%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Txt_TST_Answer_given_by_the_teachers);
|
|
|
|
|
HTM_Txt ("•");
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
HTM_TD_Empty (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CT Qst_ANS_0_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Answer letter (a, b, c,...) */
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LT %s_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassTxt,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtF ("%c) ",'a' + (char) NumOpt);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Answer text and feedback */
|
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"%s_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassTxt,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_QST_ANS_TXT])
|
|
|
|
|
{
|
|
|
|
|
HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text);
|
|
|
|
|
Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media,
|
2022-03-24 20:31:18 +01:00
|
|
|
|
"Tst_MED_SHOW_CONT",
|
|
|
|
|
"Tst_MED_SHOW");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Feedback)
|
|
|
|
|
if (Question->Answer.Options[Indexes[NumOpt]].Feedback[0])
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"%s_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassFeedback,The_GetSuffix ());
|
2021-10-27 20:47:01 +02:00
|
|
|
|
HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Feedback);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/************** Write text answer when assessing a test print ****************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_WriteTxtAnsPrint (struct UsrData *UsrDat,
|
|
|
|
|
const struct TstPrn_PrintedQuestion *PrintedQuestion,
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question *Question,
|
2020-06-17 20:20:16 +02:00
|
|
|
|
bool ICanView[TstVis_NUM_ITEMS_VISIBILITY],
|
|
|
|
|
__attribute__((unused)) const char *ClassTxt,
|
|
|
|
|
__attribute__((unused)) const char *ClassFeedback)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
unsigned NumOpt;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
char TextAnsUsr[Qst_MAX_BYTES_ANSWERS_ONE_QST + 1];
|
|
|
|
|
char TextAnsOK[Qst_MAX_BYTES_ANSWERS_ONE_QST + 1];
|
2020-04-02 03:28:08 +02:00
|
|
|
|
bool Correct = false;
|
2020-04-03 19:13:00 +02:00
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/***** Change format of answers text *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_ChangeFormatAnswersText (Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-17 02:31:42 +02:00
|
|
|
|
/***** Change format of answers feedback *****/
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_FEEDBACK_TXT])
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_ChangeFormatAnswersFeedback (Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin table *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header with the title of each column *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
TstPrn_WriteHeadUserCorrect (UsrDat);
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the user answer *****/
|
|
|
|
|
if (PrintedQuestion->StrAnswers[0]) // If user has answered the question
|
|
|
|
|
{
|
|
|
|
|
/* Filter the user answer */
|
|
|
|
|
Str_Copy (TextAnsUsr,PrintedQuestion->StrAnswers,sizeof (TextAnsUsr) - 1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* In order to compare student answer to stored answer,
|
|
|
|
|
the text answers are stored avoiding two or more consecurive spaces */
|
|
|
|
|
Str_ReplaceSeveralSpacesForOne (TextAnsUsr);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Str_ConvertToComparable (TextAnsUsr);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
/* Filter this correct answer */
|
|
|
|
|
Str_Copy (TextAnsOK,Question->Answer.Options[NumOpt].Text,sizeof (TextAnsOK) - 1);
|
|
|
|
|
Str_ConvertToComparable (TextAnsOK);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Check is user answer is correct */
|
|
|
|
|
if (!strcoll (TextAnsUsr,TextAnsOK))
|
|
|
|
|
{
|
|
|
|
|
Correct = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CT %s_%s\"",
|
|
|
|
|
ICanView[TstVis_VISIBLE_CORRECT_ANSWER] ? (Correct ? "Qst_ANS_OK" : // Correct
|
|
|
|
|
"Qst_ANS_BAD") : // Wrong
|
|
|
|
|
"Qst_ANS_0", // Blank answer
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (PrintedQuestion->StrAnswers);
|
2021-10-27 20:47:01 +02:00
|
|
|
|
HTM_TD_End ();
|
2021-10-27 00:58:37 +02:00
|
|
|
|
}
|
|
|
|
|
else // If user has omitted the answer
|
2021-10-27 20:47:01 +02:00
|
|
|
|
HTM_TD_Empty (1);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write the correct answers *****/
|
|
|
|
|
if (ICanView[TstVis_VISIBLE_CORRECT_ANSWER])
|
|
|
|
|
{
|
|
|
|
|
HTM_TD_Begin ("class=\"CT\"");
|
|
|
|
|
HTM_TABLE_BeginPadding (2);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
for (NumOpt = 0;
|
|
|
|
|
NumOpt < Question->Answer.NumOptions;
|
|
|
|
|
NumOpt++)
|
|
|
|
|
{
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Answer letter (a, b, c,...) */
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LT Qst_ANS_0_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtF ("%c) ",'a' + (char) NumOpt);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Answer text and feedback */
|
|
|
|
|
HTM_TD_Begin ("class=\"LT\"");
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"Qst_ANS_0_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Question->Answer.Options[NumOpt].Text);
|
|
|
|
|
HTM_DIV_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView[TstVis_VISIBLE_FEEDBACK_TXT])
|
|
|
|
|
if (Question->Answer.Options[NumOpt].Feedback)
|
|
|
|
|
if (Question->Answer.Options[NumOpt].Feedback[0])
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_DIV_Begin ("class=\"Qst_TXT_LIGHT\"");
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Question->Answer.Options[NumOpt].Feedback);
|
|
|
|
|
HTM_DIV_End ();
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-03-24 20:31:18 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"CT Qst_ANS_0_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
HTM_TABLE_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/********* Write head with two columns: ********/
|
|
|
|
|
/********* one for the user's answer and other for the correct answer ********/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-07 18:33:26 +02:00
|
|
|
|
static void TstPrn_WriteHeadUserCorrect (struct UsrData *UsrDat)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_User[Usr_NUM_SEXS];
|
|
|
|
|
extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
|
|
|
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"CM DAT_SMALL_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Txt_User[UsrDat->Sex]);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"CM DAT_SMALL_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Txt (Txt_ROLES_PLURAL_Abc[Rol_TCH][Usr_SEX_UNKNOWN]);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/*************** Select users and dates to show their tests ******************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_SelUsrsToViewUsrsPrints (void)
|
2020-04-09 21:36:21 +02:00
|
|
|
|
{
|
2020-05-18 14:34:31 +02:00
|
|
|
|
TstPrn_PutFormToSelectUsrsToViewUsrsPrints (NULL);
|
2020-04-09 21:36:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_PutFormToSelectUsrsToViewUsrsPrints (__attribute__((unused)) void *Args)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests_results;
|
|
|
|
|
extern const char *Txt_Results;
|
2020-05-18 22:59:07 +02:00
|
|
|
|
extern const char *Txt_View_results;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-09 21:36:21 +02:00
|
|
|
|
Usr_PutFormToSelectUsrsToGoToAct (&Gbl.Usrs.Selected,
|
2020-05-18 22:59:07 +02:00
|
|
|
|
ActSeeUsrTstResCrs,
|
2020-04-09 21:36:21 +02:00
|
|
|
|
NULL,NULL,
|
|
|
|
|
Txt_Results,
|
|
|
|
|
Hlp_ASSESSMENT_Tests_results,
|
2020-05-18 22:59:07 +02:00
|
|
|
|
Txt_View_results,
|
2020-04-09 21:36:21 +02:00
|
|
|
|
true); // Put form with date range
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/*********************** Select dates to show my tests ***********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_SelDatesToSeeMyPrints (void)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests_results;
|
|
|
|
|
extern const char *Txt_Results;
|
2020-05-18 22:59:07 +02:00
|
|
|
|
extern const char *Txt_View_results;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
static const Dat_SetHMS SetHMS[Dat_NUM_START_END_TIME] =
|
|
|
|
|
{
|
2021-09-18 18:22:26 +02:00
|
|
|
|
[Dat_STR_TIME] = Dat_HMS_DO_NOT_SET,
|
|
|
|
|
[Dat_END_TIME] = Dat_HMS_DO_NOT_SET
|
2020-04-02 03:28:08 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***** Begin form *****/
|
2021-03-02 00:54:26 +01:00
|
|
|
|
Frm_BeginForm (ActSeeMyTstResCrs);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin box and table *****/
|
|
|
|
|
Box_BoxTableBegin (NULL,Txt_Results,
|
|
|
|
|
NULL,NULL,
|
|
|
|
|
Hlp_ASSESSMENT_Tests_results,Box_NOT_CLOSABLE,2);
|
|
|
|
|
|
|
|
|
|
Dat_PutFormStartEndClientLocalDateTimesWithYesterdayToday (SetHMS);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** End table, send button and end box *****/
|
|
|
|
|
Box_BoxTableWithButtonEnd (Btn_CONFIRM_BUTTON,Txt_View_results);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End form *****/
|
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/******************************* Show my tests *******************************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_ShowMyPrints (void)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests_results;
|
|
|
|
|
extern const char *Txt_Results;
|
|
|
|
|
|
|
|
|
|
/***** Get starting and ending dates *****/
|
|
|
|
|
Dat_GetIniEndDatesFromForm ();
|
|
|
|
|
|
|
|
|
|
/***** Begin box and table *****/
|
|
|
|
|
Box_BoxTableBegin (NULL,Txt_Results,
|
|
|
|
|
NULL,NULL,
|
|
|
|
|
Hlp_ASSESSMENT_Tests_results,Box_NOT_CLOSABLE,2);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header of the table with the list of users *****/
|
|
|
|
|
TstPrn_ShowHeaderPrints (Usr_ME);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** List my tests *****/
|
|
|
|
|
TstCfg_GetConfig (); // To get visibility
|
|
|
|
|
TstPrn_ShowUsrPrints (&Gbl.Usrs.Me.UsrDat);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End table and box *****/
|
|
|
|
|
Box_BoxTableEnd ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/********************** Get users and show their test ************************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_GetUsrsAndShowPrints (void)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
Usr_GetSelectedUsrsAndGoToAct (&Gbl.Usrs.Selected,
|
2020-05-18 14:34:31 +02:00
|
|
|
|
TstPrn_ShowUsrsPrints,NULL,
|
|
|
|
|
TstPrn_PutFormToSelectUsrsToViewUsrsPrints,NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/********************* Show test prints for several users ********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_ShowUsrsPrints (__attribute__((unused)) void *Args)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests_results;
|
|
|
|
|
extern const char *Txt_Results;
|
|
|
|
|
const char *Ptr;
|
|
|
|
|
|
|
|
|
|
/***** Get starting and ending dates *****/
|
|
|
|
|
Dat_GetIniEndDatesFromForm ();
|
|
|
|
|
|
|
|
|
|
/***** Begin box and table *****/
|
|
|
|
|
Box_BoxTableBegin (NULL,Txt_Results,
|
|
|
|
|
NULL,NULL,
|
2020-06-22 19:27:23 +02:00
|
|
|
|
Hlp_ASSESSMENT_Tests_results,Box_NOT_CLOSABLE,5);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Header of the table with the list of users *****/
|
|
|
|
|
TstPrn_ShowHeaderPrints (Usr_OTHER);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** List the tests of the selected users *****/
|
|
|
|
|
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
|
|
|
|
|
while (*Ptr)
|
|
|
|
|
{
|
|
|
|
|
Par_GetNextStrUntilSeparParamMult (&Ptr,Gbl.Usrs.Other.UsrDat.EnUsrCod,
|
|
|
|
|
Cry_BYTES_ENCRYPTED_STR_SHA256_BASE64);
|
|
|
|
|
Usr_GetUsrCodFromEncryptedUsrCod (&Gbl.Usrs.Other.UsrDat);
|
|
|
|
|
if (Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
|
|
|
|
|
Usr_DONT_GET_PREFS,
|
|
|
|
|
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
|
|
|
|
|
if (Usr_CheckIfICanViewTstExaMchResult (&Gbl.Usrs.Other.UsrDat))
|
|
|
|
|
{
|
|
|
|
|
/***** Show tests *****/
|
2021-11-03 21:31:16 +01:00
|
|
|
|
Gbl.Usrs.Other.UsrDat.Accepted = Enr_CheckIfUsrHasAcceptedInCurrentCrs (&Gbl.Usrs.Other.UsrDat);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
TstPrn_ShowUsrPrints (&Gbl.Usrs.Other.UsrDat);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End table and box *****/
|
|
|
|
|
Box_BoxTableEnd ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/************************** Show header of my tests **************************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-06-24 20:10:57 +02:00
|
|
|
|
static void TstPrn_ShowHeaderPrints (Usr_MeOrOther_t MeOrOther)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_User[Usr_NUM_SEXS];
|
|
|
|
|
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
|
|
|
|
|
extern const char *Txt_Questions;
|
2020-06-23 20:28:33 +02:00
|
|
|
|
extern const char *Txt_Answers;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
extern const char *Txt_Score;
|
|
|
|
|
extern const char *Txt_Grade;
|
2020-06-23 20:28:33 +02:00
|
|
|
|
extern const char *Txt_ANSWERS_non_blank;
|
|
|
|
|
extern const char *Txt_ANSWERS_blank;
|
|
|
|
|
extern const char *Txt_total;
|
|
|
|
|
extern const char *Txt_average;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-23 20:28:33 +02:00
|
|
|
|
/***** First row *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2022-01-02 15:17:30 +01:00
|
|
|
|
HTM_TH_Span (Txt_User[MeOrOther == Usr_ME ?
|
|
|
|
|
Gbl.Usrs.Me.UsrDat.Sex :
|
|
|
|
|
Usr_SEX_UNKNOWN ],HTM_HEAD_CENTER,3,2,"LINE_BOTTOM");
|
|
|
|
|
HTM_TH_Span (Txt_START_END_TIME[Dat_STR_TIME] ,HTM_HEAD_LEFT ,3,1,"LINE_BOTTOM");
|
|
|
|
|
HTM_TH_Span (Txt_START_END_TIME[Dat_END_TIME] ,HTM_HEAD_LEFT ,3,1,"LINE_BOTTOM");
|
|
|
|
|
HTM_TH_Span (Txt_Questions ,HTM_HEAD_RIGHT ,3,1,"LINE_BOTTOM LINE_LEFT");
|
|
|
|
|
HTM_TH_Span (Txt_Answers ,HTM_HEAD_CENTER,1,2,"LINE_LEFT");
|
|
|
|
|
HTM_TH_Span (Txt_Score ,HTM_HEAD_CENTER,1,2,"LINE_LEFT");
|
|
|
|
|
HTM_TH_Span (Txt_Grade ,HTM_HEAD_RIGHT ,3,1,"LINE_BOTTOM LINE_LEFT");
|
|
|
|
|
HTM_TH_Span (NULL ,HTM_HEAD_CENTER,3,1,"LINE_BOTTOM LINE_LEFT");
|
2020-06-23 20:28:33 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
|
|
|
|
|
/***** Second row *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2022-01-02 15:17:30 +01:00
|
|
|
|
HTM_TH_Span (Txt_ANSWERS_non_blank ,HTM_HEAD_RIGHT ,1,1,"LINE_LEFT");
|
|
|
|
|
HTM_TH (Txt_ANSWERS_blank ,HTM_HEAD_RIGHT );
|
|
|
|
|
HTM_TH_Span (Txt_total ,HTM_HEAD_RIGHT ,1,1,"LINE_LEFT");
|
|
|
|
|
HTM_TH (Txt_average ,HTM_HEAD_RIGHT );
|
2020-06-23 20:28:33 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
|
|
|
|
|
/***** Third row *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2022-01-02 15:17:30 +01:00
|
|
|
|
HTM_TH_Span ("{-1≤<em>p<sub>i</sub></em>≤1}",HTM_HEAD_RIGHT ,1,1,"LINE_BOTTOM LINE_LEFT");
|
|
|
|
|
HTM_TH_Span ("{<em>p<sub>i</sub></em>=0}" ,HTM_HEAD_RIGHT ,1,1,"LINE_BOTTOM");
|
|
|
|
|
HTM_TH_Span ("<em>Σp<sub>i</sub></em>" ,HTM_HEAD_RIGHT ,1,1,"LINE_BOTTOM LINE_LEFT");
|
|
|
|
|
HTM_TH_Span ("-1≤"
|
|
|
|
|
"<em style=\"text-decoration:overline;\">p</em>"
|
|
|
|
|
"≤1" ,HTM_HEAD_RIGHT ,1,1,"LINE_BOTTOM");
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2020-05-18 14:34:31 +02:00
|
|
|
|
/************ Show the test prints of a user in the current course ***********/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_View_test;
|
|
|
|
|
MYSQL_RES *mysql_res;
|
2020-05-18 14:34:31 +02:00
|
|
|
|
unsigned NumPrints;
|
|
|
|
|
unsigned NumPrint;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
static unsigned UniqueId = 0;
|
|
|
|
|
Dat_StartEndTime_t StartEndTime;
|
|
|
|
|
char *Id;
|
2020-05-07 18:33:26 +02:00
|
|
|
|
struct TstPrn_Print Print;
|
2020-06-24 02:15:50 +02:00
|
|
|
|
unsigned NumQstsBlank;
|
|
|
|
|
struct TstPrn_NumQuestions NumTotalQsts;
|
|
|
|
|
double TotalScore;
|
2020-05-18 14:34:31 +02:00
|
|
|
|
unsigned NumPrintsVisibleByTchs = 0;
|
2020-06-23 18:10:20 +02:00
|
|
|
|
struct TstRes_ICanView ICanView;
|
2021-12-15 00:47:29 +01:00
|
|
|
|
const char *ClassDat;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-24 02:15:50 +02:00
|
|
|
|
/***** Reset total number of questions and total score *****/
|
|
|
|
|
NumTotalQsts.All =
|
|
|
|
|
NumTotalQsts.NotBlank = 0;
|
|
|
|
|
TotalScore = 0.0;
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/***** Make database query *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
NumPrints = Tst_DB_GetUsrPrintsInCurrentCrs (&mysql_res,UsrDat->UsrCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Show user's data *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Usr_ShowTableCellWithUsrData (UsrDat,NumPrints);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Get and print tests *****/
|
|
|
|
|
if (NumPrints)
|
|
|
|
|
{
|
|
|
|
|
for (NumPrint = 0;
|
|
|
|
|
NumPrint < NumPrints;
|
|
|
|
|
NumPrint++)
|
|
|
|
|
{
|
|
|
|
|
/* Get print code (row[0]) */
|
2021-10-27 20:47:01 +02:00
|
|
|
|
if ((Print.PrnCod = DB_GetNextCode (mysql_res)) <= 0)
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Err_WrongTestExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Get print data */
|
|
|
|
|
TstPrn_GetPrintDataByPrnCod (&Print);
|
2022-03-25 11:09:51 +01:00
|
|
|
|
ClassDat = Print.AllowTeachers ? "DAT" :
|
|
|
|
|
"DAT_LIGHT";
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Get if I can see print result and score */
|
|
|
|
|
TstRes_CheckIfICanSeePrintResult (&Print,UsrDat->UsrCod,&ICanView);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (NumPrint)
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
|
|
|
|
/* Write dates and times */
|
|
|
|
|
UniqueId++;
|
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
|
|
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
|
|
|
StartEndTime++)
|
|
|
|
|
{
|
|
|
|
|
if (asprintf (&Id,"tst_date_%u_%u",(unsigned) StartEndTime,UniqueId) < 0)
|
|
|
|
|
Err_NotEnoughMemoryExit ();
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("id=\"%s\" class=\"LT %s_%s %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
Id,ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Dat_WriteLocalDateHMSFromUTC (Id,Print.TimeUTC[StartEndTime],
|
|
|
|
|
Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK,
|
|
|
|
|
true,true,false,0x7);
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
free (Id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Accumulate questions and score */
|
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
{
|
|
|
|
|
NumTotalQsts.All += Print.NumQsts.All;
|
|
|
|
|
NumTotalQsts.NotBlank += Print.NumQsts.NotBlank;
|
|
|
|
|
TotalScore += Print.Score;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write number of questions */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Result)
|
|
|
|
|
HTM_Unsigned (Print.NumQsts.All);
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write number of non-blank answers */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Result)
|
|
|
|
|
{
|
|
|
|
|
if (Print.NumQsts.NotBlank)
|
|
|
|
|
HTM_Unsigned (Print.NumQsts.NotBlank);
|
|
|
|
|
else
|
|
|
|
|
HTM_Light0 ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write number of blank answers */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Result)
|
|
|
|
|
{
|
|
|
|
|
NumQstsBlank = Print.NumQsts.All - Print.NumQsts.NotBlank;
|
|
|
|
|
if (NumQstsBlank)
|
|
|
|
|
HTM_Unsigned (NumQstsBlank);
|
|
|
|
|
else
|
|
|
|
|
HTM_Light0 ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write score */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
{
|
|
|
|
|
HTM_Double2Decimals (Print.Score);
|
|
|
|
|
HTM_Txt ("/");
|
|
|
|
|
HTM_Unsigned (Print.NumQsts.All);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write average score per question */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
HTM_Double2Decimals (Print.NumQsts.All ? Print.Score /
|
|
|
|
|
(double) Print.NumQsts.All :
|
|
|
|
|
0.0);
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-06-23 20:28:33 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Write grade */
|
2022-03-25 11:09:51 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT %s_%s LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
ClassDat,The_GetSuffix (),
|
2022-03-25 11:09:51 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
TstPrn_ComputeAndShowGrade (Print.NumQsts.All,Print.Score,Tst_SCORE_MAX);
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Link to show this test */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Result)
|
|
|
|
|
{
|
|
|
|
|
Frm_BeginForm (Gbl.Action.Act == ActSeeMyTstResCrs ? ActSeeOneTstResMe :
|
|
|
|
|
ActSeeOneTstResOth);
|
2021-12-01 01:43:13 +01:00
|
|
|
|
TstPrn_PutParamPrnCod (Print.PrnCod);
|
2021-12-22 00:20:06 +01:00
|
|
|
|
Ico_PutIconLink ("tasks.svg",Ico_BLACK,Txt_View_test);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Frm_EndForm ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (Print.AllowTeachers)
|
|
|
|
|
NumPrintsVisibleByTchs++;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write totals for this user *****/
|
2021-11-18 22:06:06 +01:00
|
|
|
|
TstPrn_ShowPrintsSummaryRow (Usr_ItsMe (UsrDat->UsrCod),NumPrintsVisibleByTchs,
|
2021-10-27 00:58:37 +02:00
|
|
|
|
&NumTotalQsts,TotalScore);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Columns for dates */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("colspan=\"2\" class=\"LINE_BOTTOM %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Column for questions */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LINE_BOTTOM LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Columns for answers */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("colspan=\"2\" class=\"LINE_BOTTOM LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Columns for score */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("colspan=\"2\" class=\"LINE_BOTTOM LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Column for grade */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LINE_BOTTOM LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/* Column for link to show the result */
|
2021-12-20 22:43:32 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LINE_BOTTOM LINE_LEFT %s\"",
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-06-24 02:15:50 +02:00
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
|
2022-03-24 01:18:19 +01:00
|
|
|
|
The_ChangeRowColor ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***************** Write parameter with code of test print ******************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-09 21:07:50 +02:00
|
|
|
|
void TstPrn_PutParamPrnCod (long ExaCod)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-05-09 21:07:50 +02:00
|
|
|
|
Par_PutHiddenParamLong (NULL,"PrnCod",ExaCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***************** Get parameter with code of test print *********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-09 21:07:50 +02:00
|
|
|
|
long TstPrn_GetParamPrnCod (void)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Get code of test print *****/
|
2020-05-09 21:07:50 +02:00
|
|
|
|
return Par_GetParToLong ("PrnCod");
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/****************** Show row with summary of user's tess *********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
static void TstPrn_ShowPrintsSummaryRow (bool ItsMe,
|
2020-06-24 02:15:50 +02:00
|
|
|
|
unsigned NumPrints,
|
|
|
|
|
struct TstPrn_NumQuestions *NumTotalQsts,
|
|
|
|
|
double TotalScore)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Txt_Visible_tests;
|
|
|
|
|
bool ICanViewTotalScore;
|
|
|
|
|
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_STD:
|
|
|
|
|
ICanViewTotalScore = ItsMe &&
|
|
|
|
|
TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ());
|
|
|
|
|
break;
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_DEG_ADM:
|
|
|
|
|
case Rol_CTR_ADM:
|
|
|
|
|
case Rol_INS_ADM:
|
|
|
|
|
ICanViewTotalScore = ItsMe ||
|
2020-05-18 14:34:31 +02:00
|
|
|
|
NumPrints;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
break;
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
ICanViewTotalScore = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ICanViewTotalScore = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Begin row *****/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Row title *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("colspan=\"2\""
|
|
|
|
|
" class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
HTM_TxtColonNBSP (Txt_Visible_tests);
|
|
|
|
|
HTM_Unsigned (NumPrints);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write total number of questions *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (NumPrints)
|
|
|
|
|
HTM_Unsigned (NumTotalQsts->All);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write total number of non-blank answers *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (NumPrints)
|
|
|
|
|
HTM_Unsigned (NumTotalQsts->NotBlank);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write total number of blank answers *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (NumPrints)
|
|
|
|
|
HTM_Unsigned (NumTotalQsts->All - NumTotalQsts->NotBlank);
|
|
|
|
|
HTM_TD_End ();
|
2020-06-23 20:28:33 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write total score *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (ICanViewTotalScore)
|
|
|
|
|
{
|
|
|
|
|
HTM_Double2Decimals (TotalScore);
|
|
|
|
|
HTM_Txt ("/");
|
|
|
|
|
HTM_Unsigned (NumTotalQsts->All);
|
|
|
|
|
}
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write average score per question *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (ICanViewTotalScore)
|
|
|
|
|
HTM_Double2Decimals (NumTotalQsts->All ? TotalScore / (double) NumTotalQsts->All :
|
|
|
|
|
0.0);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Write grade over Tst_SCORE_MAX *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RM DAT_STRONG_%s LINE_TOP LINE_BOTTOM LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
if (ICanViewTotalScore)
|
|
|
|
|
TstPrn_ComputeAndShowGrade (NumTotalQsts->All,TotalScore,Tst_SCORE_MAX);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-07-08 15:00:17 +02:00
|
|
|
|
/***** Last cell *****/
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"DAT_STRONG_%s LINE_TOP LINE_BOTTOM LINE_LEFT %s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix (),
|
2022-03-19 02:05:53 +01:00
|
|
|
|
The_GetColorRows ());
|
2021-07-08 15:00:17 +02:00
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End row *****/
|
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/*********************** Show one test of another user ***********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_ShowOnePrint (void)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
extern const char *Hlp_ASSESSMENT_Tests_results;
|
2020-05-17 02:28:30 +02:00
|
|
|
|
extern const char *Txt_Result;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
|
|
|
|
|
extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME];
|
|
|
|
|
extern const char *Txt_Questions;
|
2020-06-22 19:27:23 +02:00
|
|
|
|
extern const char *Txt_Answers;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
extern const char *Txt_Score;
|
|
|
|
|
extern const char *Txt_Grade;
|
|
|
|
|
extern const char *Txt_Tags;
|
2021-12-31 14:51:44 +01:00
|
|
|
|
static const char *ClassPhoto[PhoSha_NUM_SHAPES] =
|
2021-12-01 01:43:13 +01:00
|
|
|
|
{
|
2021-12-31 14:51:44 +01:00
|
|
|
|
[PhoSha_SHAPE_CIRCLE ] = "PHOTOC45x60",
|
|
|
|
|
[PhoSha_SHAPE_ELLIPSE ] = "PHOTOE45x60",
|
|
|
|
|
[PhoSha_SHAPE_OVAL ] = "PHOTOO45x60",
|
|
|
|
|
[PhoSha_SHAPE_RECTANGLE] = "PHOTOR45x60",
|
2021-12-01 01:43:13 +01:00
|
|
|
|
};
|
2020-05-07 18:33:26 +02:00
|
|
|
|
struct TstPrn_Print Print;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
Dat_StartEndTime_t StartEndTime;
|
|
|
|
|
char *Id;
|
2020-06-23 18:10:20 +02:00
|
|
|
|
struct TstRes_ICanView ICanView;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Get the code of the test *****/
|
2020-05-11 02:28:38 +02:00
|
|
|
|
TstPrn_ResetPrint (&Print);
|
2021-04-25 20:36:48 +02:00
|
|
|
|
if ((Print.PrnCod = TstPrn_GetParamPrnCod ()) <= 0)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongTestExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Get test data *****/
|
2020-05-10 01:42:30 +02:00
|
|
|
|
TstPrn_GetPrintDataByPrnCod (&Print);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-23 18:10:20 +02:00
|
|
|
|
/***** Get if I can see print result and score *****/
|
|
|
|
|
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
|
2021-10-26 17:33:20 +02:00
|
|
|
|
TstCfg_GetConfig (); // To get visibility
|
2020-06-23 18:10:20 +02:00
|
|
|
|
TstRes_CheckIfICanSeePrintResult (&Print,Gbl.Usrs.Other.UsrDat.UsrCod,&ICanView);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-06-23 18:10:20 +02:00
|
|
|
|
if (ICanView.Result) // I am allowed to view this test print result
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Get questions and user's answers of the test from database *****/
|
2021-11-26 01:53:31 +01:00
|
|
|
|
if (!TstPrn_GetPrintQuestionsFromDB (&Print))
|
|
|
|
|
Err_WrongExamExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Begin box *****/
|
2020-05-17 02:28:30 +02:00
|
|
|
|
Box_BoxBegin (NULL,Txt_Result,
|
2020-04-02 03:28:08 +02:00
|
|
|
|
NULL,NULL,
|
|
|
|
|
Hlp_ASSESSMENT_Tests_results,Box_NOT_CLOSABLE);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Lay_WriteHeaderClassPhoto (false,false,
|
|
|
|
|
Gbl.Hierarchy.Ins.InsCod,
|
|
|
|
|
Gbl.Hierarchy.Deg.DegCod,
|
|
|
|
|
Gbl.Hierarchy.Crs.CrsCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Begin table *****/
|
|
|
|
|
HTM_TABLE_BeginWideMarginPadding (10);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** User *****/
|
|
|
|
|
/* Get data of the user who made the test */
|
|
|
|
|
if (!Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (&Gbl.Usrs.Other.UsrDat,
|
|
|
|
|
Usr_DONT_GET_PREFS,
|
|
|
|
|
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
|
|
|
|
|
Err_WrongUserExit ();
|
|
|
|
|
if (!Usr_CheckIfICanViewTstExaMchResult (&Gbl.Usrs.Other.UsrDat))
|
|
|
|
|
Err_NoPermissionExit ();
|
|
|
|
|
|
|
|
|
|
/* User */
|
|
|
|
|
HTM_TR_Begin (NULL);
|
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_ROLES_SINGUL_Abc[Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs][Gbl.Usrs.Other.UsrDat.Sex]);
|
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
2022-04-05 01:00:24 +02:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
ID_WriteUsrIDs (&Gbl.Usrs.Other.UsrDat,NULL);
|
|
|
|
|
HTM_TxtF (" %s",Gbl.Usrs.Other.UsrDat.Surname1);
|
|
|
|
|
if (Gbl.Usrs.Other.UsrDat.Surname2[0])
|
|
|
|
|
HTM_TxtF (" %s",Gbl.Usrs.Other.UsrDat.Surname2);
|
|
|
|
|
if (Gbl.Usrs.Other.UsrDat.FrstName[0])
|
|
|
|
|
HTM_TxtF (", %s",Gbl.Usrs.Other.UsrDat.FrstName);
|
|
|
|
|
HTM_BR ();
|
2021-12-01 01:43:13 +01:00
|
|
|
|
Pho_ShowUsrPhotoIfAllowed (&Gbl.Usrs.Other.UsrDat,
|
2021-12-02 08:39:18 +01:00
|
|
|
|
ClassPhoto[Gbl.Prefs.PhotoShape],Pho_ZOOM,
|
2021-12-01 01:43:13 +01:00
|
|
|
|
false);
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TD_End ();
|
|
|
|
|
|
|
|
|
|
HTM_TR_End ();
|
|
|
|
|
|
|
|
|
|
/***** Start/end time (for user in this test print) *****/
|
|
|
|
|
for (StartEndTime = (Dat_StartEndTime_t) 0;
|
|
|
|
|
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
|
|
|
|
|
StartEndTime++)
|
|
|
|
|
{
|
|
|
|
|
if (asprintf (&Id,"tst_date_%u",(unsigned) StartEndTime) < 0)
|
|
|
|
|
Err_NotEnoughMemoryExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_START_END_TIME[StartEndTime]);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("id=\"%s\" class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
Id,The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
Dat_WriteLocalDateHMSFromUTC (Id,Print.TimeUTC[StartEndTime],
|
|
|
|
|
Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA,
|
|
|
|
|
true,true,true,0x7);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
free (Id);
|
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Number of questions *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_Questions);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Unsigned (Print.NumQsts.All);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Number of answers *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_Answers);
|
|
|
|
|
HTM_TD_End ();
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_Unsigned (Print.NumQsts.NotBlank);
|
|
|
|
|
HTM_TD_End ();
|
2020-06-22 19:27:23 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Score *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_Score);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
{
|
|
|
|
|
HTM_STRONG_Begin ();
|
|
|
|
|
HTM_Double2Decimals (Print.Score);
|
|
|
|
|
HTM_Txt ("/");
|
|
|
|
|
HTM_Unsigned (Print.NumQsts.All);
|
|
|
|
|
HTM_STRONG_End ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Grade *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_Grade);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
if (ICanView.Score)
|
|
|
|
|
{
|
|
|
|
|
HTM_STRONG_Begin ();
|
|
|
|
|
TstPrn_ComputeAndShowGrade (Print.NumQsts.All,Print.Score,Tst_SCORE_MAX);
|
|
|
|
|
HTM_STRONG_End ();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Ico_PutIconNotVisible ();
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Tags present in this test *****/
|
|
|
|
|
HTM_TR_Begin (NULL);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"RT DAT_STRONG_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TxtColon (Txt_Tags);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2022-03-26 21:08:25 +01:00
|
|
|
|
HTM_TD_Begin ("class=\"LB DAT_%s\"",
|
2022-04-05 01:00:24 +02:00
|
|
|
|
The_GetSuffix ());
|
2021-10-27 00:58:37 +02:00
|
|
|
|
TstPrn_ShowTagsPresentInAPrint (Print.PrnCod);
|
|
|
|
|
HTM_TD_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
HTM_TR_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** Write answers and solutions *****/
|
|
|
|
|
TstPrn_ShowPrintAnswers (&Gbl.Usrs.Other.UsrDat,
|
|
|
|
|
Print.NumQsts.All,
|
|
|
|
|
Print.PrintedQuestions,
|
|
|
|
|
Print.TimeUTC,
|
|
|
|
|
TstCfg_GetConfigVisibility ());
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 00:58:37 +02:00
|
|
|
|
/***** End table *****/
|
|
|
|
|
HTM_TABLE_End ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** End box *****/
|
|
|
|
|
Box_BoxEnd ();
|
|
|
|
|
}
|
2021-10-26 09:23:06 +02:00
|
|
|
|
else // I am not allowed to view this test
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_NoPermissionExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
2020-06-23 18:10:20 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/****************** Get if I can see print result and score ******************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void TstRes_CheckIfICanSeePrintResult (const struct TstPrn_Print *Print,
|
|
|
|
|
long UsrCod,
|
|
|
|
|
struct TstRes_ICanView *ICanView)
|
|
|
|
|
{
|
|
|
|
|
/***** Check if I can view print result and score *****/
|
|
|
|
|
switch (Gbl.Usrs.Me.Role.Logged)
|
|
|
|
|
{
|
|
|
|
|
case Rol_STD:
|
|
|
|
|
// Depends on whether the print is sent or not
|
|
|
|
|
// if the print is not sent ==> I can not view results
|
|
|
|
|
ICanView->Result = Print->Sent && Usr_ItsMe (UsrCod);
|
|
|
|
|
|
|
|
|
|
if (ICanView->Result)
|
|
|
|
|
// Depends on 5 visibility icons associated to tests
|
|
|
|
|
ICanView->Score = TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ());
|
|
|
|
|
else
|
|
|
|
|
ICanView->Score = false;
|
|
|
|
|
break;
|
|
|
|
|
case Rol_NET:
|
|
|
|
|
case Rol_TCH:
|
|
|
|
|
case Rol_DEG_ADM:
|
|
|
|
|
case Rol_CTR_ADM:
|
|
|
|
|
case Rol_INS_ADM:
|
|
|
|
|
// Depends on whether the print is sent or not, and whether teachers are allowed
|
|
|
|
|
// if the print is not sent ==> I can not view results
|
|
|
|
|
// if teachers are not allowed ==> I can not view results (except if the print is mine)
|
|
|
|
|
ICanView->Result =
|
|
|
|
|
ICanView->Score = Print->Sent && (Print->AllowTeachers || Usr_ItsMe (UsrCod));
|
|
|
|
|
break;
|
|
|
|
|
case Rol_SYS_ADM:
|
|
|
|
|
ICanView->Result =
|
|
|
|
|
ICanView->Score = true;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
ICanView->Result =
|
|
|
|
|
ICanView->Score = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/************************ Show test tags in this test ************************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
static void TstPrn_ShowTagsPresentInAPrint (long PrnCod)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
unsigned NumTags;
|
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
/***** Get all tags of questions in this test print *****/
|
|
|
|
|
NumTags = Tst_DB_GetTagsPresentInAPrint (&mysql_res,PrnCod);
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Tag_ShowTagList (NumTags,mysql_res);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/**************** Show user's and correct answers of a test ******************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_ShowPrintAnswers (struct UsrData *UsrDat,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
unsigned NumQsts,
|
|
|
|
|
struct TstPrn_PrintedQuestion PrintedQuestions[TstCfg_MAX_QUESTIONS_PER_TEST],
|
|
|
|
|
time_t TimeUTC[Dat_NUM_START_END_TIME],
|
2020-05-22 20:10:45 +02:00
|
|
|
|
unsigned Visibility)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd;
|
2021-10-24 21:35:42 +02:00
|
|
|
|
struct Qst_Question Question;
|
2020-05-07 19:54:24 +02:00
|
|
|
|
bool QuestionExists;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-04-26 17:29:04 +02:00
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < NumQsts;
|
2022-03-24 01:18:19 +01:00
|
|
|
|
QstInd++, The_ChangeRowColor ())
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-04-03 19:13:00 +02:00
|
|
|
|
/***** Create test question *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstConstructor (&Question);
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Question.QstCod = PrintedQuestions[QstInd].QstCod;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-03 19:13:00 +02:00
|
|
|
|
/***** Get question data *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
QuestionExists = Qst_GetQstDataFromDB (&Question);
|
2020-05-07 19:54:24 +02:00
|
|
|
|
|
|
|
|
|
/***** Write questions and answers *****/
|
2020-06-24 20:10:57 +02:00
|
|
|
|
TstPrn_WriteQstAndAnsExam (UsrDat,
|
2021-04-26 17:29:04 +02:00
|
|
|
|
PrintedQuestions,QstInd,
|
2020-06-24 20:10:57 +02:00
|
|
|
|
TimeUTC,
|
|
|
|
|
&Question,QuestionExists,
|
|
|
|
|
Visibility);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-03 19:13:00 +02:00
|
|
|
|
/***** Destroy test question *****/
|
2021-10-24 21:35:42 +02:00
|
|
|
|
Qst_QstDestructor (&Question);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/**************** Get data of a test using its test code *********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-10 01:42:30 +02:00
|
|
|
|
void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
|
|
|
|
|
/***** Make database query *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
if (Tst_DB_GetPrintDataByPrnCod (&mysql_res,Print->PrnCod) == 1)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
|
|
|
|
|
/* Get user code (row[0]) */
|
|
|
|
|
Gbl.Usrs.Other.UsrDat.UsrCod = Str_ConvertStrCodToLongCod (row[0]);
|
|
|
|
|
|
|
|
|
|
/* Get date-time (row[1] and row[2] hold UTC date-time) */
|
2021-09-18 18:22:26 +02:00
|
|
|
|
Print->TimeUTC[Dat_STR_TIME] = Dat_GetUNIXTimeFromStr (row[1]);
|
|
|
|
|
Print->TimeUTC[Dat_END_TIME] = Dat_GetUNIXTimeFromStr (row[2]);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
/* Get number of questions (row[3])
|
|
|
|
|
and number of questions not blank (row[4]) */
|
|
|
|
|
if (sscanf (row[3],"%u",&Print->NumQsts.All ) != 1)
|
|
|
|
|
Print->NumQsts.All = 0;
|
2020-06-24 02:15:50 +02:00
|
|
|
|
if (sscanf (row[4],"%u",&Print->NumQsts.NotBlank) != 1)
|
|
|
|
|
Print->NumQsts.NotBlank = 0;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
/* Get if print has been sent (row[5])
|
|
|
|
|
and if teachers are allowed to see this test print (row[6]) */
|
|
|
|
|
Print->Sent = (row[5][0] == 'Y');
|
2020-05-07 18:33:26 +02:00
|
|
|
|
Print->AllowTeachers = (row[6][0] == 'Y');
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-16 21:03:22 +02:00
|
|
|
|
/* Get score (row[7]) */
|
2020-04-02 03:28:08 +02:00
|
|
|
|
Str_SetDecimalPointToUS (); // To get the decimal point as a dot
|
2020-05-07 18:33:26 +02:00
|
|
|
|
if (sscanf (row[7],"%lf",&Print->Score) != 1)
|
|
|
|
|
Print->Score = 0.0;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
Str_SetDecimalPointToLocal (); // Return to local system
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-05-11 02:28:38 +02:00
|
|
|
|
TstPrn_ResetPrintExceptPrnCod (Print);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/************* Get the questions of a test print from database ***************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-11-26 01:53:31 +01:00
|
|
|
|
bool TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
2020-04-14 02:37:24 +02:00
|
|
|
|
unsigned NumQsts;
|
2021-04-26 17:29:04 +02:00
|
|
|
|
unsigned QstInd;
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Get questions of a test print from database *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
NumQsts = Tst_DB_GetPrintQuestions (&mysql_res,Print->PrnCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-10 01:42:30 +02:00
|
|
|
|
/***** Get questions *****/
|
2020-06-24 02:15:50 +02:00
|
|
|
|
if (NumQsts == Print->NumQsts.All)
|
2021-04-26 17:29:04 +02:00
|
|
|
|
for (QstInd = 0;
|
|
|
|
|
QstInd < NumQsts;
|
|
|
|
|
QstInd++)
|
2020-04-14 02:37:24 +02:00
|
|
|
|
{
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-04-30 20:15:21 +02:00
|
|
|
|
/* Get question code (row[0]) */
|
2021-04-26 17:29:04 +02:00
|
|
|
|
if ((Print->PrintedQuestions[QstInd].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_WrongQuestionExit ();
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-12 02:45:03 +02:00
|
|
|
|
/* Get score (row[1]) */
|
2020-05-11 14:56:49 +02:00
|
|
|
|
Str_SetDecimalPointToUS (); // To get the decimal point as a dot
|
2021-04-26 17:29:04 +02:00
|
|
|
|
if (sscanf (row[1],"%lf",&Print->PrintedQuestions[QstInd].Score) != 1)
|
2021-04-26 15:27:27 +02:00
|
|
|
|
Err_ShowErrorAndExit ("Wrong question score.");
|
2020-05-11 14:56:49 +02:00
|
|
|
|
Str_SetDecimalPointToLocal (); // Return to local system
|
|
|
|
|
|
2021-10-27 20:47:01 +02:00
|
|
|
|
/* Get indexes for this question (row[2])
|
|
|
|
|
and answers selected by user for this question (row[3]) */
|
2021-04-26 17:29:04 +02:00
|
|
|
|
Str_Copy (Print->PrintedQuestions[QstInd].StrIndexes,row[2],
|
|
|
|
|
sizeof (Print->PrintedQuestions[QstInd].StrIndexes) - 1);
|
|
|
|
|
Str_Copy (Print->PrintedQuestions[QstInd].StrAnswers,row[3],
|
|
|
|
|
sizeof (Print->PrintedQuestions[QstInd].StrAnswers) - 1);
|
2020-04-14 02:37:24 +02:00
|
|
|
|
}
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
2020-04-14 02:37:24 +02:00
|
|
|
|
|
2021-11-26 01:53:31 +01:00
|
|
|
|
return (NumQsts == Print->NumQsts.All);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/********************** Remove test prints made by a user ********************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2020-05-18 22:59:07 +02:00
|
|
|
|
/***** Remove test prints questions for the given user *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
Tst_DB_RemovePrintQuestionsMadeByUsrInAllCrss (UsrCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2020-05-18 22:59:07 +02:00
|
|
|
|
/***** Remove test prints made by the given user *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
Tst_DB_RemovePrintsMadeByUsrInAllCrss (UsrCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/************** Remove test prints made by a user in a course ****************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-27 20:47:01 +02:00
|
|
|
|
/***** Remove test prints questions for the given user *****/
|
|
|
|
|
Tst_DB_RemovePrintQuestionsMadeByUsrInCrs (UsrCod,CrsCod);
|
|
|
|
|
|
|
|
|
|
/***** Remove test prints made by the given user *****/
|
|
|
|
|
Tst_DB_RemovePrintsMadeByUsrInCrs (UsrCod,CrsCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/****************** Remove all test prints made in a course ******************/
|
2020-04-02 03:28:08 +02:00
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2020-05-18 14:34:31 +02:00
|
|
|
|
void TstPrn_RemoveCrsPrints (long CrsCod)
|
2020-04-02 03:28:08 +02:00
|
|
|
|
{
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Remove questions of tests made in the course *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
Tst_DB_RemovePrintQuestionsMadeInCrs (CrsCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
|
2021-10-26 09:23:06 +02:00
|
|
|
|
/***** Remove tests made in the course *****/
|
2021-10-27 20:47:01 +02:00
|
|
|
|
Tst_DB_RemovePrintsMadeByInCrs (CrsCod);
|
2020-04-02 03:28:08 +02:00
|
|
|
|
}
|
2021-10-26 09:23:06 +02:00
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
/***************** Get number of test prints generated by me *****************/
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
unsigned TstPrn_GetNumPrintsGeneratedByMe (void)
|
|
|
|
|
{
|
|
|
|
|
MYSQL_RES *mysql_res;
|
|
|
|
|
MYSQL_ROW row;
|
|
|
|
|
unsigned NumRows;
|
|
|
|
|
unsigned NumPrintsGeneratedByMe = 0;
|
|
|
|
|
|
|
|
|
|
if (Gbl.Usrs.Me.IBelongToCurrentCrs)
|
|
|
|
|
{
|
|
|
|
|
/***** Get number of test prints generated by me from database *****/
|
|
|
|
|
NumRows = Tst_DB_GetNumPrintsGeneratedByMe (&mysql_res);
|
|
|
|
|
|
|
|
|
|
if (NumRows == 0)
|
|
|
|
|
NumPrintsGeneratedByMe = 0;
|
|
|
|
|
else if (NumRows == 1)
|
|
|
|
|
{
|
|
|
|
|
/* Get number of hits */
|
|
|
|
|
row = mysql_fetch_row (mysql_res);
|
|
|
|
|
if (row[0] == NULL)
|
|
|
|
|
NumPrintsGeneratedByMe = 0;
|
|
|
|
|
else if (sscanf (row[0],"%u",&NumPrintsGeneratedByMe) != 1)
|
|
|
|
|
NumPrintsGeneratedByMe = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
Err_ShowErrorAndExit ("Error when getting number of tests.");
|
|
|
|
|
|
|
|
|
|
/***** Free structure that stores the query result *****/
|
|
|
|
|
DB_FreeMySQLResult (&mysql_res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NumPrintsGeneratedByMe;
|
|
|
|
|
}
|