Version19.149.1

This commit is contained in:
acanas 2020-03-18 18:49:45 +01:00
parent 6e9aed2d76
commit f818cf372d
6 changed files with 317 additions and 243 deletions

View File

@ -497,7 +497,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.149 (2020-03-18)" #define Log_PLATFORM_VERSION "SWAD 19.149.1 (2020-03-18)"
#define CSS_FILE "swad19.146.css" #define CSS_FILE "swad19.146.css"
#define JS_FILE "swad19.91.1.js" #define JS_FILE "swad19.91.1.js"
/* /*
@ -524,6 +524,7 @@ Param
// TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores // TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores
// TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo // TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo
Version 19.149.1: Mar 18, 2020 Code refactoring in tests. (283094 lines)
Version 19.149: Mar 18, 2020 Code refactoring in tests. (283020 lines) Version 19.149: Mar 18, 2020 Code refactoring in tests. (283020 lines)
Version 19.148.3: Mar 17, 2020 Code refactoring in tests. (282916 lines) Version 19.148.3: Mar 17, 2020 Code refactoring in tests. (282916 lines)
Version 19.148.2: Mar 17, 2020 Code refactoring in tests. (282868 lines) Version 19.148.2: Mar 17, 2020 Code refactoring in tests. (282868 lines)

View File

@ -1875,6 +1875,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
MYSQL_ROW row; MYSQL_ROW row;
long QstCod; long QstCod;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
unsigned QstInd; unsigned QstInd;
unsigned MaxQstInd; unsigned MaxQstInd;
@ -1909,7 +1910,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
row[1] QstCod row[1] QstCod
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/* Get question index (row[0]) */ /* Get question index (row[0]) */
QstInd = Str_ConvertStrToUnsigned (row[0]); QstInd = Str_ConvertStrToUnsigned (row[0]);
@ -1996,6 +1997,7 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd)
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
bool QstExists; bool QstExists;
Tst_AnswerType_t AnswerType;
struct Media Media; struct Media Media;
/***** Get question from database *****/ /***** Get question from database *****/
@ -2030,8 +2032,8 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd)
HTM_DIV_Begin ("class=\"DAT_SMALL\""); HTM_DIV_Begin ("class=\"DAT_SMALL\"");
if (QstExists) if (QstExists)
{ {
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
HTM_Txt (Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); HTM_Txt (Txt_TST_STR_ANSWER_TYPES[AnswerType]);
} }
HTM_DIV_End (); HTM_DIV_End ();
@ -2069,7 +2071,7 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd)
Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT");
/* Show answers */ /* Show answers */
Tst_WriteAnswersEdit (QstCod); Tst_WriteAnswersEdit (QstCod,AnswerType);
} }
else else
{ {

View File

@ -192,7 +192,8 @@ static void Mch_PutIfAnswered (const struct Match *Match,bool Answered);
static void Mch_PutIconToRemoveMyAnswer (const struct Match *Match); static void Mch_PutIconToRemoveMyAnswer (const struct Match *Match);
static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match); static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match);
static void Mch_WriteAnswersMatchResult (const struct Match *Match, static void Mch_WriteAnswersMatchResult (const struct Match *Match,
const char *Class,bool ShowResult); const char *Class,bool ShowResult,
Tst_AnswerType_t AnswerType);
static bool Mch_ShowQuestionAndAnswersStd (const struct Match *Match, static bool Mch_ShowQuestionAndAnswersStd (const struct Match *Match,
const struct Mch_UsrAnswer *UsrAnswer, const struct Mch_UsrAnswer *UsrAnswer,
Mch_Update_t Update); Mch_Update_t Update);
@ -2863,6 +2864,7 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
extern const char *Txt_Question_removed; extern const char *Txt_Question_removed;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
Tst_AnswerType_t AnswerType;
struct Media Media; struct Media Media;
/***** Trivial check: do not show anything on match start and end *****/ /***** Trivial check: do not show anything on match start and end *****/
@ -2888,8 +2890,8 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
/***** Show question *****/ /***** Show question *****/
/* Get answer type (row[0]) */ /* Get answer type (row[0]) */
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]);
if (Gbl.Test.AnswerType != Tst_ANS_UNIQUE_CHOICE) if (AnswerType != Tst_ANS_UNIQUE_CHOICE)
Lay_ShowErrorAndExit ("Wrong answer type."); Lay_ShowErrorAndExit ("Wrong answer type.");
/* Begin container */ /* Begin container */
@ -2919,15 +2921,17 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
/* Write answers */ /* Write answers */
Mch_WriteAnswersMatchResult (Match, Mch_WriteAnswersMatchResult (Match,
"MCH_TCH_ANS", "MCH_TCH_ANS",
false); // Don't show result false, // Don't show result
else // Match is paused, not being played AnswerType);
else // Match is paused, not being played
Mch_ShowWaitImage (Txt_MATCH_Paused); Mch_ShowWaitImage (Txt_MATCH_Paused);
break; break;
case Mch_RESULTS: case Mch_RESULTS:
/* Write answers with results */ /* Write answers with results */
Mch_WriteAnswersMatchResult (Match, Mch_WriteAnswersMatchResult (Match,
"MCH_TCH_ANS", "MCH_TCH_ANS",
true); // Show result true, // Show result
AnswerType);
break; break;
default: default:
/* Don't write anything */ /* Don't write anything */
@ -2946,10 +2950,11 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
/*****************************************************************************/ /*****************************************************************************/
static void Mch_WriteAnswersMatchResult (const struct Match *Match, static void Mch_WriteAnswersMatchResult (const struct Match *Match,
const char *Class,bool ShowResult) const char *Class,bool ShowResult,
Tst_AnswerType_t AnswerType)
{ {
/***** Write answer depending on type *****/ /***** Write answer depending on type *****/
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE) if (AnswerType == Tst_ANS_UNIQUE_CHOICE)
Tst_WriteChoiceAnsViewMatch (Match->MchCod,Match->Status.QstInd,Match->Status.QstCod, Tst_WriteChoiceAnsViewMatch (Match->MchCod,Match->Status.QstInd,Match->Status.QstCod,
Match->Status.NumCols,Class,ShowResult); Match->Status.NumCols,Class,ShowResult);
else else
@ -3786,6 +3791,7 @@ static void Mch_RemoveMyAnswerToMatchQuestion (const struct Match *Match)
static double Mch_ComputeScore (unsigned NumQsts) static double Mch_ComputeScore (unsigned NumQsts)
{ {
unsigned NumQst; unsigned NumQst;
Tst_AnswerType_t AnswerType = Tst_ANS_UNIQUE_CHOICE;
struct Tst_Answer Answer; struct Tst_Answer Answer;
double ScoreThisQst; double ScoreThisQst;
bool AnswerIsNotBlank; bool AnswerIsNotBlank;
@ -3807,7 +3813,7 @@ static double Mch_ComputeScore (unsigned NumQsts)
Tst_GetCorrectAnswersFromDB (Gbl.Test.QstCodes[NumQst],&Answer); Tst_GetCorrectAnswersFromDB (Gbl.Test.QstCodes[NumQst],&Answer);
/***** Compute the total score of this question *****/ /***** Compute the total score of this question *****/
Tst_ComputeScoreQst (&Answer, Tst_ComputeScoreQst (AnswerType,&Answer,
Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank); Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
/***** Compute total score *****/ /***** Compute total score *****/

View File

@ -175,9 +175,11 @@ static void Tst_ListOneOrMoreQuestionsForSelection (unsigned long NumRows,
MYSQL_RES *mysql_res); MYSQL_RES *mysql_res);
static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod); static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod);
static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,bool Shuffle); static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,bool Shuffle);
static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat,
unsigned NumQst,long QstCod, unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,
unsigned Visibility, unsigned Visibility,
double *ScoreThisQst,bool *AnswerIsNotBlank); double *ScoreThisQst,bool *AnswerIsNotBlank);
@ -190,9 +192,12 @@ static void Tst_WriteTFAnsAssessTest (struct UsrData *UsrDat,
double *ScoreThisQst, double *ScoreThisQst,
bool *AnswerIsNotBlank); bool *AnswerIsNotBlank);
static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle); static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,
bool Shuffle);
static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
unsigned NumQst, unsigned NumQst,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
MYSQL_RES *mysql_res, MYSQL_RES *mysql_res,
unsigned Visibility, unsigned Visibility,
@ -237,12 +242,14 @@ static int Tst_CountNumTagsInList (void);
static int Tst_CountNumAnswerTypesInList (void); static int Tst_CountNumAnswerTypesInList (void);
static void Tst_PutFormEditOneQst (long QstCod, static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer, const struct Tst_Answer *Answer,
char Stem[Cns_MAX_BYTES_TEXT + 1], char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]); char Feedback[Cns_MAX_BYTES_TEXT + 1]);
static void Tst_PutFloatInputField (const char *Label,const char *Field, static void Tst_PutFloatInputField (const char *Label,const char *Field,
double Value); double Value,Tst_AnswerType_t AnswerType);
static void Tst_PutTFInputField (const struct Tst_Answer *Answer, static void Tst_PutTFInputField (Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer,
const char *Label,char Value); const char *Label,char Value);
static void Tst_FreeTextChoiceAnswers (struct Tst_Answer *Answer); static void Tst_FreeTextChoiceAnswers (struct Tst_Answer *Answer);
@ -255,6 +262,7 @@ static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question,
static void Tst_GetQstDataFromDB (long QstCod, static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question, struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
char Stem[Cns_MAX_BYTES_TEXT + 1], char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]); char Feedback[Cns_MAX_BYTES_TEXT + 1]);
@ -264,10 +272,12 @@ static void Tst_GetMediaFromDB (long CrsCod,long QstCod,int NumOpt,
static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr); static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
static long Tst_GetQstFromForm (struct Tst_Question *Question, static long Tst_GetQstFromForm (struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
char *Stem,char *Feedback); char *Stem,char *Feedback);
static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, static void Tst_MoveMediaToDefinitiveDirectories (long QstCod,
struct Tst_Question *Question, struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
static long Tst_GetTagCodFromTagTxt (const char *TagTxt); static long Tst_GetTagCodFromTagTxt (const char *TagTxt);
@ -283,9 +293,12 @@ static void Tst_RemoveOneQstFromDB (long CrsCod,long QstCod);
static long Tst_GetQstCod (void); static long Tst_GetQstCod (void);
static long Tst_InsertOrUpdateQstIntoDB (long QstCod, static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
const struct Tst_Question *Question); const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType);
static void Tst_InsertTagsIntoDB (long QstCod); static void Tst_InsertTagsIntoDB (long QstCod);
static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Answer *Answer); static void Tst_InsertAnswersIntoDB (long QstCod,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer);
static void Tst_RemAnsFromQst (long QstCod); static void Tst_RemAnsFromQst (long QstCod);
static void Tst_RemTagsFromQst (long QstCod); static void Tst_RemTagsFromQst (long QstCod);
@ -1004,6 +1017,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
{ {
extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES];
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
bool IsVisibleQstAndAnsTxt = TsV_IsVisibleQstAndAnsTxt (Visibility); bool IsVisibleQstAndAnsTxt = TsV_IsVisibleQstAndAnsTxt (Visibility);
/* /*
@ -1018,7 +1032,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
row[8] Score row[8] Score
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
@ -1029,9 +1043,9 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
HTM_DIV_End (); HTM_DIV_End ();
/***** Write answer type (row[1]) *****/ /***** Write answer type (row[1]) *****/
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
HTM_DIV_Begin ("class=\"DAT_SMALL\""); HTM_DIV_Begin ("class=\"DAT_SMALL\"");
HTM_Txt (Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); HTM_Txt (Txt_TST_STR_ANSWER_TYPES[AnswerType]);
HTM_DIV_End (); HTM_DIV_End ();
HTM_TD_End (); HTM_TD_End ();
@ -1054,10 +1068,10 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
switch (ActionToDoWithQuestions) switch (ActionToDoWithQuestions)
{ {
case Tst_SHOW_TEST_TO_ANSWER: case Tst_SHOW_TEST_TO_ANSWER:
Tst_WriteAnswersTestToAnswer (NumQst,QstCod,(row[2][0] == 'Y')); Tst_WriteAnswersTestToAnswer (NumQst,QstCod,AnswerType,(row[2][0] == 'Y'));
break; break;
case Tst_SHOW_TEST_RESULT: case Tst_SHOW_TEST_RESULT:
Tst_WriteAnswersTestResult (UsrDat,NumQst,QstCod, Tst_WriteAnswersTestResult (UsrDat,NumQst,QstCod,AnswerType,
Visibility, Visibility,
ScoreThisQst,AnswerIsNotBlank); ScoreThisQst,AnswerIsNotBlank);
@ -2891,6 +2905,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
static unsigned UniqueId = 0; static unsigned UniqueId = 0;
char *Id; char *Id;
@ -2900,7 +2915,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
double TotalScoreThisQst; double TotalScoreThisQst;
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get and show questvoidion data *****/ /***** Get and show questvoidion data *****/
if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) if (Tst_GetOneQuestionByCod (QstCod,&mysql_res))
@ -2949,9 +2964,9 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
HTM_DIV_End (); HTM_DIV_End ();
/* Write answer type (row[1]) */ /* Write answer type (row[1]) */
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
HTM_DIV_Begin ("class=\"DAT_SMALL\""); HTM_DIV_Begin ("class=\"DAT_SMALL\"");
HTM_Txt (Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); HTM_Txt (Txt_TST_STR_ANSWER_TYPES[AnswerType]);
HTM_DIV_End (); HTM_DIV_End ();
HTM_TD_End (); HTM_TD_End ();
@ -2980,8 +2995,8 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
/* Write if shuffle is enabled (row[2]) */ /* Write if shuffle is enabled (row[2]) */
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || if (AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) AnswerType == Tst_ANS_MULTIPLE_CHOICE)
{ {
Frm_StartForm (ActChgShfTstQst); Frm_StartForm (ActChgShfTstQst);
Tst_PutParamQstCod (QstCod); Tst_PutParamQstCod (QstCod);
@ -3012,7 +3027,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
/* Write feedback (row[4]) and answers */ /* Write feedback (row[4]) and answers */
Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT");
Tst_WriteAnswersEdit (QstCod); Tst_WriteAnswersEdit (QstCod,AnswerType);
HTM_TD_End (); HTM_TD_End ();
/* Get number of hits /* Get number of hits
@ -3041,7 +3056,8 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
/* Write average score */ /* Write average score */
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
if (NumHitsThisQst) if (NumHitsThisQst)
HTM_Double2Decimals (TotalScoreThisQst / (double) NumHitsThisQst); HTM_Double2Decimals (TotalScoreThisQst /
(double) NumHitsThisQst);
else else
HTM_Txt ("N.A."); HTM_Txt ("N.A.");
HTM_TD_End (); HTM_TD_End ();
@ -3054,7 +3070,8 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
/* Write average score (not blank) */ /* Write average score (not blank) */
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
if (NumHitsNotBlankThisQst) if (NumHitsNotBlankThisQst)
HTM_Double2Decimals (TotalScoreThisQst / (double) NumHitsNotBlankThisQst); HTM_Double2Decimals (TotalScoreThisQst /
(double) NumHitsNotBlankThisQst);
else else
HTM_Txt ("N.A."); HTM_Txt ("N.A.");
HTM_TD_End (); HTM_TD_End ();
@ -3155,13 +3172,14 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
static unsigned UniqueId = 0; static unsigned UniqueId = 0;
char *Id; char *Id;
time_t TimeUTC; time_t TimeUTC;
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get and show questvoidion data *****/ /***** Get and show questvoidion data *****/
if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) if (Tst_GetOneQuestionByCod (QstCod,&mysql_res))
@ -3219,9 +3237,9 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
HTM_TD_End (); HTM_TD_End ();
/* Write the question type (row[1]) */ /* Write the question type (row[1]) */
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
HTM_TxtF ("%s ",Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); HTM_TxtF ("%s ",Txt_TST_STR_ANSWER_TYPES[AnswerType]);
HTM_TD_End (); HTM_TD_End ();
/* Write if shuffle is enabled (row[2]) */ /* Write if shuffle is enabled (row[2]) */
@ -3248,7 +3266,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT");
/* Write answers */ /* Write answers */
Tst_WriteAnswersEdit (QstCod); Tst_WriteAnswersEdit (QstCod,AnswerType);
HTM_TD_End (); HTM_TD_End ();
/***** End table row *****/ /***** End table row *****/
@ -3346,7 +3364,7 @@ void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Answer *Answer)
/**************** Get and write the answers of a test question ***************/ /**************** Get and write the answers of a test question ***************/
/*****************************************************************************/ /*****************************************************************************/
void Tst_WriteAnswersEdit (long QstCod) void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType)
{ {
extern const char *Txt_TST_Answer_given_by_the_teachers; extern const char *Txt_TST_Answer_given_by_the_teachers;
struct Tst_Question Question; struct Tst_Question Question;
@ -3362,7 +3380,7 @@ void Tst_WriteAnswersEdit (long QstCod)
double FloatNum[2]; double FloatNum[2];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get answers *****/ /***** Get answers *****/
Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false);
@ -3375,7 +3393,7 @@ void Tst_WriteAnswersEdit (long QstCod)
*/ */
/***** Write answers *****/ /***** Write answers *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_CheckIfNumberOfAnswersIsOne (&Answer); Tst_CheckIfNumberOfAnswersIsOne (&Answer);
@ -3506,13 +3524,14 @@ void Tst_WriteAnswersEdit (long QstCod)
/************** Write answers of a question when viewing a test **************/ /************** Write answers of a question when viewing a test **************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,bool Shuffle) static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,bool Shuffle)
{ {
/***** Write parameter with question code *****/ /***** Write parameter with question code *****/
Tst_WriteParamQstCod (NumQst,QstCod); Tst_WriteParamQstCod (NumQst,QstCod);
/***** Write answer depending on type *****/ /***** Write answer depending on type *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_WriteIntAnsViewTest (NumQst); Tst_WriteIntAnsViewTest (NumQst);
@ -3525,7 +3544,7 @@ static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,bool Shuff
break; break;
case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE:
Tst_WriteChoiceAnsViewTest (NumQst,QstCod,Shuffle); Tst_WriteChoiceAnsViewTest (NumQst,QstCod,AnswerType,Shuffle);
break; break;
case Tst_ANS_TEXT: case Tst_ANS_TEXT:
Tst_WriteTextAnsViewTest (NumQst); Tst_WriteTextAnsViewTest (NumQst);
@ -3541,6 +3560,7 @@ static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod,bool Shuff
static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat,
unsigned NumQst,long QstCod, unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,
unsigned Visibility, unsigned Visibility,
double *ScoreThisQst,bool *AnswerIsNotBlank) double *ScoreThisQst,bool *AnswerIsNotBlank)
{ {
@ -3549,7 +3569,7 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat,
struct Tst_Answer Answer; struct Tst_Answer Answer;
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get answer of a question from database *****/ /***** Get answer of a question from database *****/
Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false);
@ -3562,7 +3582,7 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat,
*/ */
/***** Write answer depending on type *****/ /***** Write answer depending on type *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_WriteIntAnsAssessTest (UsrDat,NumQst,&Answer,mysql_res, Tst_WriteIntAnsAssessTest (UsrDat,NumQst,&Answer,mysql_res,
@ -3581,7 +3601,7 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat,
break; break;
case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE:
Tst_WriteChoiceAnsAssessTest (UsrDat,NumQst,&Answer,mysql_res, Tst_WriteChoiceAnsAssessTest (UsrDat,NumQst,AnswerType,&Answer,mysql_res,
Visibility, Visibility,
ScoreThisQst,AnswerIsNotBlank); ScoreThisQst,AnswerIsNotBlank);
break; break;
@ -3755,7 +3775,9 @@ static void Tst_WriteTFAnsAssessTest (struct UsrData *UsrDat,
/******** Write single or multiple choice answer when viewing a test *********/ /******** Write single or multiple choice answer when viewing a test *********/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle) static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,
Tst_AnswerType_t AnswerType,
bool Shuffle)
{ {
unsigned NumOpt; unsigned NumOpt;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
@ -3768,7 +3790,7 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle
char StrAns[32]; char StrAns[32];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get answers of a question from database *****/ /***** Get answers of a question from database *****/
Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle);
@ -3830,14 +3852,14 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle
snprintf (StrAns,sizeof (StrAns), snprintf (StrAns,sizeof (StrAns),
"Ans%06u", "Ans%06u",
NumQst); NumQst);
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE) if (AnswerType == Tst_ANS_UNIQUE_CHOICE)
HTM_INPUT_RADIO (StrAns,false, HTM_INPUT_RADIO (StrAns,false,
"id=\"Ans%06u_%u\" value=\"%u\"" "id=\"Ans%06u_%u\" value=\"%u\""
" onclick=\"selectUnselectRadio(this,this.form.Ans%06u,%u);\"", " onclick=\"selectUnselectRadio(this,this.form.Ans%06u,%u);\"",
NumQst,NumOpt, NumQst,NumOpt,
Index, Index,
NumQst,Answer.NumOptions); NumQst,Answer.NumOptions);
else // Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE else // AnswerType == Tst_ANS_MULTIPLE_CHOICE
HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE, HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"Ans%06u_%u\" value=\"%u\"", "id=\"Ans%06u_%u\" value=\"%u\"",
NumQst,NumOpt, NumQst,NumOpt,
@ -3879,6 +3901,7 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod,bool Shuffle
static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
unsigned NumQst, unsigned NumQst,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
MYSQL_RES *mysql_res, MYSQL_RES *mysql_res,
unsigned Visibility, unsigned Visibility,
@ -3907,7 +3930,7 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat,
Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr); Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr);
/***** Compute the total score of this question *****/ /***** Compute the total score of this question *****/
Tst_ComputeScoreQst (Answer, Tst_ComputeScoreQst (AnswerType,Answer,
Indexes,AnswersUsr,ScoreThisQst,AnswerIsNotBlank); Indexes,AnswersUsr,ScoreThisQst,AnswerIsNotBlank);
/***** Begin table *****/ /***** Begin table *****/
@ -4158,7 +4181,8 @@ void Tst_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ON
/********************* Compute the score of this question ********************/ /********************* Compute the score of this question ********************/
/*****************************************************************************/ /*****************************************************************************/
void Tst_ComputeScoreQst (const struct Tst_Answer *Answer, void Tst_ComputeScoreQst (Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], // Indexes of all answers of this question
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION], bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION],
double *ScoreThisQst,bool *AnswerIsNotBlank) double *ScoreThisQst,bool *AnswerIsNotBlank)
@ -4192,7 +4216,7 @@ void Tst_ComputeScoreQst (const struct Tst_Answer *Answer,
if (*AnswerIsNotBlank) if (*AnswerIsNotBlank)
{ {
/* Compute the score */ /* Compute the score */
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE) if (AnswerType == Tst_ANS_UNIQUE_CHOICE)
{ {
if (NumOptTotInQst >= 2) // It should be 2 options at least if (NumOptTotInQst >= 2) // It should be 2 options at least
*ScoreThisQst = (double) NumAnsGood - *ScoreThisQst = (double) NumAnsGood -
@ -4200,7 +4224,7 @@ void Tst_ComputeScoreQst (const struct Tst_Answer *Answer,
else // 0 or 1 options (impossible) else // 0 or 1 options (impossible)
*ScoreThisQst = (double) NumAnsGood; *ScoreThisQst = (double) NumAnsGood;
} }
else // Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE else // AnswerType == Tst_ANS_MULTIPLE_CHOICE
{ {
if (NumOptCorrInQst) // There are correct options in the question if (NumOptCorrInQst) // There are correct options in the question
{ {
@ -4231,6 +4255,7 @@ void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod,
unsigned NumCols,const char *Class,bool ShowResult) unsigned NumCols,const char *Class,bool ShowResult)
{ {
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
unsigned NumOpt; unsigned NumOpt;
bool RowIsOpen = false; bool RowIsOpen = false;
@ -4241,7 +4266,7 @@ void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get number of users who have answered this question from database *****/ /***** Get number of users who have answered this question from database *****/
NumRespondersQst = Mch_GetNumUsrsWhoAnsweredQst (MchCod,QstInd); NumRespondersQst = Mch_GetNumUsrsWhoAnsweredQst (MchCod,QstInd);
@ -5161,21 +5186,22 @@ void Tst_ShowFormEditOneQst (void)
{ {
long QstCod; long QstCod;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
char Stem[Cns_MAX_BYTES_TEXT + 1]; char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get question data *****/ /***** Get question data *****/
QstCod = Tst_GetQstCod (); QstCod = Tst_GetQstCod ();
Stem[0] = Feedback[0] = '\0'; Stem[0] = Feedback[0] = '\0';
if (QstCod > 0) // If question already exists in the database if (QstCod > 0) // If question already exists in the database
Tst_GetQstDataFromDB (QstCod,&Question,&Answer,Stem,Feedback); Tst_GetQstDataFromDB (QstCod,&Question,&AnswerType,&Answer,Stem,Feedback);
/***** Put form to edit question *****/ /***** Put form to edit question *****/
Tst_PutFormEditOneQst (QstCod,&Question,&Answer,Stem,Feedback); Tst_PutFormEditOneQst (QstCod,&Question,AnswerType,&Answer,Stem,Feedback);
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question,&Answer); Tst_QstDestructor (&Question,&Answer);
@ -5192,6 +5218,7 @@ void Tst_ShowFormEditOneQst (void)
static void Tst_PutFormEditOneQst (long QstCod, static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer, const struct Tst_Answer *Answer,
char Stem[Cns_MAX_BYTES_TEXT + 1], char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]) char Feedback[Cns_MAX_BYTES_TEXT + 1])
@ -5388,7 +5415,8 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_INPUT_RADIO ("AnswerType",false, HTM_INPUT_RADIO ("AnswerType",false,
"value=\"%u\"%s onclick=\"enableDisableAns(this.form);\"", "value=\"%u\"%s onclick=\"enableDisableAns(this.form);\"",
(unsigned) AnsType, (unsigned) AnsType,
AnsType == Gbl.Test.AnswerType ? " checked=\"checked\"" : ""); AnsType == AnswerType ? " checked=\"checked\"" :
"");
HTM_TxtF ("%s ",Txt_TST_STR_ANSWER_TYPES[AnsType]); HTM_TxtF ("%s ",Txt_TST_STR_ANSWER_TYPES[AnsType]);
HTM_LABEL_End (); HTM_LABEL_End ();
HTM_BR (); HTM_BR ();
@ -5413,8 +5441,8 @@ static void Tst_PutFormEditOneQst (long QstCod,
Answer->Integer); Answer->Integer);
HTM_INPUT_TEXT ("AnsInt",Cns_MAX_DECIMAL_DIGITS_LONG,StrInteger,false, HTM_INPUT_TEXT ("AnsInt",Cns_MAX_DECIMAL_DIGITS_LONG,StrInteger,false,
"size=\"11\" required=\"required\"%s", "size=\"11\" required=\"required\"%s",
Gbl.Test.AnswerType == Tst_ANS_INT ? "" : AnswerType == Tst_ANS_INT ? "" :
" disabled=\"disabled\""); " disabled=\"disabled\"");
HTM_LABEL_End (); HTM_LABEL_End ();
HTM_TD_End (); HTM_TD_End ();
@ -5425,9 +5453,9 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_TD_Empty (1); HTM_TD_Empty (1);
HTM_TD_Begin ("class=\"LT\""); HTM_TD_Begin ("class=\"LT\"");
Tst_PutFloatInputField (Txt_Real_number_between_A_and_B_1,"AnsFloatMin", Tst_PutFloatInputField (Txt_Real_number_between_A_and_B_1,"AnsFloatMin",
Answer->FloatingPoint[0]); Answer->FloatingPoint[0],AnswerType);
Tst_PutFloatInputField (Txt_Real_number_between_A_and_B_2,"AnsFloatMax", Tst_PutFloatInputField (Txt_Real_number_between_A_and_B_2,"AnsFloatMax",
Answer->FloatingPoint[1]); Answer->FloatingPoint[1],AnswerType);
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -5435,8 +5463,8 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
HTM_TD_Empty (1); HTM_TD_Empty (1);
HTM_TD_Begin ("class=\"LT\""); HTM_TD_Begin ("class=\"LT\"");
Tst_PutTFInputField (Answer,Txt_TF_QST[0],'T'); Tst_PutTFInputField (AnswerType,Answer,Txt_TF_QST[0],'T');
Tst_PutTFInputField (Answer,Txt_TF_QST[1],'F'); Tst_PutTFInputField (AnswerType,Answer,Txt_TF_QST[1],'F');
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -5451,9 +5479,9 @@ static void Tst_PutFormEditOneQst (long QstCod,
"value=\"Y\"%s%s", "value=\"Y\"%s%s",
Question->Shuffle ? " checked=\"checked\"" : Question->Shuffle ? " checked=\"checked\"" :
"", "",
Gbl.Test.AnswerType != Tst_ANS_UNIQUE_CHOICE && AnswerType != Tst_ANS_UNIQUE_CHOICE &&
Gbl.Test.AnswerType != Tst_ANS_MULTIPLE_CHOICE ? " disabled=\"disabled\"" : AnswerType != Tst_ANS_MULTIPLE_CHOICE ? " disabled=\"disabled\"" :
""); "");
HTM_Txt (Txt_Shuffle); HTM_Txt (Txt_Shuffle);
HTM_LABEL_End (); HTM_LABEL_End ();
HTM_TD_End (); HTM_TD_End ();
@ -5466,9 +5494,9 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_TD_Begin ("class=\"LT\""); HTM_TD_Begin ("class=\"LT\"");
HTM_TABLE_BeginPadding (2); // Table with choice answers HTM_TABLE_BeginPadding (2); // Table with choice answers
OptionsDisabled = Gbl.Test.AnswerType != Tst_ANS_UNIQUE_CHOICE && OptionsDisabled = AnswerType != Tst_ANS_UNIQUE_CHOICE &&
Gbl.Test.AnswerType != Tst_ANS_MULTIPLE_CHOICE && AnswerType != Tst_ANS_MULTIPLE_CHOICE &&
Gbl.Test.AnswerType != Tst_ANS_TEXT; AnswerType != Tst_ANS_TEXT;
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++) NumOpt++)
@ -5493,16 +5521,19 @@ static void Tst_PutFormEditOneQst (long QstCod,
"value=\"%u\"%s%s%s onclick=\"enableDisableAns(this.form);\"", "value=\"%u\"%s%s%s onclick=\"enableDisableAns(this.form);\"",
NumOpt, NumOpt,
Answer->Options[NumOpt].Correct ? " checked=\"checked\"" : "", Answer->Options[NumOpt].Correct ? " checked=\"checked\"" : "",
NumOpt < 2 ? " required=\"required\"" : "", // First or second options required NumOpt < 2 ? " required=\"required\"" : // First or second options required
Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE ? "" : " disabled=\"disabled\""); "",
AnswerType == Tst_ANS_UNIQUE_CHOICE ? "" :
" disabled=\"disabled\"");
/* Checkbox for multiple choice answers */ /* Checkbox for multiple choice answers */
HTM_INPUT_CHECKBOX ("AnsMulti",HTM_DONT_SUBMIT_ON_CHANGE, HTM_INPUT_CHECKBOX ("AnsMulti",HTM_DONT_SUBMIT_ON_CHANGE,
"value=\"%u\"%s%s", "value=\"%u\"%s%s",
NumOpt, NumOpt,
Answer->Options[NumOpt].Correct ? " checked=\"checked\"" : "", Answer->Options[NumOpt].Correct ? " checked=\"checked\"" :
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE ? "" : "",
" disabled=\"disabled\""); AnswerType == Tst_ANS_MULTIPLE_CHOICE ? "" :
" disabled=\"disabled\"");
HTM_TD_End (); HTM_TD_End ();
@ -5603,7 +5634,7 @@ static void Tst_PutFormEditOneQst (long QstCod,
/*****************************************************************************/ /*****************************************************************************/
static void Tst_PutFloatInputField (const char *Label,const char *Field, static void Tst_PutFloatInputField (const char *Label,const char *Field,
double Value) double Value,Tst_AnswerType_t AnswerType)
{ {
extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *The_ClassFormInBox[The_NUM_THEMES];
char StrDouble[32]; char StrDouble[32];
@ -5615,8 +5646,8 @@ static void Tst_PutFloatInputField (const char *Label,const char *Field,
Value); Value);
HTM_INPUT_TEXT (Field,Tst_MAX_BYTES_FLOAT_ANSWER,StrDouble,false, HTM_INPUT_TEXT (Field,Tst_MAX_BYTES_FLOAT_ANSWER,StrDouble,false,
"size=\"11\" required=\"required\"%s", "size=\"11\" required=\"required\"%s",
Gbl.Test.AnswerType == Tst_ANS_FLOAT ? "" : AnswerType == Tst_ANS_FLOAT ? "" :
" disabled=\"disabled\""); " disabled=\"disabled\"");
HTM_LABEL_End (); HTM_LABEL_End ();
} }
@ -5624,7 +5655,8 @@ static void Tst_PutFloatInputField (const char *Label,const char *Field,
/*********************** Put input field for T/F answer **********************/ /*********************** Put input field for T/F answer **********************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_PutTFInputField (const struct Tst_Answer *Answer, static void Tst_PutTFInputField (Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer,
const char *Label,char Value) const char *Label,char Value)
{ {
extern const char *The_ClassFormInBox[The_NUM_THEMES]; extern const char *The_ClassFormInBox[The_NUM_THEMES];
@ -5635,8 +5667,8 @@ static void Tst_PutTFInputField (const struct Tst_Answer *Answer,
Value, Value,
Answer->TF == Value ? " checked=\"checked\"" : Answer->TF == Value ? " checked=\"checked\"" :
"", "",
Gbl.Test.AnswerType == Tst_ANS_TRUE_FALSE ? "" : AnswerType == Tst_ANS_TRUE_FALSE ? "" :
" disabled=\"disabled\""); " disabled=\"disabled\"");
HTM_Txt (Label); HTM_Txt (Label);
HTM_LABEL_End (); HTM_LABEL_End ();
} }
@ -5646,6 +5678,7 @@ static void Tst_PutTFInputField (const struct Tst_Answer *Answer,
/*****************************************************************************/ /*****************************************************************************/
void Tst_QstConstructor (struct Tst_Question *Question, void Tst_QstConstructor (struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer) struct Tst_Answer *Answer)
{ {
unsigned NumOpt; unsigned NumOpt;
@ -5656,7 +5689,7 @@ void Tst_QstConstructor (struct Tst_Question *Question,
Question->Feedback.Length = 0; Question->Feedback.Length = 0;
Question->Shuffle = false; Question->Shuffle = false;
Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE; *AnswerType = Tst_ANS_UNIQUE_CHOICE;
Answer->NumOptions = 0; Answer->NumOptions = 0;
Answer->TF = ' '; Answer->TF = ' ';
@ -5791,6 +5824,7 @@ static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question,
static void Tst_GetQstDataFromDB (long QstCod, static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question, struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
char Stem[Cns_MAX_BYTES_TEXT + 1], char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]) char Feedback[Cns_MAX_BYTES_TEXT + 1])
@ -5815,7 +5849,7 @@ static void Tst_GetQstDataFromDB (long QstCod,
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get the type of answer */ /* Get the type of answer */
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); *AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]);
/* Get shuffle (row[1]) */ /* Get shuffle (row[1]) */
Question->Shuffle = (row[1][0] == 'Y'); Question->Shuffle = (row[1][0] == 'Y');
@ -5866,7 +5900,7 @@ static void Tst_GetQstDataFromDB (long QstCod,
NumOpt++) NumOpt++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
switch (Gbl.Test.AnswerType) switch (*AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
if (Answer->NumOptions != 1) if (Answer->NumOptions != 1)
@ -6022,25 +6056,26 @@ void Tst_ReceiveQst (void)
{ {
long QstCod; long QstCod;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
char Stem[Cns_MAX_BYTES_TEXT + 1]; char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/***** Get parameters of the question from form *****/ /***** Get parameters of the question from form *****/
Stem[0] = Feedback[0] = '\0'; Stem[0] = Feedback[0] = '\0';
QstCod = Tst_GetQstFromForm (&Question,&Answer,Stem,Feedback); QstCod = Tst_GetQstFromForm (&Question,&AnswerType,&Answer,Stem,Feedback);
/***** Make sure that tags, text and answer are not empty *****/ /***** Make sure that tags, text and answer are not empty *****/
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Answer)) if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,AnswerType,&Answer))
{ {
/***** Move images to definitive directories *****/ /***** Move images to definitive directories *****/
Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question,&Answer); Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question,AnswerType,&Answer);
/***** Insert or update question, tags and answer in the database *****/ /***** Insert or update question, tags and answer in the database *****/
QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question,&Answer); QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question,AnswerType,&Answer);
/***** Show the question just inserted in the database *****/ /***** Show the question just inserted in the database *****/
Tst_ListOneQstToEdit (QstCod); Tst_ListOneQstToEdit (QstCod);
@ -6051,7 +6086,7 @@ void Tst_ReceiveQst (void)
Tst_ResetMediaOfQuestion (&Question,&Answer); Tst_ResetMediaOfQuestion (&Question,&Answer);
/***** Put form to edit question again *****/ /***** Put form to edit question again *****/
Tst_PutFormEditOneQst (QstCod,&Question,&Answer,Stem,Feedback); Tst_PutFormEditOneQst (QstCod,&Question,AnswerType,&Answer,Stem,Feedback);
} }
/***** Destroy test question *****/ /***** Destroy test question *****/
@ -6063,6 +6098,7 @@ void Tst_ReceiveQst (void)
/*****************************************************************************/ /*****************************************************************************/
static long Tst_GetQstFromForm (struct Tst_Question *Question, static long Tst_GetQstFromForm (struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer, struct Tst_Answer *Answer,
char *Stem,char *Feedback) char *Stem,char *Feedback)
{ {
@ -6083,12 +6119,12 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
QstCod = Tst_GetQstCod (); QstCod = Tst_GetQstCod ();
/***** Get answer type *****/ /***** Get answer type *****/
Gbl.Test.AnswerType = (Tst_AnswerType_t) *AnswerType = (Tst_AnswerType_t)
Par_GetParToUnsignedLong ("AnswerType", Par_GetParToUnsignedLong ("AnswerType",
0, 0,
Tst_NUM_ANS_TYPES - 1, Tst_NUM_ANS_TYPES - 1,
(unsigned long) Tst_ANS_ALL); (unsigned long) Tst_ANS_ALL);
if (Gbl.Test.AnswerType == Tst_ANS_ALL) if (*AnswerType == Tst_ANS_ALL)
Lay_ShowErrorAndExit ("Wrong type of answer. 4"); Lay_ShowErrorAndExit ("Wrong type of answer. 4");
/***** Get question tags *****/ /***** Get question tags *****/
@ -6136,7 +6172,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
/***** Get answers *****/ /***** Get answers *****/
Question->Shuffle = false; Question->Shuffle = false;
switch (Gbl.Test.AnswerType) switch (*AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
if (!Tst_AllocateTextChoiceAnswer (Answer,0)) if (!Tst_AllocateTextChoiceAnswer (Answer,0))
@ -6187,7 +6223,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
NumOpt); NumOpt);
Par_GetParToHTML (AnsStr,Answer->Options[NumOpt].Text, Par_GetParToHTML (AnsStr,Answer->Options[NumOpt].Text,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
if (Gbl.Test.AnswerType == Tst_ANS_TEXT) if (*AnswerType == Tst_ANS_TEXT)
/* In order to compare student answer to stored answer, /* In order to compare student answer to stored answer,
the text answers are stored avoiding two or more consecurive spaces */ the text answers are stored avoiding two or more consecurive spaces */
Str_ReplaceSeveralSpacesForOne (Answer->Options[NumOpt].Text); Str_ReplaceSeveralSpacesForOne (Answer->Options[NumOpt].Text);
@ -6200,8 +6236,8 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
/* Get media associated to the answer (action, file and title) */ /* Get media associated to the answer (action, file and title) */
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || if (*AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) *AnswerType == Tst_ANS_MULTIPLE_CHOICE)
{ {
Answer->Options[NumOpt].Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; Answer->Options[NumOpt].Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH;
Answer->Options[NumOpt].Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; Answer->Options[NumOpt].Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT;
@ -6216,7 +6252,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
} }
/* Get the numbers of correct answers */ /* Get the numbers of correct answers */
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE) if (*AnswerType == Tst_ANS_UNIQUE_CHOICE)
{ {
NumCorrectAns = (unsigned) Par_GetParToUnsignedLong ("AnsUni", NumCorrectAns = (unsigned) Par_GetParToUnsignedLong ("AnsUni",
0, 0,
@ -6224,7 +6260,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
0); 0);
Answer->Options[NumCorrectAns].Correct = true; Answer->Options[NumCorrectAns].Correct = true;
} }
else if (Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) else if (*AnswerType == Tst_ANS_MULTIPLE_CHOICE)
{ {
Par_GetParMultiToText ("AnsMulti",StrMultiAns,Tst_MAX_BYTES_ANSWERS_ONE_QST); Par_GetParMultiToText ("AnsMulti",StrMultiAns,Tst_MAX_BYTES_ANSWERS_ONE_QST);
Ptr = StrMultiAns; Ptr = StrMultiAns;
@ -6271,6 +6307,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
// Computes Answer->Integer and Answer->FloatingPoint[0..1] // Computes Answer->Integer and Answer->FloatingPoint[0..1]
bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question, bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer) struct Tst_Answer *Answer)
{ {
extern const char *Txt_You_must_type_at_least_one_tag_for_the_question; extern const char *Txt_You_must_type_at_least_one_tag_for_the_question;
@ -6306,7 +6343,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question
} }
/***** Check answer *****/ /***** Check answer *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
/* First option should be filled */ /* First option should be filled */
@ -6454,6 +6491,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question
/*****************************************************************************/ /*****************************************************************************/
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question, bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer) const struct Tst_Answer *Answer)
{ {
extern const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES]; extern const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES];
@ -6476,7 +6514,7 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
"SELECT QstCod FROM tst_questions" "SELECT QstCod FROM tst_questions"
" WHERE CrsCod=%ld AND AnsType='%s' AND Stem='%s'", " WHERE CrsCod=%ld AND AnsType='%s' AND Stem='%s'",
Gbl.Hierarchy.Crs.CrsCod, Gbl.Hierarchy.Crs.CrsCod,
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], Tst_StrAnswerTypesDB[AnswerType],
Question->Stem.Text); Question->Stem.Text);
if (NumQstsWithThisStem) // There are questions in database with the same stem that the one of this question if (NumQstsWithThisStem) // There are questions in database with the same stem that the one of this question
@ -6500,7 +6538,7 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
" WHERE QstCod=%ld ORDER BY AnsInd", " WHERE QstCod=%ld ORDER BY AnsInd",
QstCod); QstCod);
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
row = mysql_fetch_row (mysql_res_ans); row = mysql_fetch_row (mysql_res_ans);
@ -6562,6 +6600,7 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, static void Tst_MoveMediaToDefinitiveDirectories (long QstCod,
struct Tst_Question *Question, struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer) struct Tst_Answer *Answer)
{ {
unsigned NumOpt; unsigned NumOpt;
@ -6573,16 +6612,22 @@ static void Tst_MoveMediaToDefinitiveDirectories (long QstCod,
Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Question->Media); Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Question->Media);
/****** Move media associated to answers *****/ /****** Move media associated to answers *****/
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || switch (AnswerType)
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) {
for (NumOpt = 0; case Tst_ANS_UNIQUE_CHOICE:
NumOpt < Answer->NumOptions; case Tst_ANS_MULTIPLE_CHOICE:
NumOpt++) for (NumOpt = 0;
{ NumOpt < Answer->NumOptions;
CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod, NumOpt++)
NumOpt); // Get current media code associated to this option {
Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Answer->Options[NumOpt].Media); CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod,
} NumOpt); // Get current media code associated to this option
Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Answer->Options[NumOpt].Media);
}
break;
default:
break;
}
} }
/*****************************************************************************/ /*****************************************************************************/
@ -6974,10 +7019,11 @@ void Tst_PutParamQstCod (long QstCod)
long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer) struct Tst_Answer *Answer)
{ {
/***** Insert or update question in the table of questions *****/ /***** Insert or update question in the table of questions *****/
QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question); QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question,AnswerType);
if (QstCod > 0) if (QstCod > 0)
{ {
/***** Insert tags in the tags table *****/ /***** Insert tags in the tags table *****/
@ -6987,7 +7033,7 @@ long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
Tst_RemoveUnusedTagsFromCrs (Gbl.Hierarchy.Crs.CrsCod); Tst_RemoveUnusedTagsFromCrs (Gbl.Hierarchy.Crs.CrsCod);
/***** Insert answers in the answers table *****/ /***** Insert answers in the answers table *****/
Tst_InsertAnswersIntoDB (QstCod,Answer); Tst_InsertAnswersIntoDB (QstCod,AnswerType,Answer);
} }
return QstCod; return QstCod;
@ -6998,7 +7044,8 @@ long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
/*****************************************************************************/ /*****************************************************************************/
static long Tst_InsertOrUpdateQstIntoDB (long QstCod, static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
const struct Tst_Question *Question) const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType)
{ {
if (QstCod < 0) // It's a new question if (QstCod < 0) // It's a new question
{ {
@ -7026,7 +7073,7 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
"0," // NumHits "0," // NumHits
"0)", // Score "0)", // Score
Gbl.Hierarchy.Crs.CrsCod, Gbl.Hierarchy.Crs.CrsCod,
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], Tst_StrAnswerTypesDB[AnswerType],
Question->Shuffle ? 'Y' : Question->Shuffle ? 'Y' :
'N', 'N',
Question->Stem.Text, Question->Stem.Text,
@ -7047,7 +7094,7 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
"Feedback='%s'," "Feedback='%s',"
"MedCod=%ld" "MedCod=%ld"
" WHERE QstCod=%ld AND CrsCod=%ld", " WHERE QstCod=%ld AND CrsCod=%ld",
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], Tst_StrAnswerTypesDB[AnswerType],
Question->Shuffle ? 'Y' : Question->Shuffle ? 'Y' :
'N', 'N',
Question->Stem.Text, Question->Stem.Text,
@ -7101,13 +7148,15 @@ static void Tst_InsertTagsIntoDB (long QstCod)
/******************* Insert answers in the answers table *********************/ /******************* Insert answers in the answers table *********************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Answer *Answer) static void Tst_InsertAnswersIntoDB (long QstCod,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer)
{ {
unsigned NumOpt; unsigned NumOpt;
unsigned i; unsigned i;
/***** Insert answers in the answers table *****/ /***** Insert answers in the answers table *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
DB_QueryINSERT ("can not create answer", DB_QueryINSERT ("can not create answer",

View File

@ -179,7 +179,7 @@ void Tst_WriteParamEditQst (void);
unsigned Tst_GetNumAnswersQst (long QstCod); unsigned Tst_GetNumAnswersQst (long QstCod);
unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle); unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle);
void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Answer *Answer); void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Answer *Answer);
void Tst_WriteAnswersEdit (long QstCod); void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType);
bool Tst_CheckIfQuestionIsValidForGame (long QstCod); bool Tst_CheckIfQuestionIsValidForGame (long QstCod);
void Tst_WriteAnsTF (char AnsTF); void Tst_WriteAnsTF (char AnsTF);
void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Answer *Answer); void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Answer *Answer);
@ -187,7 +187,8 @@ void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ON
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]); unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void Tst_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1], void Tst_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1],
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]); bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]);
void Tst_ComputeScoreQst (const struct Tst_Answer *Answer, void Tst_ComputeScoreQst (Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION], unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION],
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION], bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION],
double *ScoreThisQst,bool *AnswerIsNotBlank); double *ScoreThisQst,bool *AnswerIsNotBlank);
@ -212,6 +213,7 @@ void Tst_ReceiveConfigTst (void);
void Tst_ShowFormEditOneQst (void); void Tst_ShowFormEditOneQst (void);
void Tst_QstConstructor (struct Tst_Question *Question, void Tst_QstConstructor (struct Tst_Question *Question,
Tst_AnswerType_t *AnswerType,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
void Tst_QstDestructor (struct Tst_Question *Question, void Tst_QstDestructor (struct Tst_Question *Question,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
@ -221,9 +223,11 @@ int Tst_AllocateTextChoiceAnswer (struct Tst_Answer *Answer,unsigned NumOpt);
Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD);
void Tst_ReceiveQst (void); void Tst_ReceiveQst (void);
bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question, bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question, bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer); const struct Tst_Answer *Answer);
long Tst_GetIntAnsFromStr (char *Str); long Tst_GetIntAnsFromStr (char *Str);
@ -242,6 +246,7 @@ void Tst_PutParamQstCod (long QstCod);
long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
void Tst_RemoveCrsTests (long CrsCod); void Tst_RemoveCrsTests (long CrsCod);

View File

@ -71,16 +71,19 @@ static void TsI_PutCreateXMLParam (void);
static void TsI_ExportQuestion (long QstCod,FILE *FileXML); static void TsI_ExportQuestion (long QstCod,FILE *FileXML);
static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML); static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML);
static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML); static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
FILE *FileXML);
static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML); static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML);
static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer); static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer);
static Tst_AnswerType_t TsI_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrAnsTypeXML); static Tst_AnswerType_t TsI_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrAnsTypeXML);
static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem, static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer); struct Tst_Answer *Answer);
static void TsI_WriteHeadingListImportedQst (void); static void TsI_WriteHeadingListImportedQst (void);
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem, struct XMLElement *FeedbackElem,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer, const struct Tst_Answer *Answer,
bool QuestionExists); bool QuestionExists);
@ -245,6 +248,7 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
extern const char *Txt_NEW_LINE; extern const char *Txt_NEW_LINE;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
Tst_AnswerType_t AnswerType;
if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) if (Tst_GetOneQuestionByCod (QstCod,&mysql_res))
{ {
@ -263,9 +267,9 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
*/ */
/***** Write the answer type (row[1]) *****/ /***** Write the answer type (row[1]) *****/
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
fprintf (FileXML,"<question type=\"%s\">%s", fprintf (FileXML,"<question type=\"%s\">%s",
Tst_StrAnswerTypesXML[Gbl.Test.AnswerType],Txt_NEW_LINE); Tst_StrAnswerTypesXML[AnswerType],Txt_NEW_LINE);
/***** Write the question tags *****/ /***** Write the question tags *****/
fprintf (FileXML,"<tags>%s",Txt_NEW_LINE); fprintf (FileXML,"<tags>%s",Txt_NEW_LINE);
@ -285,13 +289,13 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
/***** Write the answers of this question. /***** Write the answers of this question.
Shuffle can be enabled or disabled (row[2]) *****/ Shuffle can be enabled or disabled (row[2]) *****/
fprintf (FileXML,"<answer"); fprintf (FileXML,"<answer");
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || if (AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) AnswerType == Tst_ANS_MULTIPLE_CHOICE)
fprintf (FileXML," shuffle=\"%s\"", fprintf (FileXML," shuffle=\"%s\"",
(row[2][0] == 'Y') ? "yes" : (row[2][0] == 'Y') ? "yes" :
"no"); "no");
fprintf (FileXML,">"); fprintf (FileXML,">");
TsI_WriteAnswersOfAQstXML (QstCod,FileXML); TsI_WriteAnswersOfAQstXML (QstCod,AnswerType,FileXML);
fprintf (FileXML,"</answer>%s",Txt_NEW_LINE); fprintf (FileXML,"</answer>%s",Txt_NEW_LINE);
/***** End question *****/ /***** End question *****/
@ -331,7 +335,8 @@ static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML)
/**************** Get and write the answers of a test question ***************/ /**************** Get and write the answers of a test question ***************/
/*****************************************************************************/ /*****************************************************************************/
static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML) static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
FILE *FileXML)
{ {
extern const char *Txt_NEW_LINE; extern const char *Txt_NEW_LINE;
struct Tst_Answer Answer; struct Tst_Answer Answer;
@ -352,7 +357,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
*/ */
/***** Write answers *****/ /***** Write answers *****/
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_CheckIfNumberOfAnswersIsOne (&Answer); Tst_CheckIfNumberOfAnswersIsOne (&Answer);
@ -399,7 +404,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
fprintf (FileXML,"<option"); fprintf (FileXML,"<option");
/* Write whether the answer is correct or not (row[4]) */ /* Write whether the answer is correct or not (row[4]) */
if (Gbl.Test.AnswerType != Tst_ANS_TEXT) if (AnswerType != Tst_ANS_TEXT)
fprintf (FileXML," correct=\"%s\"", fprintf (FileXML," correct=\"%s\"",
(row[4][0] == 'Y') ? "yes" : (row[4][0] == 'Y') ? "yes" :
"no"); "no");
@ -535,6 +540,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
bool AnswerTypeFound; bool AnswerTypeFound;
bool QuestionExists; bool QuestionExists;
struct Tst_Question Question; struct Tst_Question Question;
Tst_AnswerType_t AnswerType;
struct Tst_Answer Answer; struct Tst_Answer Answer;
char Stem[Cns_MAX_BYTES_TEXT + 1]; char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1];
@ -579,124 +585,127 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
if (!strcmp (QuestionElem->TagName,"question")) if (!strcmp (QuestionElem->TagName,"question"))
{ {
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question,&Answer); Tst_QstConstructor (&Question,&AnswerType,&Answer);
/* Get type of questions (in mandatory attribute "type") */ /* Get answer type (in mandatory attribute "type") */
AnswerTypeFound = false; AnswerTypeFound = false;
for (Attribute = QuestionElem->FirstAttribute; for (Attribute = QuestionElem->FirstAttribute;
Attribute != NULL; Attribute != NULL;
Attribute = Attribute->Next) Attribute = Attribute->Next)
if (!strcmp (Attribute->AttributeName,"type")) if (!strcmp (Attribute->AttributeName,"type"))
{ {
Gbl.Test.AnswerType = TsI_ConvertFromStrAnsTypXMLToAnsTyp (Attribute->Content); AnswerType = TsI_ConvertFromStrAnsTypXMLToAnsTyp (Attribute->Content);
AnswerTypeFound = true; AnswerTypeFound = true;
break; // Only first attribute "type" break; // Only first attribute "type"
} }
if (!AnswerTypeFound)
Lay_ShowErrorAndExit ("Wrong type of answer.");
/* Get tags */ if (AnswerTypeFound)
for (TagsElem = QuestionElem->FirstChild, Gbl.Test.Tags.Num = 0;
TagsElem != NULL;
TagsElem = TagsElem->NextBrother)
if (!strcmp (TagsElem->TagName,"tags"))
{
for (TagElem = TagsElem->FirstChild;
TagElem != NULL && Gbl.Test.Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
TagElem = TagElem->NextBrother)
if (!strcmp (TagElem->TagName,"tag"))
{
if (TagElem->Content)
{
Str_Copy (Gbl.Test.Tags.Txt[Gbl.Test.Tags.Num],
TagElem->Content,
Tst_MAX_BYTES_TAG);
Gbl.Test.Tags.Num++;
}
}
break; // Only first element "tags"
}
/* Get stem (mandatory) */
for (StemElem = QuestionElem->FirstChild;
StemElem != NULL;
StemElem = StemElem->NextBrother)
if (!strcmp (StemElem->TagName,"stem"))
{
if (StemElem->Content)
{
/* Convert stem from text to HTML (in database stem is stored in HTML) */
Str_Copy (Stem,StemElem->Content,
Cns_MAX_BYTES_TEXT);
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Stem,Cns_MAX_BYTES_TEXT,true);
Question.Stem.Text = Stem;
Question.Stem.Length = strlen (Stem);
}
break; // Only first element "stem"
}
/* Get feedback (optional) */
for (FeedbackElem = QuestionElem->FirstChild;
FeedbackElem != NULL;
FeedbackElem = FeedbackElem->NextBrother)
if (!strcmp (FeedbackElem->TagName,"feedback"))
{
if (FeedbackElem->Content)
{
/* Convert feedback from text to HTML (in database feedback is stored in HTML) */
Str_Copy (Feedback,FeedbackElem->Content,
Cns_MAX_BYTES_TEXT);
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Feedback,Cns_MAX_BYTES_TEXT,true);
Question.Feedback.Text = Feedback;
Question.Feedback.Length = strlen (Feedback);
}
break; // Only first element "feedback"
}
/* Get shuffle. By default, shuffle is false. */
Question.Shuffle = false;
for (AnswerElem = QuestionElem->FirstChild;
AnswerElem != NULL;
AnswerElem = AnswerElem->NextBrother)
if (!strcmp (AnswerElem->TagName,"answer"))
{
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
/* Get whether shuffle answers (in attribute "shuffle") */
for (Attribute = AnswerElem->FirstAttribute;
Attribute != NULL;
Attribute = Attribute->Next)
if (!strcmp (Attribute->AttributeName,"shuffle"))
{
Question.Shuffle = XML_GetAttributteYesNoFromXMLTree (Attribute);
break; // Only first attribute "shuffle"
}
break; // Only first element "answer"
}
/* Get answer (mandatory) */
TsI_GetAnswerFromXML (AnswerElem,&Answer);
/* Make sure that tags, text and answer are not empty */
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Answer))
{ {
/* Check if question already exists in database */ /* Get tags */
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question,&Answer); for (TagsElem = QuestionElem->FirstChild, Gbl.Test.Tags.Num = 0;
TagsElem != NULL;
TagsElem = TagsElem->NextBrother)
if (!strcmp (TagsElem->TagName,"tags"))
{
for (TagElem = TagsElem->FirstChild;
TagElem != NULL && Gbl.Test.Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
TagElem = TagElem->NextBrother)
if (!strcmp (TagElem->TagName,"tag"))
{
if (TagElem->Content)
{
Str_Copy (Gbl.Test.Tags.Txt[Gbl.Test.Tags.Num],
TagElem->Content,
Tst_MAX_BYTES_TAG);
Gbl.Test.Tags.Num++;
}
}
break; // Only first element "tags"
}
/* Write row with this imported question */ /* Get stem (mandatory) */
TsI_WriteRowImportedQst (StemElem,FeedbackElem, for (StemElem = QuestionElem->FirstChild;
&Question,&Answer, StemElem != NULL;
QuestionExists); StemElem = StemElem->NextBrother)
if (!strcmp (StemElem->TagName,"stem"))
{
if (StemElem->Content)
{
/* Convert stem from text to HTML (in database stem is stored in HTML) */
Str_Copy (Stem,StemElem->Content,
Cns_MAX_BYTES_TEXT);
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Stem,Cns_MAX_BYTES_TEXT,true);
/***** If a new question ==> insert question, tags and answer in the database *****/ Question.Stem.Text = Stem;
if (!QuestionExists) Question.Stem.Length = strlen (Stem);
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,&Answer) <= 0) }
Lay_ShowErrorAndExit ("Can not create question."); break; // Only first element "stem"
}
/* Get feedback (optional) */
for (FeedbackElem = QuestionElem->FirstChild;
FeedbackElem != NULL;
FeedbackElem = FeedbackElem->NextBrother)
if (!strcmp (FeedbackElem->TagName,"feedback"))
{
if (FeedbackElem->Content)
{
/* Convert feedback from text to HTML (in database feedback is stored in HTML) */
Str_Copy (Feedback,FeedbackElem->Content,
Cns_MAX_BYTES_TEXT);
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Feedback,Cns_MAX_BYTES_TEXT,true);
Question.Feedback.Text = Feedback;
Question.Feedback.Length = strlen (Feedback);
}
break; // Only first element "feedback"
}
/* Get shuffle. By default, shuffle is false. */
Question.Shuffle = false;
for (AnswerElem = QuestionElem->FirstChild;
AnswerElem != NULL;
AnswerElem = AnswerElem->NextBrother)
if (!strcmp (AnswerElem->TagName,"answer"))
{
if (AnswerType == Tst_ANS_UNIQUE_CHOICE ||
AnswerType == Tst_ANS_MULTIPLE_CHOICE)
/* Get whether shuffle answers (in attribute "shuffle") */
for (Attribute = AnswerElem->FirstAttribute;
Attribute != NULL;
Attribute = Attribute->Next)
if (!strcmp (Attribute->AttributeName,"shuffle"))
{
Question.Shuffle = XML_GetAttributteYesNoFromXMLTree (Attribute);
break; // Only first attribute "shuffle"
}
break; // Only first element "answer"
}
/* Get answer (mandatory) */
TsI_GetAnswerFromXML (AnswerElem,AnswerType,&Answer);
/* Make sure that tags, text and answer are not empty */
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,AnswerType,&Answer))
{
/* Check if question already exists in database */
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question,AnswerType,&Answer);
/* Write row with this imported question */
TsI_WriteRowImportedQst (StemElem,FeedbackElem,
&Question,AnswerType,&Answer,
QuestionExists);
/***** If a new question ==> insert question, tags and answer in the database *****/
if (!QuestionExists)
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,AnswerType,&Answer) <= 0)
Lay_ShowErrorAndExit ("Can not create question.");
}
} }
else // Answer type not found
Lay_ShowErrorAndExit ("Wrong type of answer.");
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question,&Answer); Tst_QstDestructor (&Question,&Answer);
@ -742,6 +751,7 @@ static Tst_AnswerType_t TsI_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrAnsT
// Answer is mandatory // Answer is mandatory
static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem, static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
Tst_AnswerType_t AnswerType,
struct Tst_Answer *Answer) struct Tst_Answer *Answer)
{ {
struct XMLElement *OptionElem; struct XMLElement *OptionElem;
@ -751,7 +761,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
struct XMLAttribute *Attribute; struct XMLAttribute *Attribute;
unsigned NumOpt; unsigned NumOpt;
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
if (!Tst_AllocateTextChoiceAnswer (Answer,0)) if (!Tst_AllocateTextChoiceAnswer (Answer,0))
@ -859,7 +869,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
break; // Only first element "feedback" break; // Only first element "feedback"
} }
if (Gbl.Test.AnswerType == Tst_ANS_TEXT) if (AnswerType == Tst_ANS_TEXT)
Answer->Options[NumOpt].Correct = true; Answer->Options[NumOpt].Correct = true;
else else
/* Check if option is correct or wrong */ /* Check if option is correct or wrong */
@ -911,6 +921,7 @@ static void TsI_WriteHeadingListImportedQst (void)
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem, struct XMLElement *FeedbackElem,
const struct Tst_Question *Question, const struct Tst_Question *Question,
Tst_AnswerType_t AnswerType,
const struct Tst_Answer *Answer, const struct Tst_Answer *Answer,
bool QuestionExists) bool QuestionExists)
{ {
@ -991,13 +1002,13 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
/***** Write the question type *****/ /***** Write the question type *****/
HTM_TD_Begin ("class=\"%s CT COLOR%u\"",ClassData,Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"%s CT COLOR%u\"",ClassData,Gbl.RowEvenOdd);
HTM_TxtF ("%s&nbsp;",Txt_TST_STR_ANSWER_TYPES[Gbl.Test.AnswerType]); HTM_TxtF ("%s&nbsp;",Txt_TST_STR_ANSWER_TYPES[AnswerType]);
HTM_TD_End (); HTM_TD_End ();
/***** Write if shuffle is enabled *****/ /***** Write if shuffle is enabled *****/
HTM_TD_Begin ("class=\"CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"CT COLOR%u\"",Gbl.RowEvenOdd);
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || if (AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) AnswerType == Tst_ANS_MULTIPLE_CHOICE)
/* Put an icon that indicates whether shuffle is enabled or not */ /* Put an icon that indicates whether shuffle is enabled or not */
if (Question->Shuffle) if (Question->Shuffle)
Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers, Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,
@ -1010,7 +1021,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
Tst_WriteQstStem (Stem,ClassStem, Tst_WriteQstStem (Stem,ClassStem,
true); // Visible true); // Visible
Tst_WriteQstFeedback (Feedback,"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (Feedback,"TEST_EDI_LIGHT");
switch (Gbl.Test.AnswerType) switch (AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
HTM_SPAN_Begin ("class=\"%s\"",ClassStem); HTM_SPAN_Begin ("class=\"%s\"",ClassStem);