diff --git a/swad_changelog.h b/swad_changelog.h index ce8b4417..17c2a166 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -497,13 +497,13 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.153 (2020-03-24)" +#define Log_PLATFORM_VERSION "SWAD 19.154 (2020-03-25)" #define CSS_FILE "swad19.146.css" #define JS_FILE "swad19.153.js" /* * // TODO: Geolocalización: -Función API sendLocation... +Función API sendCurrentLocation... Parámetros: string con ubicación (ej. "Aula 0.1") Poblar base de datos: @@ -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: 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.154: Mar 25, 2020 Code refactoring in tests. (283385 lines) Version 19.153: Mar 24, 2020 Code refactoring in tests. (283432 lines) Version 19.152.4: Mar 24, 2020 Code refactoring in tests. (283459 lines) Version 19.152.3: Mar 23, 2020 Code refactoring in tests. (283512 lines) diff --git a/swad_game.c b/swad_game.c index f706d605..55757b30 100644 --- a/swad_game.c +++ b/swad_game.c @@ -156,7 +156,8 @@ static void Gam_ListGameQuestions (struct Game *Game); static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, MYSQL_RES *mysql_res, bool ICanEditQuestions); -static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd); +static void Gam_ListQuestionForEdition (struct Tst_Question *Question, + unsigned QstInd); static void Gam_PutIconToAddNewQuestions (void); static void Gam_PutButtonToAddNewQuestions (void); @@ -1873,7 +1874,6 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, extern const char *Txt_Movement_not_allowed; unsigned NumQst; MYSQL_ROW row; - long QstCod; struct Tst_Question Question; unsigned QstInd; unsigned MaxQstInd; @@ -1902,13 +1902,15 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, { Gbl.RowEvenOdd = NumQst % 2; + /***** Create test question *****/ + Tst_QstConstructor (&Question); + + /***** Get question data *****/ row = mysql_fetch_row (mysql_res); /* row[0] QstInd row[1] QstCod */ - /***** Create test question *****/ - Tst_QstConstructor (&Question); /* Get question index (row[0]) */ QstInd = Str_ConvertStrToUnsigned (row[0]); @@ -1917,7 +1919,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, QstInd); /* Get question code (row[1]) */ - QstCod = Str_ConvertStrCodToLongCod (row[1]); + Question.QstCod = Str_ConvertStrCodToLongCod (row[1]); /***** Icons *****/ Gam_SetCurrentGamCod (GamCod); // Used to pass parameter @@ -1965,14 +1967,14 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, /* Put icon to edit the question */ if (ICanEditQuestions) { - Tst_SetParamGblQstCod (QstCod); + Tst_SetParamGblQstCod (Question.QstCod); Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,Tst_PutParamGblQstCod); } HTM_TD_End (); /***** Question *****/ - Gam_ListQuestionForEdition (QstCod,QstInd); + Gam_ListQuestionForEdition (&Question,QstInd); HTM_TR_End (); @@ -1988,7 +1990,8 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, /********************** List game question for edition ***********************/ /*****************************************************************************/ -static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd) +static void Gam_ListQuestionForEdition (struct Tst_Question *Question, + unsigned QstInd) { extern const char *Txt_Question_removed; MYSQL_RES *mysql_res; @@ -1998,7 +2001,7 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd) struct Media Media; /***** Get question from database *****/ - QstExists = Tst_GetOneQuestionByCod (QstCod,&mysql_res); // Question exists? + QstExists = Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res); // Question exists? if (QstExists) { @@ -2029,13 +2032,13 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd) /***** Write question code *****/ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - HTM_TxtF ("%ld ",QstCod); + HTM_TxtF ("%ld ",Question->QstCod); HTM_TD_End (); /***** Write the question tags *****/ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); if (QstExists) - Tst_GetAndWriteTagsQst (QstCod); + Tst_GetAndWriteTagsQst (Question->QstCod); HTM_TD_End (); /***** Write stem (row[3]) and media *****/ @@ -2059,7 +2062,7 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd) Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); /* Show answers */ - Tst_WriteAnswersEdit (QstCod,AnswerType); + Tst_WriteAnswersEdit (Question); } else { diff --git a/swad_match.c b/swad_match.c index 48d36a1b..ad84100e 100644 --- a/swad_match.c +++ b/swad_match.c @@ -140,7 +140,7 @@ static void Mch_ShowLstGrpsToCreateMatch (void); static long Mch_CreateMatch (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1]); static void Mch_CreateIndexes (long GamCod,long MchCod); static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, - long QstCod,bool Shuffle); + const struct Tst_Question *Question); static void Mch_CreateGrps (long MchCod); static void Mch_UpdateMatchStatusInDB (const struct Match *Match); @@ -1448,11 +1448,9 @@ static void Mch_CreateIndexes (long GamCod,long MchCod) MYSQL_ROW row; unsigned NumQsts; unsigned NumQst; - long QstCod; + struct Tst_Question Question; long LongNum; unsigned QstInd; - Tst_AnswerType_t AnswerType; - bool Shuffle; /***** Get questions of the game *****/ NumQsts = (unsigned) @@ -1472,11 +1470,20 @@ static void Mch_CreateIndexes (long GamCod,long MchCod) NumQst < NumQsts; NumQst++) { + /***** Create test question *****/ + Tst_QstConstructor (&Question); + /***** Get question data *****/ row = mysql_fetch_row (mysql_res); + /* + gam_questions.QstCod row[0] + gam_questions.QstInd row[1] + tst_questions.AnsType row[2] + tst_questions.Shuffle row[3] + */ /* Get question code (row[0]) */ - if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) + if ((Question.QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) Lay_ShowErrorAndExit ("Wrong code of question."); /* Get question index (row[1]) */ @@ -1485,15 +1492,18 @@ static void Mch_CreateIndexes (long GamCod,long MchCod) QstInd = (unsigned) LongNum; /* Get answer type (row[2]) */ - AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[2]); - if (AnswerType != Tst_ANS_UNIQUE_CHOICE) + Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[2]); + if (Question.Answer.Type != Tst_ANS_UNIQUE_CHOICE) Lay_ShowErrorAndExit ("Wrong answer type."); /* Get shuffle (row[3]) */ - Shuffle = (row[3][0] == 'Y'); + Question.Shuffle = (row[3][0] == 'Y'); /***** Reorder answer *****/ - Mch_ReorderAnswer (MchCod,QstInd,QstCod,Shuffle); + Mch_ReorderAnswer (MchCod,QstInd,&Question); + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); } /***** Free structure that stores the query result *****/ @@ -1505,7 +1515,7 @@ static void Mch_CreateIndexes (long GamCod,long MchCod) /*****************************************************************************/ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, - long QstCod,bool Shuffle) + const struct Tst_Question *Question) { MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -1526,9 +1536,9 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, " FROM tst_answers" " WHERE QstCod=%ld" " ORDER BY %s", - QstCod, - Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order - "AnsInd"); + Question->QstCod, + Question->Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order + "AnsInd"); /***** For each answer in question... *****/ for (NumAns = 0; @@ -3799,34 +3809,30 @@ static void Mch_ComputeScore (struct TsR_Result *Result) unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]; - /***** Create test question *****/ - Tst_QstConstructor (&Question); - Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; - Result->Score = 0.0; - - for (NumQst = 0; + for (NumQst = 0, Result->Score = 0.0; NumQst < Result->NumQsts; NumQst++) { - /***** Get indexes for this question from string *****/ - Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes); - - /***** Get the user's answers for this question from string *****/ - Tst_GetAnswersFromStr (Result->StrAnswers[NumQst],AnswersUsr); + /***** Create test question *****/ + Tst_QstConstructor (&Question); + Question.QstCod = Result->QstCodes[NumQst]; + Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; /***** Get correct answers of test question from database *****/ - Tst_GetCorrectAnswersFromDB (Result->QstCodes[NumQst],&Question); + Tst_GetCorrectAnswersFromDB (&Question); - /***** Compute the total score of this question *****/ + /***** Compute the score of this question *****/ + Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes); + Tst_GetAnswersFromStr (Result->StrAnswers[NumQst],AnswersUsr); Tst_ComputeScoreQst (&Question, Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank); /***** Update total score *****/ Result->Score += ScoreThisQst; - } - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); + } } /*****************************************************************************/ diff --git a/swad_test.c b/swad_test.c index b719b98a..134775b6 100644 --- a/swad_test.c +++ b/swad_test.c @@ -119,14 +119,14 @@ extern struct Globals Gbl; /*****************************************************************************/ static long Tst_ParamGblQstCod = -1L; // Used to pass parameter to function -struct Tst_Test Tst_Test; // Used to pass parameters to functions +struct Tst_Test Tst_ParamGblTest; // Used to pass parameters to functions /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ +static void Tst_ResetTest (struct Tst_Test *Test); static void Tst_ResetTags (struct Tst_Tags *Tags); -static void Tst_ResetAnswerTypes (struct Tst_AnswerTypes *AnswerTypes); static void Tst_ShowFormRequestTest (struct Tst_Test *Test); @@ -151,7 +151,7 @@ static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst); static void Tst_UpdateLastAccTst (unsigned NumQsts); static void Tst_ShowFormRequestEditTests (struct Tst_Test *Test); -static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Tags *Tags); +static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Test *Test); static bool Tst_CheckIfICanEditTests (void); static void Tst_PutIconsTests (void); static void Tst_PutButtonToAddQuestion (void); @@ -174,28 +174,27 @@ static void Tst_PutInputFieldNumQst (const char *Field,const char *Label, static void Tst_ShowFormAnswerTypes (const struct Tst_AnswerTypes *AnswerTypes); static void Tst_GetQuestions (struct Tst_Test *Test,MYSQL_RES **mysql_res); static void Tst_GetQuestionsForTest (struct Tst_Test *Test,MYSQL_RES **mysql_res); -static void Tst_ListOneQstToEdit (struct Tst_Test *Test,long QstCod); +static void Tst_ListOneQstToEdit (struct Tst_Test *Test, + struct Tst_Question *Question); static void Tst_ListOneOrMoreQuestionsForEdition (const struct Tst_Test *Test, MYSQL_RES *mysql_res); static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Test *Test); static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, unsigned NumQst, - long QstCod); + struct Tst_Question *Question); static void Tst_ListOneOrMoreQuestionsForSelection (unsigned NumQsts, MYSQL_RES *mysql_res); static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod); -static void Tst_ResetGblTags (void); -static void Tst_GetParamGblTags (struct Tst_Tags *TagsDst); -static void Tst_ResetGblAnswerTypes (void); -static void Tst_GetParamGblAnswerTypes (struct Tst_AnswerTypes *AnswerTypesDst); +static void Tst_ResetParamGblTest (void); -static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType,bool Shuffle); +static void Tst_WriteAnswersTestToAnswer (unsigned NumQst, + struct Tst_Question *Question, + bool Shuffle); static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, const struct TsR_Result *Result, - unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType, + unsigned NumQst, + struct Tst_Question *Question, unsigned Visibility, double *ScoreThisQst,bool *AnswerIsNotBlank); @@ -209,8 +208,8 @@ static void Tst_WriteTFAnsAssessTest (struct UsrData *UsrDat, double *ScoreThisQst, bool *AnswerIsNotBlank); -static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType, +static void Tst_WriteChoiceAnsViewTest (unsigned NumQst, + struct Tst_Question *Question, bool Shuffle); static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, const struct TsR_Result *Result, @@ -220,7 +219,7 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, unsigned Visibility, double *ScoreThisQst, bool *AnswerIsNotBlank); -static void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Question *Question); +static void Tst_GetChoiceAns (struct Tst_Question *Question,MYSQL_RES *mysql_res); static void Tst_WriteTextAnsViewTest (unsigned NumQst); static void Tst_WriteTextAnsAssessTest (struct UsrData *UsrDat, @@ -265,9 +264,7 @@ static int Tst_CountNumAnswerTypesInList (const struct Tst_AnswerTypes *AnswerTy static void Tst_FreeTagsList (struct Tst_Tags *Tags); -static void Tst_PutFormEditOneQst (long QstCod, - const struct Tst_Question *Question, - const struct Tst_Tags *Tags, +static void Tst_PutFormEditOneQst (const struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]); static void Tst_PutFloatInputField (const char *Label,const char *Field, @@ -282,9 +279,7 @@ static void Tst_FreeTextChoiceAnswer (struct Tst_Question *Question,unsigned Num static void Tst_ResetMediaOfQuestion (struct Tst_Question *Question); static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question); -static void Tst_GetQstDataFromDB (long QstCod, - struct Tst_Question *Question, - struct Tst_Tags *Tags, +static void Tst_GetQstDataFromDB (struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]); static long Tst_GetMedCodFromDB (long CrsCod,long QstCod,int NumOpt); @@ -292,11 +287,9 @@ static void Tst_GetMediaFromDB (long CrsCod,long QstCod,int NumOpt, struct Media *Media); static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr); -static long Tst_GetQstFromForm (struct Tst_Question *Question, - struct Tst_Tags *Tags, +static void Tst_GetQstFromForm (struct Tst_Question *Question, char *Stem,char *Feedback); -static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, - struct Tst_Question *Question); +static void Tst_MoveMediaToDefinitiveDirectories (struct Tst_Question *Question); static long Tst_GetTagCodFromTagTxt (const char *TagTxt); static long Tst_CreateNewTag (long CrsCod,const char *TagTxt); @@ -310,10 +303,9 @@ static void Tst_RemoveOneQstFromDB (long CrsCod,long QstCod); static long Tst_GetQstCod (void); -static long Tst_InsertOrUpdateQstIntoDB (long QstCod, - const struct Tst_Question *Question); -static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags); -static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question); +static void Tst_InsertOrUpdateQstIntoDB (struct Tst_Question *Question); +static void Tst_InsertTagsIntoDB (const struct Tst_Question *Question); +static void Tst_InsertAnswersIntoDB (struct Tst_Question *Question); static void Tst_RemAnsFromQst (long QstCod); static void Tst_RemTagsFromQst (long QstCod); @@ -335,16 +327,30 @@ void Tst_RequestTest (void) { struct Tst_Test Test; - /***** Reset tags *****/ - Tst_ResetTags (&Test.Tags); - - /***** Reset answer types *****/ - Tst_ResetAnswerTypes (&Test.AnswerTypes); + /***** Reset test *****/ + Tst_ResetTest (&Test); /***** Show form to generate a self-assessment test *****/ Tst_ShowFormRequestTest (&Test); } +/*****************************************************************************/ +/***************************** Reset answer types ****************************/ +/*****************************************************************************/ + +static void Tst_ResetTest (struct Tst_Test *Test) + { + /***** Reset tags *****/ + Tst_ResetTags (&Test->Tags); + + /***** Reset answer types *****/ + Test->AnswerTypes.All = false; + Test->AnswerTypes.List[0] = '\0'; + + /***** Reset selected order *****/ + Test->SelectedOrder = Tst_DEFAULT_ORDER; + } + /*****************************************************************************/ /********************************* Reset tags ********************************/ /*****************************************************************************/ @@ -356,16 +362,6 @@ static void Tst_ResetTags (struct Tst_Tags *Tags) Tags->List = NULL; } -/*****************************************************************************/ -/***************************** Reset answer types ****************************/ -/*****************************************************************************/ - -static void Tst_ResetAnswerTypes (struct Tst_AnswerTypes *AnswerTypes) - { - AnswerTypes->All = false; - AnswerTypes->List[0] = '\0'; - } - /*****************************************************************************/ /*************** Show form to generate a self-assessment test ****************/ /*****************************************************************************/ @@ -383,8 +379,7 @@ static void Tst_ShowFormRequestTest (struct Tst_Test *Test) TstCfg_GetConfigFromDB (); /***** Begin box *****/ - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Box_BoxBegin (NULL,Txt_Take_a_test,Tst_PutIconsTests, Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE); @@ -1046,6 +1041,7 @@ static void Tst_WriteQstAndAnsTestToAnswer (unsigned NumQst, /***** Create test question *****/ Tst_QstConstructor (&Question); + Question.QstCod = QstCod; /***** Begin row *****/ HTM_TR_Begin (NULL); @@ -1071,7 +1067,7 @@ static void Tst_WriteQstAndAnsTestToAnswer (unsigned NumQst, "TEST_MED_SHOW"); /* Answers depending on shuffle (row[2]) */ - Tst_WriteAnswersTestToAnswer (NumQst,QstCod,Question.Answer.Type,(row[2][0] == 'Y')); + Tst_WriteAnswersTestToAnswer (NumQst,&Question,(row[2][0] == 'Y')); HTM_TD_End (); @@ -1109,6 +1105,7 @@ void Tst_WriteQstAndAnsTestResult (struct UsrData *UsrDat, /***** Create test question *****/ Tst_QstConstructor (&Question); + Question.QstCod = Result->QstCodes[NumQst]; /***** Begin row *****/ HTM_TR_Begin (NULL); @@ -1138,7 +1135,7 @@ void Tst_WriteQstAndAnsTestResult (struct UsrData *UsrDat, /* Answers */ Tst_WriteAnswersTestResult (UsrDat,Result, - NumQst,Result->QstCodes[NumQst],Question.Answer.Type, + NumQst,&Question, Visibility, ScoreThisQst,AnswerIsNotBlank); @@ -1374,11 +1371,8 @@ void Tst_RequestEditTests (void) { struct Tst_Test Test; - /***** Reset tags *****/ - Tst_ResetTags (&Test.Tags); - - /***** Reset answer types *****/ - Tst_ResetAnswerTypes (&Test.AnswerTypes); + /***** Reset test *****/ + Tst_ResetTest (&Test); /***** Show form to generate a self-assessment test *****/ Tst_ShowFormRequestEditTests (&Test); @@ -1407,8 +1401,7 @@ static void Tst_ShowFormRequestEditTests (struct Tst_Test *Test) Mnu_ContextMenuEnd (); /***** Begin box *****/ - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Box_BoxBegin (NULL,Txt_List_edit_questions,Tst_PutIconsTests, Hlp_ASSESSMENT_Tests_editing_questions,Box_NOT_CLOSABLE); @@ -1457,20 +1450,20 @@ static void Tst_ShowFormRequestEditTests (struct Tst_Test *Test) void Tst_RequestSelectTestsForGame (void) { - struct Tst_Tags Tags; + struct Tst_Test Test; - /***** Reset tags *****/ - Tst_ResetTags (&Tags); + /***** Reset test *****/ + Tst_ResetTest (&Test); /***** Show form to select test for game *****/ - Tst_ShowFormRequestSelectTestsForGame (&Tags); + Tst_ShowFormRequestSelectTestsForGame (&Test); // No tags selected } /*****************************************************************************/ /************** Show form to select test questions for a game ****************/ /*****************************************************************************/ -static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Tags *Tags) +static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Test *Test) { extern const char *Hlp_ASSESSMENT_Games_questions; extern const char *Txt_No_test_questions; @@ -1488,7 +1481,7 @@ static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Tags *Tags) Hlp_ASSESSMENT_Games_questions,Box_NOT_CLOSABLE); /***** Get tags already present in the table of questions *****/ - if ((Tags->Num = Tst_GetAllTagsFromCurrentCrs (&mysql_res))) + if ((Test->Tags.Num = Tst_GetAllTagsFromCurrentCrs (&mysql_res))) { Frm_StartForm (ActGamLstTstQst); Gam_PutParams (); @@ -1496,7 +1489,7 @@ static void Tst_ShowFormRequestSelectTestsForGame (struct Tst_Tags *Tags) HTM_TABLE_BeginPadding (2); /***** Selection of tags *****/ - Tst_ShowFormSelTags (Tags,mysql_res,false); + Tst_ShowFormSelTags (&Test->Tags,mysql_res,false); /***** Starting and ending dates in the search *****/ Dat_PutFormStartEndClientLocalDateTimesWithYesterdayToday (SetHMS); @@ -2116,8 +2109,7 @@ static void Tst_ShowFormConfigTst (void) TstCfg_GetConfigFromDB (); /***** Begin box *****/ - Tst_ResetGblTags (); - Tst_ResetGblAnswerTypes (); + Tst_ResetParamGblTest (); Box_BoxBegin (NULL,Txt_Configure_tests,Tst_PutIconsTests, Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE); @@ -2382,7 +2374,7 @@ void Tst_ListQuestionsToSelect (void) } else /* Show the form again */ - Tst_ShowFormRequestSelectTestsForGame (&Test.Tags); + Tst_ShowFormRequestSelectTestsForGame (&Test); /***** Free memory used by the list of tags *****/ Tst_FreeTagsList (&Test.Tags); @@ -2662,7 +2654,8 @@ static void Tst_GetQuestionsForTest (struct Tst_Test *Test,MYSQL_RES **mysql_res /*********************** List a test question for edition ********************/ /*****************************************************************************/ -static void Tst_ListOneQstToEdit (struct Tst_Test *Test,long QstCod) +static void Tst_ListOneQstToEdit (struct Tst_Test *Test, + struct Tst_Question *Question) { extern const char *Hlp_ASSESSMENT_Tests; extern const char *Txt_Questions; @@ -2671,8 +2664,7 @@ static void Tst_ListOneQstToEdit (struct Tst_Test *Test,long QstCod) Test->NumQsts = 1; /***** Begin box *****/ - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Box_BoxBegin (NULL,Txt_Questions,Tst_PutIconsTests, Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE); @@ -2681,7 +2673,7 @@ static void Tst_ListOneQstToEdit (struct Tst_Test *Test,long QstCod) Tst_WriteHeadingRowQuestionsForEdition (Test); /***** Write question row *****/ - Tst_WriteQuestionRowForEdition (Test,0,QstCod); + Tst_WriteQuestionRowForEdition (Test,0,Question); /***** End table *****/ HTM_TABLE_End (); @@ -2727,11 +2719,10 @@ static void Tst_ListOneOrMoreQuestionsForEdition (const struct Tst_Test *Test, extern const char *Txt_Questions; unsigned NumQst; MYSQL_ROW row; - long QstCod; + struct Tst_Question Question; /***** Begin box *****/ - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Box_BoxBegin (NULL,Txt_Questions,Tst_PutIconsTests, Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE); @@ -2746,13 +2737,19 @@ static void Tst_ListOneOrMoreQuestionsForEdition (const struct Tst_Test *Test, { Gbl.RowEvenOdd = NumQst % 2; + /***** Create test question *****/ + Tst_QstConstructor (&Question); + /***** Get question code (row[0]) *****/ row = mysql_fetch_row (mysql_res); - if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) + if ((Question.QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) Lay_ShowErrorAndExit ("Wrong code of question."); /***** Write question row *****/ - Tst_WriteQuestionRowForEdition (Test,NumQst,QstCod); + Tst_WriteQuestionRowForEdition (Test,NumQst,&Question); + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); } /***** End table *****/ @@ -2805,8 +2802,7 @@ static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Test *Test) { Frm_StartForm (ActLstTstQst); Dat_WriteParamsIniEndDates (); - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Tst_WriteParamEditQst (); Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Order); HTM_BUTTON_SUBMIT_Begin (Txt_TST_STR_ORDER_FULL[Order],"BT_LINK TIT_TBL",NULL); @@ -2835,11 +2831,10 @@ static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Test *Test) static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, unsigned NumQst, - long QstCod) + struct Tst_Question *Question) { MYSQL_RES *mysql_res; MYSQL_ROW row; - struct Tst_Question Question; static unsigned UniqueId = 0; char *Id; time_t TimeUTC; @@ -2847,11 +2842,8 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, unsigned long NumHitsNotBlankThisQst; double TotalScoreThisQst; - /***** Create test question *****/ - Tst_QstConstructor (&Question); - - /***** Get and show questvoidion data *****/ - if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) + /***** Get and show question data *****/ + if (Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res)) { /***** Get row from database *****/ row = mysql_fetch_row (mysql_res); @@ -2875,18 +2867,17 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, /* Write icon to remove the question */ Frm_StartForm (ActReqRemOneTstQst); - Tst_PutParamQstCod (QstCod); + Tst_PutParamQstCod (Question->QstCod); if (Test->NumQsts == 1) Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If there are only one row, don't list again after removing Dat_WriteParamsIniEndDates (); - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Tst_WriteParamEditQst (); Ico_PutIconRemove (); Frm_EndForm (); /* Write icon to edit the question */ - Tst_SetParamGblQstCod (QstCod); + Tst_SetParamGblQstCod (Question->QstCod); Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,Tst_PutParamGblQstCod); HTM_TD_End (); @@ -2894,13 +2885,13 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, /* Number of question and answer type (row[1]) */ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); Tst_WriteNumQst (NumQst + 1); - Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); - Tst_WriteAnswerType (Question.Answer.Type); + Question->Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); + Tst_WriteAnswerType (Question->Answer.Type); HTM_TD_End (); /* Question code */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - HTM_TxtF ("%ld ",QstCod); + HTM_TxtF ("%ld ",Question->QstCod); HTM_TD_End (); /* Date (row[0] has the UTC date-time) */ @@ -2917,19 +2908,18 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, /* Question tags */ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - Tst_GetAndWriteTagsQst (QstCod); + Tst_GetAndWriteTagsQst (Question->QstCod); HTM_TD_End (); /* Shuffle (row[2]) */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE || - Question.Answer.Type == Tst_ANS_MULTIPLE_CHOICE) + if (Question->Answer.Type == Tst_ANS_UNIQUE_CHOICE || + Question->Answer.Type == Tst_ANS_MULTIPLE_CHOICE) { Frm_StartForm (ActChgShfTstQst); - Tst_PutParamQstCod (QstCod); + Tst_PutParamQstCod (Question->QstCod); Dat_WriteParamsIniEndDates (); - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); + Tst_SetParamGblTest (Test); Tst_WriteParamEditQst (); if (Test->NumQsts == 1) Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If editing only one question, don't edit others @@ -2948,15 +2938,15 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, true); // Visible /***** Get and show media (row[5]) *****/ - Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Question.Media); - Med_ShowMedia (&Question.Media, + Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); + Med_GetMediaDataByCod (&Question->Media); + Med_ShowMedia (&Question->Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); /* Feedback (row[4]) and answers */ Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); - Tst_WriteAnswersEdit (QstCod,Question.Answer.Type); + Tst_WriteAnswersEdit (Question); HTM_TD_End (); /* Get number of hits @@ -3011,9 +3001,6 @@ static void Tst_WriteQuestionRowForEdition (const struct Tst_Test *Test, /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); - - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -3106,9 +3093,10 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod) /***** Create test question *****/ Tst_QstConstructor (&Question); + Question.QstCod = QstCod; /***** Get and show questvoidion data *****/ - if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) + if (Tst_GetOneQuestionByCod (Question.QstCod,&mysql_res)) { /***** Get row of the result of the query *****/ row = mysql_fetch_row (mysql_res); @@ -3133,7 +3121,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod) /* Write checkbox to select the question */ HTM_INPUT_CHECKBOX ("QstCods",HTM_DONT_SUBMIT_ON_CHANGE, "value=\"%ld\"", - QstCod); + Question.QstCod); /* Write number of question */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); @@ -3142,7 +3130,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod) /* Write question code */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - HTM_TxtF ("%ld ",QstCod); + HTM_TxtF ("%ld ",Question.QstCod); HTM_TD_End (); /* Write the date (row[0] has the UTC date-time) */ @@ -3159,7 +3147,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod) /* Write the question tags */ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - Tst_GetAndWriteTagsQst (QstCod); + Tst_GetAndWriteTagsQst (Question.QstCod); HTM_TD_End (); /* Write the question type (row[1]) */ @@ -3192,7 +3180,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst,long QstCod) Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); /* Write answers */ - Tst_WriteAnswersEdit (QstCod,Question.Answer.Type); + Tst_WriteAnswersEdit (&Question); HTM_TD_End (); /***** End table row *****/ @@ -3211,18 +3199,14 @@ void Tst_WriteParamEditQst (void) { struct Tst_Test Test; - Tst_GetParamGblTags (&Test.Tags); - Par_PutHiddenParamChar ("AllTags", - Test.Tags.All ? 'Y' : - 'N'); - Par_PutHiddenParamString (NULL,"ChkTag", - Test.Tags.List ? Test.Tags.List : - ""); + Tst_GetParamGblTest (&Test); - Tst_GetParamGblAnswerTypes (&Test.AnswerTypes); - Par_PutHiddenParamChar ("AllAnsTypes", - Test.AnswerTypes.All ? 'Y' : - 'N'); + Par_PutHiddenParamChar ("AllTags",Test.Tags.All ? 'Y' : + 'N'); + Par_PutHiddenParamString (NULL,"ChkTag",Test.Tags.List ? Test.Tags.List : + ""); + Par_PutHiddenParamChar ("AllAnsTypes",Test.AnswerTypes.All ? 'Y' : + 'N'); Par_PutHiddenParamString (NULL,"AnswerType",Test.AnswerTypes.List); } @@ -3230,62 +3214,43 @@ void Tst_WriteParamEditQst (void) /************************* Function parameter with tags **********************/ /*****************************************************************************/ -static void Tst_ResetGblTags (void) +static void Tst_ResetParamGblTest (void) { - Tst_ResetTags (&Tst_Test.Tags); + Tst_ResetTest (&Tst_ParamGblTest); } -void Tst_SetParamGblTags (const struct Tst_Tags *TagsSrc) +void Tst_SetParamGblTest (const struct Tst_Test *TestSrc) { - Tst_Test.Tags.Num = TagsSrc->Num; - Tst_Test.Tags.All = TagsSrc->All; - Tst_Test.Tags.List = TagsSrc->List; + /***** Copy tags *****/ + Tst_ParamGblTest.Tags.Num = TestSrc->Tags.Num; + Tst_ParamGblTest.Tags.All = TestSrc->Tags.All; + Tst_ParamGblTest.Tags.List = TestSrc->Tags.List; /* It's not necessary to copy the Txt field */ + + /***** Copy answer types *****/ + Tst_ParamGblTest.AnswerTypes.All = TestSrc->AnswerTypes.All; + Str_Copy (Tst_ParamGblTest.AnswerTypes.List,TestSrc->AnswerTypes.List, + Tst_MAX_BYTES_LIST_ANSWER_TYPES); + + /***** Copy selected order *****/ + Tst_ParamGblTest.SelectedOrder = TestSrc->SelectedOrder; } -static void Tst_GetParamGblTags (struct Tst_Tags *TagsDst) +void Tst_GetParamGblTest (struct Tst_Test *TestDst) { - TagsDst->Num = Tst_Test.Tags.Num; - TagsDst->All = Tst_Test.Tags.All; - TagsDst->List = Tst_Test.Tags.List; + /***** Copy tags *****/ + TestDst->Tags.Num = Tst_ParamGblTest.Tags.Num; + TestDst->Tags.All = Tst_ParamGblTest.Tags.All; + TestDst->Tags.List = Tst_ParamGblTest.Tags.List; /* It's not necessary to copy the Txt field */ - } -/*****************************************************************************/ -/********************* Function parameter with answer types ******************/ -/*****************************************************************************/ - -static void Tst_ResetGblAnswerTypes (void) - { - Tst_ResetAnswerTypes (&Tst_Test.AnswerTypes); - } - -void Tst_SetParamGblAnswerTypes (const struct Tst_AnswerTypes *AnswerTypesSrc) - { - Tst_Test.AnswerTypes.All = AnswerTypesSrc->All; - Str_Copy (Tst_Test.AnswerTypes.List,AnswerTypesSrc->List, + /***** Copy answer types *****/ + TestDst->AnswerTypes.All = Tst_ParamGblTest.AnswerTypes.All; + Str_Copy (TestDst->AnswerTypes.List,Tst_ParamGblTest.AnswerTypes.List, Tst_MAX_BYTES_LIST_ANSWER_TYPES); - } -static void Tst_GetParamGblAnswerTypes (struct Tst_AnswerTypes *AnswerTypesDst) - { - AnswerTypesDst->All = Tst_Test.AnswerTypes.All; - Str_Copy (AnswerTypesDst->List,Tst_Test.AnswerTypes.List, - Tst_MAX_BYTES_LIST_ANSWER_TYPES); - } - -/*****************************************************************************/ -/********************* Function parameter with answer types ******************/ -/*****************************************************************************/ - -void Tst_SetParamGblSelectedOrder (Tst_QuestionsOrder_t SelectedOrder) - { - Tst_Test.SelectedOrder = SelectedOrder; - } - -Tst_QuestionsOrder_t Tst_GetParamGblSelectedOrder (void) - { - return Tst_Test.SelectedOrder; + /***** Copy selected order *****/ + TestDst->SelectedOrder = Tst_ParamGblTest.SelectedOrder; } /*****************************************************************************/ @@ -3301,30 +3266,28 @@ unsigned Tst_GetNumAnswersQst (long QstCod) QstCod); } -unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle) +void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, + bool Shuffle) { - unsigned long NumRows; - /***** Get answers of a question from database *****/ - NumRows = DB_QuerySELECT (mysql_res,"can not get answers of a question", - "SELECT AnsInd," // row[0] - "Answer," // row[1] - "Feedback," // row[2] - "MedCod," // row[3] - "Correct" // row[4] - " FROM tst_answers" - " WHERE QstCod=%ld" - " ORDER BY %s", - QstCod, - Shuffle ? "RAND(NOW())" : - "AnsInd"); - if (!NumRows) + Question->Answer.NumOptions =(unsigned) + DB_QuerySELECT (mysql_res,"can not get answers of a question", + "SELECT AnsInd," // row[0] + "Answer," // row[1] + "Feedback," // row[2] + "MedCod," // row[3] + "Correct" // row[4] + " FROM tst_answers" + " WHERE QstCod=%ld" + " ORDER BY %s", + Question->QstCod, + Shuffle ? "RAND(NOW())" : + "AnsInd"); + if (!Question->Answer.NumOptions) Ale_ShowAlert (Ale_ERROR,"Error when getting answers of a question."); - - return (unsigned) NumRows; } -void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question) +void Tst_GetCorrectAnswersFromDB (struct Tst_Question *Question) { MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -3337,7 +3300,7 @@ void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question) " FROM tst_answers" " WHERE QstCod=%ld" " ORDER BY AnsInd", - QstCod); + Question->QstCod); for (NumOpt = 0; NumOpt < Question->Answer.NumOptions; NumOpt++) @@ -3357,10 +3320,9 @@ void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question) /**************** Get and write the answers of a test question ***************/ /*****************************************************************************/ -void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) +void Tst_WriteAnswersEdit (struct Tst_Question *Question) { extern const char *Txt_TST_Answer_given_by_the_teachers; - struct Tst_Question Question; unsigned NumOpt; unsigned i; MYSQL_RES *mysql_res; @@ -3371,12 +3333,9 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) size_t LengthFeedback; double FloatNum[2]; - /***** Create test question *****/ - Tst_QstConstructor (&Question); - Question.Answer.Type = AnswerType; - /***** Get answers *****/ - Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); + Tst_GetAnswersQst (Question,&mysql_res, + false); // Don't shuffle /* row[0] AnsInd row[1] Answer @@ -3386,17 +3345,17 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) */ /***** Write answers *****/ - switch (Question.Answer.Type) + switch (Question->Answer.Type) { case Tst_ANS_INT: - Tst_CheckIfNumberOfAnswersIsOne (&Question); + Tst_CheckIfNumberOfAnswersIsOne (Question); row = mysql_fetch_row (mysql_res); HTM_SPAN_Begin ("class=\"TEST_EDI\""); HTM_TxtF ("(%ld)",Tst_GetIntAnsFromStr (row[1])); HTM_SPAN_End (); break; case Tst_ANS_FLOAT: - if (Question.Answer.NumOptions != 2) + if (Question->Answer.NumOptions != 2) Lay_ShowErrorAndExit ("Wrong float range."); for (i = 0; @@ -3415,7 +3374,7 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) HTM_SPAN_End (); break; case Tst_ANS_TRUE_FALSE: - Tst_CheckIfNumberOfAnswersIsOne (&Question); + Tst_CheckIfNumberOfAnswersIsOne (Question); row = mysql_fetch_row (mysql_res); HTM_SPAN_Begin ("class=\"TEST_EDI\""); HTM_Txt ("("); @@ -3428,7 +3387,7 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) case Tst_ANS_TEXT: HTM_TABLE_BeginPadding (2); for (NumOpt = 0; - NumOpt < Question.Answer.NumOptions; + NumOpt < Question->Answer.NumOptions; NumOpt++) { row = mysql_fetch_row (mysql_res); @@ -3458,8 +3417,8 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) } /* Get media (row[3]) */ - Question.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); - Med_GetMediaDataByCod (&Question.Answer.Options[NumOpt].Media); + Question->Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Question->Answer.Options[NumOpt].Media); HTM_TR_Begin (NULL); @@ -3480,7 +3439,7 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) /* Write the text of the answer and the media */ HTM_DIV_Begin ("class=\"TEST_EDI\""); HTM_Txt (AnswerTxt); - Med_ShowMedia (&Question.Answer.Options[NumOpt].Media, + Med_ShowMedia (&Question->Answer.Options[NumOpt].Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); HTM_DIV_End (); @@ -3508,23 +3467,21 @@ void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType) /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); - - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); } /*****************************************************************************/ /************** Write answers of a question when viewing a test **************/ /*****************************************************************************/ -static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType,bool Shuffle) +static void Tst_WriteAnswersTestToAnswer (unsigned NumQst, + struct Tst_Question *Question, + bool Shuffle) { /***** Write parameter with question code *****/ - Tst_WriteParamQstCod (NumQst,QstCod); + Tst_WriteParamQstCod (NumQst,Question->QstCod); /***** Write answer depending on type *****/ - switch (AnswerType) + switch (Question->Answer.Type) { case Tst_ANS_INT: Tst_WriteIntAnsViewTest (NumQst); @@ -3537,7 +3494,7 @@ static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod, break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: - Tst_WriteChoiceAnsViewTest (NumQst,QstCod,AnswerType,Shuffle); + Tst_WriteChoiceAnsViewTest (NumQst,Question,Shuffle); break; case Tst_ANS_TEXT: Tst_WriteTextAnsViewTest (NumQst); @@ -3553,20 +3510,16 @@ static void Tst_WriteAnswersTestToAnswer (unsigned NumQst,long QstCod, static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, const struct TsR_Result *Result, - unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType, + unsigned NumQst, + struct Tst_Question *Question, unsigned Visibility, double *ScoreThisQst,bool *AnswerIsNotBlank) { MYSQL_RES *mysql_res; - struct Tst_Question Question; - - /***** Create test question *****/ - Tst_QstConstructor (&Question); - Question.Answer.Type = AnswerType; /***** Get answer of a question from database *****/ - Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); + Tst_GetAnswersQst (Question,&mysql_res, + false); // Don't shuffle /* row[0] AnsInd row[1] Answer @@ -3576,36 +3529,36 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, */ /***** Write answer depending on type *****/ - switch (Question.Answer.Type) + switch (Question->Answer.Type) { case Tst_ANS_INT: Tst_WriteIntAnsAssessTest (UsrDat,Result, - NumQst,&Question,mysql_res, + NumQst,Question,mysql_res, Visibility, ScoreThisQst,AnswerIsNotBlank); break; case Tst_ANS_FLOAT: Tst_WriteFloatAnsAssessTest (UsrDat,Result, - NumQst,&Question,mysql_res, + NumQst,Question,mysql_res, Visibility, ScoreThisQst,AnswerIsNotBlank); break; case Tst_ANS_TRUE_FALSE: Tst_WriteTFAnsAssessTest (UsrDat,Result, - NumQst,&Question,mysql_res, + NumQst,Question,mysql_res, Visibility, ScoreThisQst,AnswerIsNotBlank); break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: Tst_WriteChoiceAnsAssessTest (UsrDat,Result, - NumQst,&Question,mysql_res, + NumQst,Question,mysql_res, Visibility, ScoreThisQst,AnswerIsNotBlank); break; case Tst_ANS_TEXT: Tst_WriteTextAnsAssessTest (UsrDat,Result, - NumQst,&Question,mysql_res, + NumQst,Question,mysql_res, Visibility, ScoreThisQst,AnswerIsNotBlank); break; @@ -3615,9 +3568,6 @@ static void Tst_WriteAnswersTestResult (struct UsrData *UsrDat, /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); - - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -3775,25 +3725,20 @@ static void Tst_WriteTFAnsAssessTest (struct UsrData *UsrDat, /******** Write single or multiple choice answer when viewing a test *********/ /*****************************************************************************/ -static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, - Tst_AnswerType_t AnswerType, +static void Tst_WriteChoiceAnsViewTest (unsigned NumQst, + struct Tst_Question *Question, bool Shuffle) { unsigned NumOpt; MYSQL_RES *mysql_res; MYSQL_ROW row; - struct Tst_Question Question; unsigned Index; bool ErrorInIndex = false; char ParamName[3 + 6 + 1]; char StrAns[32]; - /***** Create test question *****/ - Tst_QstConstructor (&Question); - Question.Answer.Type = AnswerType; - /***** Get answers of a question from database *****/ - Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,Shuffle); + Tst_GetAnswersQst (Question,&mysql_res,Shuffle); /* row[0] AnsInd row[1] Answer @@ -3806,14 +3751,14 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, HTM_TABLE_BeginPadding (2); for (NumOpt = 0; - NumOpt < Question.Answer.NumOptions; + NumOpt < Question->Answer.NumOptions; NumOpt++) { /***** Get next answer *****/ row = mysql_fetch_row (mysql_res); /***** Allocate memory for text in this choice answer *****/ - if (!Tst_AllocateTextChoiceAnswer (&Question,NumOpt)) + if (!Tst_AllocateTextChoiceAnswer (Question,NumOpt)) /* Abort on error */ Ale_ShowAlertsAndExit (); @@ -3831,15 +3776,15 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, Lay_ShowErrorAndExit ("Wrong index of answer when showing a test."); /***** Copy text (row[1]) and convert it, that is in HTML, to rigorous HTML ******/ - Str_Copy (Question.Answer.Options[NumOpt].Text,row[1], + Str_Copy (Question->Answer.Options[NumOpt].Text,row[1], Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, - Question.Answer.Options[NumOpt].Text, + Question->Answer.Options[NumOpt].Text, Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); /***** Get media (row[3]) *****/ - Question.Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); - Med_GetMediaDataByCod (&Question.Answer.Options[NumOpt].Media); + Question->Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); + Med_GetMediaDataByCod (&Question->Answer.Options[NumOpt].Media); HTM_TR_Begin (NULL); @@ -3852,13 +3797,13 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, snprintf (StrAns,sizeof (StrAns), "Ans%03u", NumQst); - if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE) + if (Question->Answer.Type == Tst_ANS_UNIQUE_CHOICE) HTM_INPUT_RADIO (StrAns,false, "id=\"Ans%06u_%u\" value=\"%u\"" " onclick=\"selectUnselectRadio(this,this.form.Ans%03u,%u);\"", NumQst,NumOpt, Index, - NumQst,Question.Answer.NumOptions); + NumQst,Question->Answer.NumOptions); else // Answer.Type == Tst_ANS_MULTIPLE_CHOICE HTM_INPUT_CHECKBOX (StrAns,HTM_DONT_SUBMIT_ON_CHANGE, "id=\"Ans%06u_%u\" value=\"%u\"", @@ -3875,9 +3820,9 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, /***** Write the option text *****/ HTM_TD_Begin ("class=\"LT\""); HTM_LABEL_Begin ("for=\"Ans%06u_%u\" class=\"ANS_TXT\"",NumQst,NumOpt); - HTM_Txt (Question.Answer.Options[NumOpt].Text); + HTM_Txt (Question->Answer.Options[NumOpt].Text); HTM_LABEL_End (); - Med_ShowMedia (&Question.Answer.Options[NumOpt].Media, + Med_ShowMedia (&Question->Answer.Options[NumOpt].Media, "TEST_MED_SHOW_CONT", "TEST_MED_SHOW"); HTM_TD_End (); @@ -3890,9 +3835,6 @@ static void Tst_WriteChoiceAnsViewTest (unsigned NumQst,long QstCod, /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); - - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -3921,7 +3863,7 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, /***** Get text and correctness of answers for this question from database (one row per answer) *****/ - Tst_GetChoiceAns (mysql_res,Question); + Tst_GetChoiceAns (Question,mysql_res); /***** Get indexes for this question from string *****/ Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes); @@ -4053,7 +3995,7 @@ static void Tst_WriteChoiceAnsAssessTest (struct UsrData *UsrDat, /************************ Get choice answer from row *************************/ /*****************************************************************************/ -static void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Question *Question) +static void Tst_GetChoiceAns (struct Tst_Question *Question,MYSQL_RES *mysql_res) { unsigned NumOpt; MYSQL_ROW row; @@ -4263,12 +4205,14 @@ void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod, /***** Create test question *****/ Tst_QstConstructor (&Question); + Question.QstCod = QstCod; /***** Get number of users who have answered this question from database *****/ NumRespondersQst = Mch_GetNumUsrsWhoAnsweredQst (MchCod,QstInd); /***** Get answers of a question from database *****/ - Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); + Tst_GetAnswersQst (&Question,&mysql_res, + false); // Don't shuffle /* row[0] AnsInd row[1] Answer @@ -5177,27 +5121,23 @@ static void Tst_FreeTagsList (struct Tst_Tags *Tags) void Tst_ShowFormEditOneQst (void) { - long QstCod; struct Tst_Question Question; - struct Tst_Tags Tags; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; /***** Create test question *****/ Tst_QstConstructor (&Question); - Tst_ResetTags (&Tags); /***** Get question data *****/ - QstCod = Tst_GetQstCod (); + Question.QstCod = Tst_GetQstCod (); Stem[0] = Feedback[0] = '\0'; - if (QstCod > 0) // If question already exists in the database - Tst_GetQstDataFromDB (QstCod,&Question,&Tags,Stem,Feedback); + if (Question.QstCod > 0) // If question already exists in the database + Tst_GetQstDataFromDB (&Question,Stem,Feedback); /***** Put form to edit question *****/ - Tst_PutFormEditOneQst (QstCod,&Question,&Tags,Stem,Feedback); + Tst_PutFormEditOneQst (&Question,Stem,Feedback); /***** Destroy test question *****/ - Tst_FreeTagsList (&Tags); Tst_QstDestructor (&Question); } @@ -5210,9 +5150,7 @@ void Tst_ShowFormEditOneQst (void) // 2. By clicking "Edit" icon in a listing of existing questions // 3. From the action associated to reception of a question, on error in the parameters received from the form -static void Tst_PutFormEditOneQst (long QstCod, - const struct Tst_Question *Question, - const struct Tst_Tags *Tags, +static void Tst_PutFormEditOneQst (const struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]) { @@ -5254,10 +5192,10 @@ static void Tst_PutFormEditOneQst (long QstCod, char *Title; /***** Begin box *****/ - if (QstCod > 0) // The question already has assigned a code + if (Question->QstCod > 0) // The question already has assigned a code { - Tst_SetParamGblQstCod (QstCod); - Box_BoxBegin (NULL,Str_BuildStringLong (Txt_Question_code_X,QstCod), + Tst_SetParamGblQstCod (Question->QstCod); + Box_BoxBegin (NULL,Str_BuildStringLong (Txt_Question_code_X,Question->QstCod), Tst_PutIconToRemoveOneQst, Hlp_ASSESSMENT_Tests_writing_a_question,Box_NOT_CLOSABLE); Str_FreeString (); @@ -5268,8 +5206,7 @@ static void Tst_PutFormEditOneQst (long QstCod, /***** Begin form *****/ Frm_StartForm (ActRcvTstQst); - if (QstCod > 0) // The question already has assigned a code - Tst_PutParamQstCod (QstCod); + Tst_PutParamQstCod (Question->QstCod); /***** Begin table *****/ HTM_TABLE_BeginPadding (2); // Table for this question @@ -5320,7 +5257,7 @@ static void Tst_PutFormEditOneQst (long QstCod, row[2] TagHidden */ IsThisTag = false; - if (!strcasecmp (Tags->Txt[IndTag],row[1])) + if (!strcasecmp (Question->Tags.Txt[IndTag],row[1])) { HTM_Txt (" selected=\"selected\""); IsThisTag = true; @@ -5331,10 +5268,10 @@ static void Tst_PutFormEditOneQst (long QstCod, "%s",row[1]); } /* If it's a new tag received from the form */ - if (!TagFound && Tags->Txt[IndTag][0]) - HTM_OPTION (HTM_Type_STRING,Tags->Txt[IndTag], + if (!TagFound && Question->Tags.Txt[IndTag][0]) + HTM_OPTION (HTM_Type_STRING,Question->Tags.Txt[IndTag], true,false, - "%s",Tags->Txt[IndTag]); + "%s",Question->Tags.Txt[IndTag]); HTM_OPTION (HTM_Type_STRING,"", false,false, "[%s]",Txt_new_tag); @@ -5346,7 +5283,7 @@ static void Tst_PutFormEditOneQst (long QstCod, snprintf (StrTagTxt,sizeof (StrTagTxt), "TagTxt%u", IndTag); - HTM_INPUT_TEXT (StrTagTxt,Tst_MAX_CHARS_TAG,Tags->Txt[IndTag],false, + HTM_INPUT_TEXT (StrTagTxt,Tst_MAX_CHARS_TAG,Question->Tags.Txt[IndTag],false, "id=\"%s\" class=\"TAG_TXT\" onchange=\"changeSelTag('%u')\"", StrTagTxt,IndTag); HTM_TD_End (); @@ -5611,7 +5548,7 @@ static void Tst_PutFormEditOneQst (long QstCod, HTM_TABLE_End (); // Table for this question /***** Send button *****/ - if (QstCod > 0) // The question already has assigned a code + if (Question->QstCod > 0) // The question already has assigned a code Btn_PutConfirmButton (Txt_Save_changes); else Btn_PutCreateButton (Txt_Create_question); @@ -5675,6 +5612,8 @@ void Tst_QstConstructor (struct Tst_Question *Question) { unsigned NumOpt; + Tst_ResetTags (&Question->Tags); + Question->Stem.Text = NULL; Question->Stem.Length = 0; Question->Feedback.Text = NULL; @@ -5717,9 +5656,12 @@ void Tst_QstDestructor (struct Tst_Question *Question) /*****************************************************************************/ /******************* Allocate memory for a choice answer *********************/ /*****************************************************************************/ +// Return false on error -int Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt) +bool Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt) { + Tst_FreeTagsList (&Question->Tags); + Tst_FreeTextChoiceAnswer (Question,NumOpt); if ((Question->Answer.Options[NumOpt].Text = @@ -5727,19 +5669,19 @@ int Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt) { Ale_CreateAlert (Ale_ERROR,NULL, "Not enough memory to store answer."); - return 0; + return false; } if ((Question->Answer.Options[NumOpt].Feedback = (char *) malloc (Tst_MAX_BYTES_ANSWER_OR_FEEDBACK + 1)) == NULL) { Ale_CreateAlert (Ale_ERROR,NULL, "Not enough memory to store feedback."); - return 0; + return false; } Question->Answer.Options[NumOpt].Text[0] = Question->Answer.Options[NumOpt].Feedback[0] = '\0'; - return 1; + return true; } /*****************************************************************************/ @@ -5811,9 +5753,7 @@ static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question) /****************** Get data of a question from database *********************/ /*****************************************************************************/ -static void Tst_GetQstDataFromDB (long QstCod, - struct Tst_Question *Question, - struct Tst_Tags *Tags, +static void Tst_GetQstDataFromDB (struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]) { @@ -5833,7 +5773,7 @@ static void Tst_GetQstDataFromDB (long QstCod, "MedCod" // row[4] " FROM tst_questions" " WHERE QstCod=%ld AND CrsCod=%ld", - QstCod,Gbl.Hierarchy.Crs.CrsCod); + Question->QstCod,Gbl.Hierarchy.Crs.CrsCod); row = mysql_fetch_row (mysql_res); /* Get the type of answer */ @@ -5861,13 +5801,13 @@ static void Tst_GetQstDataFromDB (long QstCod, DB_FreeMySQLResult (&mysql_res); /***** Get the tags from the database *****/ - NumRows = Tst_GetTagsQst (QstCod,&mysql_res); + NumRows = Tst_GetTagsQst (Question->QstCod,&mysql_res); for (NumRow = 0; NumRow < NumRows; NumRow++) { row = mysql_fetch_row (mysql_res); - Str_Copy (Tags->Txt[NumRow],row[0], + Str_Copy (Question->Tags.Txt[NumRow],row[0], Tst_MAX_BYTES_TAG); } @@ -5875,7 +5815,8 @@ static void Tst_GetQstDataFromDB (long QstCod, DB_FreeMySQLResult (&mysql_res); /***** Get the answers from the database *****/ - Question->Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); + Tst_GetAnswersQst (Question,&mysql_res, + false); // Don't shuffle /* row[0] AnsInd row[1] Answer @@ -6042,7 +5983,6 @@ static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *Unsigned void Tst_ReceiveQst (void) { - long QstCod; struct Tst_Question Question; struct Tst_Test Test; char Stem[Cns_MAX_BYTES_TEXT + 1]; @@ -6050,28 +5990,27 @@ void Tst_ReceiveQst (void) /***** Create test question *****/ Tst_QstConstructor (&Question); - Tst_ResetTags (&Test.Tags); - Tst_ResetAnswerTypes (&Test.AnswerTypes); - Test.SelectedOrder = Tst_DEFAULT_ORDER; /***** Get parameters of the question from form *****/ Stem[0] = Feedback[0] = '\0'; - QstCod = Tst_GetQstFromForm (&Question,&Test.Tags,Stem,Feedback); - snprintf (Test.AnswerTypes.List,sizeof (Test.AnswerTypes.List), - "%u", - (unsigned) Question.Answer.Type); + Tst_GetQstFromForm (&Question,Stem,Feedback); /***** Make sure that tags, text and answer are not empty *****/ - if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Test.Tags)) + if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question)) { /***** Move images to definitive directories *****/ - Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question); + Tst_MoveMediaToDefinitiveDirectories (&Question); /***** Insert or update question, tags and answer in the database *****/ - QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question,&Test.Tags); + Tst_InsertOrUpdateQstTagsAnsIntoDB (&Question); /***** Show the question just inserted in the database *****/ - Tst_ListOneQstToEdit (&Test,QstCod); + Tst_ResetTest (&Test); + snprintf (Test.AnswerTypes.List,sizeof (Test.AnswerTypes.List), + "%u", + (unsigned) Question.Answer.Type); + Tst_ListOneQstToEdit (&Test,&Question); + Tst_FreeTagsList (&Test.Tags); } else // Question is wrong { @@ -6079,11 +6018,10 @@ void Tst_ReceiveQst (void) Tst_ResetMediaOfQuestion (&Question); /***** Put form to edit question again *****/ - Tst_PutFormEditOneQst (QstCod,&Question,&Test.Tags,Stem,Feedback); + Tst_PutFormEditOneQst (&Question,Stem,Feedback); } /***** Destroy test question *****/ - Tst_FreeTagsList (&Test.Tags); Tst_QstDestructor (&Question); } @@ -6091,11 +6029,9 @@ void Tst_ReceiveQst (void) /**************** Get parameters of a test question from form ****************/ /*****************************************************************************/ -static long Tst_GetQstFromForm (struct Tst_Question *Question, - struct Tst_Tags *Tags, +static void Tst_GetQstFromForm (struct Tst_Question *Question, char *Stem,char *Feedback) { - long QstCod; unsigned NumTag; unsigned NumTagRead; unsigned NumOpt; @@ -6109,7 +6045,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, unsigned NumCorrectAns; /***** Get question code *****/ - QstCod = Tst_GetQstCod (); + Question->QstCod = Tst_GetQstCod (); /***** Get answer type *****/ Question->Answer.Type = (Tst_AnswerType_t) @@ -6128,19 +6064,19 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, snprintf (TagStr,sizeof (TagStr), "TagTxt%u", NumTag); - Par_GetParToText (TagStr,Tags->Txt[NumTag],Tst_MAX_BYTES_TAG); + Par_GetParToText (TagStr,Question->Tags.Txt[NumTag],Tst_MAX_BYTES_TAG); - if (Tags->Txt[NumTag][0]) + if (Question->Tags.Txt[NumTag][0]) { Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT, - Tags->Txt[NumTag],Tst_MAX_BYTES_TAG,true); + Question->Tags.Txt[NumTag],Tst_MAX_BYTES_TAG,true); /* Check if not repeated */ for (NumTagRead = 0; NumTagRead < NumTag; NumTagRead++) - if (!strcmp (Tags->Txt[NumTagRead],Tags->Txt[NumTag])) + if (!strcmp (Question->Tags.Txt[NumTagRead],Question->Tags.Txt[NumTag])) { - Tags->Txt[NumTag][0] = '\0'; + Question->Tags.Txt[NumTag][0] = '\0'; break; } } @@ -6156,7 +6092,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, Question->Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; Question->Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; Question->Media.Quality = Tst_IMAGE_SAVED_QUALITY; - Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,QstCod, + Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,Question->QstCod, -1, // < 0 ==> the image associated to the stem &Question->Media, Tst_GetMediaFromDB, @@ -6235,7 +6171,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, Question->Answer.Options[NumOpt].Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; Question->Answer.Options[NumOpt].Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; Question->Answer.Options[NumOpt].Media.Quality = Tst_IMAGE_SAVED_QUALITY; - Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,QstCod, + Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,Question->QstCod, (int) NumOpt, // >= 0 ==> the image associated to an answer &Question->Answer.Options[NumOpt].Media, Tst_GetMediaFromDB, @@ -6279,17 +6215,15 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, } /***** Adjust variables related to this test question *****/ - for (NumTag = 0, Tags->Num = 0; + for (NumTag = 0, Question->Tags.Num = 0; NumTag < Tst_MAX_TAGS_PER_QUESTION; NumTag++) - if (Tags->Txt[NumTag][0]) - Tags->Num++; + if (Question->Tags.Txt[NumTag][0]) + Question->Tags.Num++; Question->Stem.Text = Stem; Question->Stem.Length = strlen (Question->Stem.Text); Question->Feedback.Text = Feedback; Question->Feedback.Length = strlen (Question->Feedback.Text); - - return QstCod; } /*****************************************************************************/ @@ -6299,8 +6233,7 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question, // Counts Question->Answer.NumOptions // Computes Question->Answer.Integer and Question->Answer.FloatingPoint[0..1] -bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question, - const struct Tst_Tags *Tags) +bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question) { extern const char *Txt_You_must_type_at_least_one_tag_for_the_question; extern const char *Txt_You_must_type_the_stem_of_the_question; @@ -6321,7 +6254,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Quest Question->Answer.NumOptions = 0; /***** A question must have at least one tag *****/ - if (!Tags->Num) // There are no tags with text + if (!Question->Tags.Num) // There are no tags with text { Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_one_tag_for_the_question); return false; @@ -6482,7 +6415,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Quest /*********** Check if a test question already exists in database *************/ /*****************************************************************************/ -bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) +bool Tst_CheckIfQuestionExistsInDB (struct Tst_Question *Question) { extern const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES]; MYSQL_RES *mysql_res_qst; @@ -6494,7 +6427,6 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) unsigned NumQstsWithThisStem; unsigned NumOpt; unsigned NumOptsExistingQstInDB; - long QstCod; unsigned i; /***** Check if stem exists *****/ @@ -6517,7 +6449,7 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) { /* Get question code */ row = mysql_fetch_row (mysql_res_qst); - if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) + if ((Question->QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) Lay_ShowErrorAndExit ("Wrong code of question."); /* Get answers from this question */ @@ -6526,7 +6458,7 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) " of a question", "SELECT Answer FROM tst_answers" " WHERE QstCod=%ld ORDER BY AnsInd", - QstCod); + Question->QstCod); switch (Question->Answer.Type) { @@ -6588,14 +6520,13 @@ bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) /* Move images associates to a test question to their definitive directories */ /*****************************************************************************/ -static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, - struct Tst_Question *Question) +static void Tst_MoveMediaToDefinitiveDirectories (struct Tst_Question *Question) { unsigned NumOpt; long CurrentMedCodInDB; /***** Media associated to question stem *****/ - CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod, + CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,Question->QstCod, -1L); // Get current media code associated to stem Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Question->Media); @@ -6608,7 +6539,7 @@ static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, NumOpt < Question->Answer.NumOptions; NumOpt++) { - CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod, + CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,Question->QstCod, NumOpt); // Get current media code associated to this option Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Question->Answer.Options[NumOpt].Media); } @@ -6722,8 +6653,7 @@ void Tst_RequestRemoveSelectedQsts (void) if (Tst_GetParamsTst (&Test,Tst_EDIT_TEST)) // Get parameters from the form { /***** Show question and button to remove question *****/ - Tst_SetParamGblTags (&Test.Tags); - Tst_SetParamGblAnswerTypes (&Test.AnswerTypes); + Tst_SetParamGblTest (&Test); Ale_ShowAlertAndButton (ActRemSevTstQst,NULL,NULL, Tst_PutParamsRemoveSelectedQsts, Btn_REMOVE_BUTTON,Txt_Remove_questions, @@ -6807,14 +6737,17 @@ void Tst_RequestRemoveOneQst (void) { extern const char *Txt_Do_you_really_want_to_remove_the_question_X; extern const char *Txt_Remove_question; - long QstCod; + struct Tst_Question Question; bool EditingOnlyThisQst; struct Tst_Test Test; + /***** Create test question *****/ + Tst_QstConstructor (&Question); + /***** Get main parameters from form *****/ /* Get the question code */ - QstCod = Tst_GetQstCod (); - if (QstCod <= 0) + Question.QstCod = Tst_GetQstCod (); + if (Question.QstCod <= 0) Lay_ShowErrorAndExit ("Wrong code of question."); /* Get a parameter that indicates whether it's necessary @@ -6827,24 +6760,27 @@ void Tst_RequestRemoveOneQst (void) Lay_ShowErrorAndExit ("Wrong test parameters."); /***** Show question and button to remove question *****/ - Tst_SetParamGblQstCod (QstCod); - Tst_SetParamGblTags (&Test.Tags); - Tst_SetParamGblAnswerTypes (&Test.AnswerTypes); + Tst_SetParamGblQstCod (Question.QstCod); + Tst_ResetParamGblTest (); Ale_ShowAlertAndButton (ActRemOneTstQst,NULL,NULL, EditingOnlyThisQst ? Tst_PutParamsRemoveOnlyThisQst : Tst_PutParamsRemoveOneQstWhileEditing, Btn_REMOVE_BUTTON,Txt_Remove_question, Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_question_X, - QstCod); + Question.QstCod); /***** Continue editing questions *****/ if (EditingOnlyThisQst) - Tst_ListOneQstToEdit (&Test,QstCod); - else { + Tst_ResetTest (&Test); + Tst_ListOneQstToEdit (&Test,&Question); Tst_FreeTagsList (&Test.Tags); - Tst_ListQuestionsToEdit (); } + else + Tst_ListQuestionsToEdit (); + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -6939,14 +6875,17 @@ void Tst_ChangeShuffleQst (void) { extern const char *Txt_The_answers_of_the_question_with_code_X_will_appear_shuffled; extern const char *Txt_The_answers_of_the_question_with_code_X_will_appear_without_shuffling; - long QstCod; + struct Tst_Question Question; bool EditingOnlyThisQst; bool Shuffle; struct Tst_Test Test; + /***** Create test question *****/ + Tst_QstConstructor (&Question); + /***** Get the question code *****/ - QstCod = Tst_GetQstCod (); - if (QstCod <= 0) + Question.QstCod = Tst_GetQstCod (); + if (Question.QstCod <= 0) Lay_ShowErrorAndExit ("Wrong code of question."); /***** Get a parameter that indicates whether it's necessary to continue listing the rest of questions ******/ @@ -6962,23 +6901,25 @@ void Tst_ChangeShuffleQst (void) " WHERE QstCod=%ld AND CrsCod=%ld", Shuffle ? 'Y' : 'N', - QstCod,Gbl.Hierarchy.Crs.CrsCod); + Question.QstCod,Gbl.Hierarchy.Crs.CrsCod); /***** Write message *****/ Ale_ShowAlert (Ale_SUCCESS,Shuffle ? Txt_The_answers_of_the_question_with_code_X_will_appear_shuffled : Txt_The_answers_of_the_question_with_code_X_will_appear_without_shuffling, - QstCod); + Question.QstCod); /***** Continue editing questions *****/ if (EditingOnlyThisQst) { - Tst_ResetTags (&Test.Tags); - Tst_ResetAnswerTypes (&Test.AnswerTypes); - Test.SelectedOrder = Tst_DEFAULT_ORDER; - Tst_ListOneQstToEdit (&Test,QstCod); + Tst_ResetTest (&Test); + Tst_ListOneQstToEdit (&Test,&Question); + Tst_FreeTagsList (&Test.Tags); } else Tst_ListQuestionsToEdit (); + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -7012,45 +6953,41 @@ void Tst_PutParamGblQstCod (void) void Tst_PutParamQstCod (long QstCod) { - Par_PutHiddenParamLong (NULL,"QstCod",QstCod); + if (QstCod > 0) // If question exists + Par_PutHiddenParamLong (NULL,"QstCod",QstCod); } /*****************************************************************************/ /******** Insert or update question, tags and anser in the database **********/ /*****************************************************************************/ -long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, - struct Tst_Question *Question, - const struct Tst_Tags *Tags) +void Tst_InsertOrUpdateQstTagsAnsIntoDB (struct Tst_Question *Question) { /***** Insert or update question in the table of questions *****/ - QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question); - if (QstCod > 0) + Tst_InsertOrUpdateQstIntoDB (Question); + if (Question->QstCod > 0) { /***** Insert tags in the tags table *****/ - Tst_InsertTagsIntoDB (QstCod,Tags); + Tst_InsertTagsIntoDB (Question); /***** Remove unused tags in current course *****/ Tst_RemoveUnusedTagsFromCrs (Gbl.Hierarchy.Crs.CrsCod); /***** Insert answers in the answers table *****/ - Tst_InsertAnswersIntoDB (QstCod,Question); + Tst_InsertAnswersIntoDB (Question); } - - return QstCod; } /*****************************************************************************/ /*********** Insert or update question in the table of questions *************/ /*****************************************************************************/ -static long Tst_InsertOrUpdateQstIntoDB (long QstCod, - const struct Tst_Question *Question) +static void Tst_InsertOrUpdateQstIntoDB (struct Tst_Question *Question) { - if (QstCod < 0) // It's a new question + if (Question->QstCod < 0) // It's a new question { /***** Insert question in the table of questions *****/ - QstCod = + Question->QstCod = DB_QueryINSERTandReturnCode ("can not create question", "INSERT INTO tst_questions" " (CrsCod," @@ -7101,21 +7038,19 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod, Question->Feedback.Text ? Question->Feedback.Text : "", Question->Media.MedCod, - QstCod,Gbl.Hierarchy.Crs.CrsCod); + Question->QstCod,Gbl.Hierarchy.Crs.CrsCod); /* Remove answers and tags from this test question */ - Tst_RemAnsFromQst (QstCod); - Tst_RemTagsFromQst (QstCod); + Tst_RemAnsFromQst (Question->QstCod); + Tst_RemTagsFromQst (Question->QstCod); } - - return QstCod; } /*****************************************************************************/ /*********************** Insert tags in the tags table ***********************/ /*****************************************************************************/ -static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags) +static void Tst_InsertTagsIntoDB (const struct Tst_Question *Question) { unsigned NumTag; unsigned TagIdx; @@ -7123,14 +7058,14 @@ static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags) /***** For each tag... *****/ for (NumTag = 0, TagIdx = 0; - TagIdx < Tags->Num; + TagIdx < Question->Tags.Num; NumTag++) - if (Tags->Txt[NumTag][0]) + if (Question->Tags.Txt[NumTag][0]) { /***** Check if this tag exists for current course *****/ - if ((TagCod = Tst_GetTagCodFromTagTxt (Tags->Txt[NumTag])) < 0) + if ((TagCod = Tst_GetTagCodFromTagTxt (Question->Tags.Txt[NumTag])) < 0) /* This tag is new for current course. Add it to tags table */ - TagCod = Tst_CreateNewTag (Gbl.Hierarchy.Crs.CrsCod,Tags->Txt[NumTag]); + TagCod = Tst_CreateNewTag (Gbl.Hierarchy.Crs.CrsCod,Question->Tags.Txt[NumTag]); /***** Insert tag in tst_question_tags *****/ DB_QueryINSERT ("can not create tag", @@ -7138,7 +7073,7 @@ static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags) " (QstCod,TagCod,TagInd)" " VALUES" " (%ld,%ld,%u)", - QstCod,TagCod,TagIdx); + Question->QstCod,TagCod,TagIdx); TagIdx++; } @@ -7148,7 +7083,7 @@ static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags) /******************* Insert answers in the answers table *********************/ /*****************************************************************************/ -static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question) +static void Tst_InsertAnswersIntoDB (struct Tst_Question *Question) { unsigned NumOpt; unsigned i; @@ -7162,7 +7097,7 @@ static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question) " (QstCod,AnsInd,Answer,Feedback,MedCod,Correct)" " VALUES" " (%ld,0,%ld,'',-1,'Y')", - QstCod, + Question->QstCod, Question->Answer.Integer); break; case Tst_ANS_FLOAT: @@ -7175,7 +7110,7 @@ static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question) " (QstCod,AnsInd,Answer,Feedback,MedCod,Correct)" " VALUES" " (%ld,%u,'%.15lg','',-1,'Y')", - QstCod,i, + Question->QstCod,i, Question->Answer.FloatingPoint[i]); Str_SetDecimalPointToLocal (); // Return to local system break; @@ -7185,7 +7120,7 @@ static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question) " (QstCod,AnsInd,Answer,Feedback,MedCod,Correct)" " VALUES" " (%ld,0,'%c','',-1,'Y')", - QstCod, + Question->QstCod, Question->Answer.TF); break; case Tst_ANS_UNIQUE_CHOICE: @@ -7202,7 +7137,7 @@ static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question) " (QstCod,AnsInd,Answer,Feedback,MedCod,Correct)" " VALUES" " (%ld,%u,'%s','%s',%ld,'%c')", - QstCod,NumOpt, + Question->QstCod,NumOpt, Question->Answer.Options[NumOpt].Text, Question->Answer.Options[NumOpt].Feedback ? Question->Answer.Options[NumOpt].Feedback : "", diff --git a/swad_test.h b/swad_test.h index f13bed50..a5851345 100644 --- a/swad_test.h +++ b/swad_test.h @@ -98,6 +98,8 @@ struct Tst_Test struct Tst_Question { + long QstCod; + struct Tst_Tags Tags; struct { char *Text; @@ -176,15 +178,14 @@ void Tst_ListQuestionsToSelect (void); bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res); void Tst_WriteParamEditQst (void); -void Tst_SetParamGblTags (const struct Tst_Tags *TagsSrc); -void Tst_SetParamGblAnswerTypes (const struct Tst_AnswerTypes *AnswerTypesSrc); -void Tst_SetParamGblSelectedOrder (Tst_QuestionsOrder_t SelectedOrder); -Tst_QuestionsOrder_t Tst_GetParamGblSelectedOrder (void); +void Tst_SetParamGblTest (const struct Tst_Test *TestSrc); +void Tst_GetParamGblTest (struct Tst_Test *TestDst); unsigned Tst_GetNumAnswersQst (long QstCod); -unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle); -void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question); -void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType); +void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, + bool Shuffle); +void Tst_GetCorrectAnswersFromDB (struct Tst_Question *Question); +void Tst_WriteAnswersEdit (struct Tst_Question *Question); bool Tst_CheckIfQuestionIsValidForGame (long QstCod); void Tst_WriteAnsTF (char AnsTF); void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. @@ -214,14 +215,13 @@ void Tst_ShowFormEditOneQst (void); void Tst_QstConstructor (struct Tst_Question *Question); void Tst_QstDestructor (struct Tst_Question *Question); -int Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt); +bool Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); void Tst_ReceiveQst (void); -bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question, - const struct Tst_Tags *Tags); +bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question); -bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question); +bool Tst_CheckIfQuestionExistsInDB (struct Tst_Question *Question); long Tst_GetIntAnsFromStr (char *Str); @@ -237,9 +237,7 @@ long Tst_GetParamGblQstCod (void); void Tst_PutParamGblQstCod (void); void Tst_PutParamQstCod (long QstCod); -long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, - struct Tst_Question *Question, - const struct Tst_Tags *Tags); +void Tst_InsertOrUpdateQstTagsAnsIntoDB (struct Tst_Question *Question); void Tst_RemoveCrsTests (long CrsCod); diff --git a/swad_test_import.c b/swad_test_import.c index f4f2fc71..6b7718e4 100644 --- a/swad_test_import.c +++ b/swad_test_import.c @@ -71,7 +71,7 @@ static void TsI_PutCreateXMLParam (void); static void TsI_ExportQuestion (long QstCod,FILE *FileXML); static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML); -static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, +static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, FILE *FileXML); static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML); static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer); @@ -81,7 +81,6 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem, static void TsI_WriteHeadingListImportedQst (void); static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, struct XMLElement *FeedbackElem, - const struct Tst_Tags *Tags, const struct Tst_Question *Question, bool QuestionExists); @@ -94,9 +93,7 @@ void TsI_PutFormToExportQuestions (const struct Tst_Test *Test) extern const char *Txt_Export_questions; /***** Put a link to create a file with questions *****/ - Tst_SetParamGblTags (&Test->Tags); - Tst_SetParamGblAnswerTypes (&Test->AnswerTypes); - Tst_SetParamGblSelectedOrder (Test->SelectedOrder); + Tst_SetParamGblTest (Test); Lay_PutContextualLinkIconText (ActLstTstQst,NULL,TsI_PutParamsExportQsts, "file-import.svg", Txt_Export_questions); @@ -108,11 +105,13 @@ void TsI_PutFormToExportQuestions (const struct Tst_Test *Test) static void TsI_PutParamsExportQsts (void) { + struct Tst_Test Test; + + Tst_GetParamGblTest (&Test); Dat_WriteParamsIniEndDates (); Tst_WriteParamEditQst (); Par_PutHiddenParamChar ("OnlyThisQst",'N'); - Par_PutHiddenParamUnsigned (NULL,"Order", - (unsigned) Tst_GetParamGblSelectedOrder ()); + Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Test.SelectedOrder); TsI_PutCreateXMLParam (); } @@ -250,7 +249,10 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML) extern const char *Txt_NEW_LINE; MYSQL_RES *mysql_res; MYSQL_ROW row; - Tst_AnswerType_t AnswerType; + struct Tst_Question Question; + + /***** Create test question *****/ + Tst_QstConstructor (&Question); if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) { @@ -269,9 +271,9 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML) */ /***** Write the answer type (row[1]) *****/ - AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); + Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); fprintf (FileXML,"%s", - Tst_StrAnswerTypesXML[AnswerType],Txt_NEW_LINE); + Tst_StrAnswerTypesXML[Question.Answer.Type],Txt_NEW_LINE); /***** Write the question tags *****/ fprintf (FileXML,"%s",Txt_NEW_LINE); @@ -291,19 +293,22 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML) /***** Write the answers of this question. Shuffle can be enabled or disabled (row[2]) *****/ fprintf (FileXML,""); - TsI_WriteAnswersOfAQstXML (QstCod,AnswerType,FileXML); + TsI_WriteAnswersOfAQstXML (&Question,FileXML); fprintf (FileXML,"%s",Txt_NEW_LINE); /***** End question *****/ fprintf (FileXML,"%s%s", Txt_NEW_LINE,Txt_NEW_LINE); } + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -337,21 +342,19 @@ static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML) /**************** Get and write the answers of a test question ***************/ /*****************************************************************************/ -static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, +static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, FILE *FileXML) { extern const char *Txt_NEW_LINE; - struct Tst_Question Question; unsigned NumOpt; unsigned i; MYSQL_RES *mysql_res; MYSQL_ROW row; double FloatNum[2]; - Question.Answer.Type = AnswerType; - /***** Get answers *****/ - Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct + Tst_GetAnswersQst (Question,&mysql_res, + false); // Don't shuffle /* row[0] AnsInd row[1] Answer @@ -361,16 +364,16 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, */ /***** Write answers *****/ - switch (Question.Answer.Type) + switch (Question->Answer.Type) { case Tst_ANS_INT: - Tst_CheckIfNumberOfAnswersIsOne (&Question); + Tst_CheckIfNumberOfAnswersIsOne (Question); row = mysql_fetch_row (mysql_res); fprintf (FileXML,"%ld", Tst_GetIntAnsFromStr (row[1])); break; case Tst_ANS_FLOAT: - if (Question.Answer.NumOptions != 2) + if (Question->Answer.NumOptions != 2) Lay_ShowErrorAndExit ("Wrong float range."); for (i = 0; @@ -388,7 +391,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, FloatNum[1],Txt_NEW_LINE); break; case Tst_ANS_TRUE_FALSE: - Tst_CheckIfNumberOfAnswersIsOne (&Question); + Tst_CheckIfNumberOfAnswersIsOne (Question); row = mysql_fetch_row (mysql_res); fprintf (FileXML,"%s", row[1][0] == 'T' ? "true" : @@ -399,7 +402,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, case Tst_ANS_TEXT: fprintf (FileXML,"%s",Txt_NEW_LINE); for (NumOpt = 0; - NumOpt < Question.Answer.NumOptions; + NumOpt < Question->Answer.NumOptions; NumOpt++) { row = mysql_fetch_row (mysql_res); @@ -408,7 +411,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, fprintf (FileXML,"Answer.Type != Tst_ANS_TEXT) fprintf (FileXML," correct=\"%s\"", (row[4][0] == 'Y') ? "yes" : "no"); @@ -541,10 +544,9 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) struct XMLElement *FeedbackElem; struct XMLElement *AnswerElem; struct XMLAttribute *Attribute; - struct Tst_Tags Tags; - bool AnswerTypeFound; - bool QuestionExists; struct Tst_Question Question; + bool QuestionExists; + bool AnswerTypeFound; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; @@ -605,22 +607,22 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) if (AnswerTypeFound) { /* Get tags */ - for (TagsElem = QuestionElem->FirstChild, Tags.Num = 0; + for (TagsElem = QuestionElem->FirstChild, Question.Tags.Num = 0; TagsElem != NULL; TagsElem = TagsElem->NextBrother) if (!strcmp (TagsElem->TagName,"tags")) { for (TagElem = TagsElem->FirstChild; - TagElem != NULL && Tags.Num < Tst_MAX_TAGS_PER_QUESTION; + TagElem != NULL && Question.Tags.Num < Tst_MAX_TAGS_PER_QUESTION; TagElem = TagElem->NextBrother) if (!strcmp (TagElem->TagName,"tag")) { if (TagElem->Content) { - Str_Copy (Tags.Txt[Tags.Num], + Str_Copy (Question.Tags.Txt[Question.Tags.Num], TagElem->Content, Tst_MAX_BYTES_TAG); - Tags.Num++; + Question.Tags.Num++; } } break; // Only first element "tags" @@ -691,19 +693,23 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) TsI_GetAnswerFromXML (AnswerElem,&Question); /* Make sure that tags, text and answer are not empty */ - if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Tags)) + if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question)) { /* Check if question already exists in database */ QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question); /* Write row with this imported question */ TsI_WriteRowImportedQst (StemElem,FeedbackElem, - &Tags,&Question,QuestionExists); + &Question,QuestionExists); /***** If a new question ==> insert question, tags and answer in the database *****/ if (!QuestionExists) - if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,&Tags) <= 0) + { + Question.QstCod = -1L; + Tst_InsertOrUpdateQstTagsAnsIntoDB (&Question); + if (Question.QstCod <= 0) Lay_ShowErrorAndExit ("Can not create question."); + } } } else // Answer type not found @@ -923,7 +929,6 @@ static void TsI_WriteHeadingListImportedQst (void) static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, struct XMLElement *FeedbackElem, - const struct Tst_Tags *Tags, const struct Tst_Question *Question, bool QuestionExists) { @@ -971,12 +976,12 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, /***** Write the question tags *****/ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - if (Tags->Num) + if (Question->Tags.Num) { /***** Write the tags *****/ HTM_TABLE_Begin (NULL); for (NumTag = 0; - NumTag < Tags->Num; + NumTag < Question->Tags.Num; NumTag++) { HTM_TR_Begin (NULL); @@ -986,7 +991,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, HTM_TD_End (); HTM_TD_Begin ("class=\"%s LT\"",ClassData); - HTM_Txt (Tags->Txt[NumTag]); + HTM_Txt (Question->Tags.Txt[NumTag]); HTM_TD_End (); HTM_TR_End ();