mirror of https://github.com/acanas/swad-core.git
Version19.149
This commit is contained in:
parent
11d934a3cc
commit
6e9aed2d76
|
@ -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.148.2 (2020-03-17)"
|
#define Log_PLATFORM_VERSION "SWAD 19.149 (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: 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)
|
||||||
Version 19.148.1: Mar 17, 2020 Code refactoring in tests. (282851 lines)
|
Version 19.148.1: Mar 17, 2020 Code refactoring in tests. (282851 lines)
|
||||||
|
|
|
@ -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;
|
||||||
|
struct Tst_Answer Answer;
|
||||||
unsigned QstInd;
|
unsigned QstInd;
|
||||||
unsigned MaxQstInd;
|
unsigned MaxQstInd;
|
||||||
char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
|
char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
|
||||||
|
@ -1908,7 +1909,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
|
||||||
row[1] QstCod
|
row[1] QstCod
|
||||||
*/
|
*/
|
||||||
/***** Create test question *****/
|
/***** Create test question *****/
|
||||||
Tst_QstConstructor (&Question);
|
Tst_QstConstructor (&Question,&Answer);
|
||||||
|
|
||||||
/* Get question index (row[0]) */
|
/* Get question index (row[0]) */
|
||||||
QstInd = Str_ConvertStrToUnsigned (row[0]);
|
QstInd = Str_ConvertStrToUnsigned (row[0]);
|
||||||
|
@ -1977,7 +1978,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
|
||||||
HTM_TR_End ();
|
HTM_TR_End ();
|
||||||
|
|
||||||
/***** Destroy test question *****/
|
/***** Destroy test question *****/
|
||||||
Tst_QstDestructor (&Question);
|
Tst_QstDestructor (&Question,&Answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** End table *****/
|
/***** End table *****/
|
||||||
|
|
|
@ -666,20 +666,6 @@ struct Globals
|
||||||
char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
|
char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
|
||||||
bool AllowTeachers; // Can teachers of this course see the test result?
|
bool AllowTeachers; // Can teachers of this course see the test result?
|
||||||
bool AllAnsTypes;
|
bool AllAnsTypes;
|
||||||
struct
|
|
||||||
{
|
|
||||||
unsigned NumOptions;
|
|
||||||
char TF;
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
bool Correct;
|
|
||||||
char *Text;
|
|
||||||
char *Feedback;
|
|
||||||
struct Media Media;
|
|
||||||
} Options[Tst_MAX_OPTIONS_PER_QUESTION];
|
|
||||||
long Integer;
|
|
||||||
double FloatingPoint[2];
|
|
||||||
} Answer;
|
|
||||||
char ListAnsTypes[Tst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
|
char ListAnsTypes[Tst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
|
||||||
Tst_QuestionsOrder_t SelectedOrder;
|
Tst_QuestionsOrder_t SelectedOrder;
|
||||||
} Test;
|
} Test;
|
||||||
|
|
|
@ -3786,6 +3786,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;
|
||||||
|
struct Tst_Answer Answer;
|
||||||
double ScoreThisQst;
|
double ScoreThisQst;
|
||||||
bool AnswerIsNotBlank;
|
bool AnswerIsNotBlank;
|
||||||
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
|
||||||
|
@ -3803,10 +3804,11 @@ static double Mch_ComputeScore (unsigned NumQsts)
|
||||||
Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr);
|
Tst_GetAnswersFromStr (Gbl.Test.StrAnswersOneQst[NumQst],AnswersUsr);
|
||||||
|
|
||||||
/***** Get correct answers of test question from database *****/
|
/***** Get correct answers of test question from database *****/
|
||||||
Tst_GetCorrectAnswersFromDB (Gbl.Test.QstCodes[NumQst]);
|
Tst_GetCorrectAnswersFromDB (Gbl.Test.QstCodes[NumQst],&Answer);
|
||||||
|
|
||||||
/***** Compute the total score of this question *****/
|
/***** Compute the total score of this question *****/
|
||||||
Tst_ComputeScoreQst (Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
|
Tst_ComputeScoreQst (&Answer,
|
||||||
|
Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
|
||||||
|
|
||||||
/***** Compute total score *****/
|
/***** Compute total score *****/
|
||||||
TotalScore += ScoreThisQst;
|
TotalScore += ScoreThisQst;
|
||||||
|
|
680
swad_test.c
680
swad_test.c
File diff suppressed because it is too large
Load Diff
41
swad_test.h
41
swad_test.h
|
@ -69,6 +69,21 @@ struct Tst_Question
|
||||||
bool Shuffle;
|
bool Shuffle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Tst_Answer
|
||||||
|
{
|
||||||
|
unsigned NumOptions;
|
||||||
|
char TF;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
bool Correct;
|
||||||
|
char *Text;
|
||||||
|
char *Feedback;
|
||||||
|
struct Media Media;
|
||||||
|
} Options[Tst_MAX_OPTIONS_PER_QUESTION];
|
||||||
|
long Integer;
|
||||||
|
double FloatingPoint[2];
|
||||||
|
};
|
||||||
|
|
||||||
#define Tst_NUM_OPTIONS_PLUGGABLE 3
|
#define Tst_NUM_OPTIONS_PLUGGABLE 3
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -163,21 +178,22 @@ bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res);
|
||||||
void Tst_WriteParamEditQst (void);
|
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);
|
void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Answer *Answer);
|
||||||
void Tst_WriteAnswersEdit (long QstCod);
|
void Tst_WriteAnswersEdit (long QstCod);
|
||||||
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);
|
void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Answer *Answer);
|
||||||
void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
|
void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
|
||||||
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 (unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION],
|
void Tst_ComputeScoreQst (const struct Tst_Answer *Answer,
|
||||||
|
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);
|
||||||
void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod,
|
void Tst_WriteChoiceAnsViewMatch (long MchCod,unsigned QstInd,long QstCod,
|
||||||
unsigned NumCols,const char *Class,bool ShowResult);
|
unsigned NumCols,const char *Class,bool ShowResult);
|
||||||
void Tst_CheckIfNumberOfAnswersIsOne (void);
|
void Tst_CheckIfNumberOfAnswersIsOne (const struct Tst_Answer *Answer);
|
||||||
|
|
||||||
unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res);
|
unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res);
|
||||||
void Tst_GetAndWriteTagsQst (long QstCod);
|
void Tst_GetAndWriteTagsQst (long QstCod);
|
||||||
|
@ -195,16 +211,20 @@ bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void);
|
||||||
void Tst_ReceiveConfigTst (void);
|
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,
|
||||||
void Tst_QstDestructor (struct Tst_Question *Question);
|
struct Tst_Answer *Answer);
|
||||||
|
void Tst_QstDestructor (struct Tst_Question *Question,
|
||||||
|
struct Tst_Answer *Answer);
|
||||||
|
|
||||||
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt);
|
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,
|
||||||
|
struct Tst_Answer *Answer);
|
||||||
|
|
||||||
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question);
|
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question,
|
||||||
|
const struct Tst_Answer *Answer);
|
||||||
|
|
||||||
long Tst_GetIntAnsFromStr (char *Str);
|
long Tst_GetIntAnsFromStr (char *Str);
|
||||||
|
|
||||||
|
@ -221,7 +241,8 @@ void Tst_PutParamGblQstCod (void);
|
||||||
void Tst_PutParamQstCod (long QstCod);
|
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,
|
||||||
|
struct Tst_Answer *Answer);
|
||||||
|
|
||||||
void Tst_RemoveCrsTests (long CrsCod);
|
void Tst_RemoveCrsTests (long CrsCod);
|
||||||
|
|
||||||
|
|
|
@ -75,11 +75,13 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,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,
|
||||||
|
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,
|
||||||
|
const struct Tst_Answer *Answer,
|
||||||
bool QuestionExists);
|
bool QuestionExists);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
@ -332,13 +334,15 @@ static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML)
|
||||||
static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
|
static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
|
||||||
{
|
{
|
||||||
extern const char *Txt_NEW_LINE;
|
extern const char *Txt_NEW_LINE;
|
||||||
|
struct Tst_Answer Answer;
|
||||||
unsigned NumOpt;
|
unsigned NumOpt;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
MYSQL_RES *mysql_res;
|
MYSQL_RES *mysql_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
double FloatNum[2];
|
double FloatNum[2];
|
||||||
|
|
||||||
Gbl.Test.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
|
/***** Get answers *****/
|
||||||
|
Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct
|
||||||
/*
|
/*
|
||||||
row[0] AnsInd
|
row[0] AnsInd
|
||||||
row[1] Answer
|
row[1] Answer
|
||||||
|
@ -346,17 +350,18 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
|
||||||
row[3] MedCod
|
row[3] MedCod
|
||||||
row[4] Correct
|
row[4] Correct
|
||||||
*/
|
*/
|
||||||
/***** Write the answers *****/
|
|
||||||
|
/***** Write answers *****/
|
||||||
switch (Gbl.Test.AnswerType)
|
switch (Gbl.Test.AnswerType)
|
||||||
{
|
{
|
||||||
case Tst_ANS_INT:
|
case Tst_ANS_INT:
|
||||||
Tst_CheckIfNumberOfAnswersIsOne ();
|
Tst_CheckIfNumberOfAnswersIsOne (&Answer);
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
fprintf (FileXML,"%ld",
|
fprintf (FileXML,"%ld",
|
||||||
Tst_GetIntAnsFromStr (row[1]));
|
Tst_GetIntAnsFromStr (row[1]));
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_FLOAT:
|
case Tst_ANS_FLOAT:
|
||||||
if (Gbl.Test.Answer.NumOptions != 2)
|
if (Answer.NumOptions != 2)
|
||||||
Lay_ShowErrorAndExit ("Wrong float range.");
|
Lay_ShowErrorAndExit ("Wrong float range.");
|
||||||
|
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
|
@ -374,7 +379,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
|
||||||
FloatNum[1],Txt_NEW_LINE);
|
FloatNum[1],Txt_NEW_LINE);
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_TRUE_FALSE:
|
case Tst_ANS_TRUE_FALSE:
|
||||||
Tst_CheckIfNumberOfAnswersIsOne ();
|
Tst_CheckIfNumberOfAnswersIsOne (&Answer);
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
fprintf (FileXML,"%s",
|
fprintf (FileXML,"%s",
|
||||||
row[1][0] == 'T' ? "true" :
|
row[1][0] == 'T' ? "true" :
|
||||||
|
@ -385,7 +390,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,FILE *FileXML)
|
||||||
case Tst_ANS_TEXT:
|
case Tst_ANS_TEXT:
|
||||||
fprintf (FileXML,"%s",Txt_NEW_LINE);
|
fprintf (FileXML,"%s",Txt_NEW_LINE);
|
||||||
for (NumOpt = 0;
|
for (NumOpt = 0;
|
||||||
NumOpt < Gbl.Test.Answer.NumOptions;
|
NumOpt < Answer.NumOptions;
|
||||||
NumOpt++)
|
NumOpt++)
|
||||||
{
|
{
|
||||||
row = mysql_fetch_row (mysql_res);
|
row = mysql_fetch_row (mysql_res);
|
||||||
|
@ -530,6 +535,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
|
||||||
bool AnswerTypeFound;
|
bool AnswerTypeFound;
|
||||||
bool QuestionExists;
|
bool QuestionExists;
|
||||||
struct Tst_Question Question;
|
struct Tst_Question Question;
|
||||||
|
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];
|
||||||
|
|
||||||
|
@ -573,7 +579,7 @@ 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);
|
Tst_QstConstructor (&Question,&Answer);
|
||||||
|
|
||||||
/* Get type of questions (in mandatory attribute "type") */
|
/* Get type of questions (in mandatory attribute "type") */
|
||||||
AnswerTypeFound = false;
|
AnswerTypeFound = false;
|
||||||
|
@ -673,25 +679,27 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get answer (mandatory) */
|
/* Get answer (mandatory) */
|
||||||
TsI_GetAnswerFromXML (AnswerElem);
|
TsI_GetAnswerFromXML (AnswerElem,&Answer);
|
||||||
|
|
||||||
/* Make sure that tags, text and answer are not empty */
|
/* Make sure that tags, text and answer are not empty */
|
||||||
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
|
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Answer))
|
||||||
{
|
{
|
||||||
/* Check if question already exists in database */
|
/* Check if question already exists in database */
|
||||||
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question);
|
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question,&Answer);
|
||||||
|
|
||||||
/* Write row with this imported question */
|
/* Write row with this imported question */
|
||||||
TsI_WriteRowImportedQst (StemElem,FeedbackElem,&Question,QuestionExists);
|
TsI_WriteRowImportedQst (StemElem,FeedbackElem,
|
||||||
|
&Question,&Answer,
|
||||||
|
QuestionExists);
|
||||||
|
|
||||||
/***** If a new question ==> insert question, tags and answer in the database *****/
|
/***** If a new question ==> insert question, tags and answer in the database *****/
|
||||||
if (!QuestionExists)
|
if (!QuestionExists)
|
||||||
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question) <= 0)
|
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,&Answer) <= 0)
|
||||||
Lay_ShowErrorAndExit ("Can not create question.");
|
Lay_ShowErrorAndExit ("Can not create question.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** Destroy test question *****/
|
/***** Destroy test question *****/
|
||||||
Tst_QstDestructor (&Question);
|
Tst_QstDestructor (&Question,&Answer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,7 +741,8 @@ 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,
|
||||||
|
struct Tst_Answer *Answer)
|
||||||
{
|
{
|
||||||
struct XMLElement *OptionElem;
|
struct XMLElement *OptionElem;
|
||||||
struct XMLElement *TextElem;
|
struct XMLElement *TextElem;
|
||||||
|
@ -745,19 +754,19 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
switch (Gbl.Test.AnswerType)
|
switch (Gbl.Test.AnswerType)
|
||||||
{
|
{
|
||||||
case Tst_ANS_INT:
|
case Tst_ANS_INT:
|
||||||
if (!Tst_AllocateTextChoiceAnswer (0))
|
if (!Tst_AllocateTextChoiceAnswer (Answer,0))
|
||||||
/* Abort on error */
|
/* Abort on error */
|
||||||
Ale_ShowAlertsAndExit ();
|
Ale_ShowAlertsAndExit ();
|
||||||
|
|
||||||
if (AnswerElem->Content)
|
if (AnswerElem->Content)
|
||||||
Str_Copy (Gbl.Test.Answer.Options[0].Text,AnswerElem->Content,
|
Str_Copy (Answer->Options[0].Text,AnswerElem->Content,
|
||||||
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_FLOAT:
|
case Tst_ANS_FLOAT:
|
||||||
if (!Tst_AllocateTextChoiceAnswer (0))
|
if (!Tst_AllocateTextChoiceAnswer (Answer,0))
|
||||||
/* Abort on error */
|
/* Abort on error */
|
||||||
Ale_ShowAlertsAndExit ();
|
Ale_ShowAlertsAndExit ();
|
||||||
if (!Tst_AllocateTextChoiceAnswer (1))
|
if (!Tst_AllocateTextChoiceAnswer (Answer,1))
|
||||||
/* Abort on error */
|
/* Abort on error */
|
||||||
Ale_ShowAlertsAndExit ();
|
Ale_ShowAlertsAndExit ();
|
||||||
|
|
||||||
|
@ -767,7 +776,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
if (!strcmp (LowerUpperElem->TagName,"lower"))
|
if (!strcmp (LowerUpperElem->TagName,"lower"))
|
||||||
{
|
{
|
||||||
if (LowerUpperElem->Content)
|
if (LowerUpperElem->Content)
|
||||||
Str_Copy (Gbl.Test.Answer.Options[0].Text,
|
Str_Copy (Answer->Options[0].Text,
|
||||||
LowerUpperElem->Content,
|
LowerUpperElem->Content,
|
||||||
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||||
break; // Only first element "lower"
|
break; // Only first element "lower"
|
||||||
|
@ -778,7 +787,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
if (!strcmp (LowerUpperElem->TagName,"upper"))
|
if (!strcmp (LowerUpperElem->TagName,"upper"))
|
||||||
{
|
{
|
||||||
if (LowerUpperElem->Content)
|
if (LowerUpperElem->Content)
|
||||||
Str_Copy (Gbl.Test.Answer.Options[1].Text,
|
Str_Copy (Answer->Options[1].Text,
|
||||||
LowerUpperElem->Content,
|
LowerUpperElem->Content,
|
||||||
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||||
break; // Only first element "upper"
|
break; // Only first element "upper"
|
||||||
|
@ -787,19 +796,19 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
case Tst_ANS_TRUE_FALSE:
|
case Tst_ANS_TRUE_FALSE:
|
||||||
// Comparisons must be case insensitive, because users can edit XML
|
// Comparisons must be case insensitive, because users can edit XML
|
||||||
if (!AnswerElem->Content)
|
if (!AnswerElem->Content)
|
||||||
Gbl.Test.Answer.TF = ' ';
|
Answer->TF = ' ';
|
||||||
else if (!strcasecmp (AnswerElem->Content,"true") ||
|
else if (!strcasecmp (AnswerElem->Content,"true") ||
|
||||||
!strcasecmp (AnswerElem->Content,"T") ||
|
!strcasecmp (AnswerElem->Content,"T") ||
|
||||||
!strcasecmp (AnswerElem->Content,"yes") ||
|
!strcasecmp (AnswerElem->Content,"yes") ||
|
||||||
!strcasecmp (AnswerElem->Content,"Y"))
|
!strcasecmp (AnswerElem->Content,"Y"))
|
||||||
Gbl.Test.Answer.TF = 'T';
|
Answer->TF = 'T';
|
||||||
else if (!strcasecmp (AnswerElem->Content,"false") ||
|
else if (!strcasecmp (AnswerElem->Content,"false") ||
|
||||||
!strcasecmp (AnswerElem->Content,"F") ||
|
!strcasecmp (AnswerElem->Content,"F") ||
|
||||||
!strcasecmp (AnswerElem->Content,"no") ||
|
!strcasecmp (AnswerElem->Content,"no") ||
|
||||||
!strcasecmp (AnswerElem->Content,"N"))
|
!strcasecmp (AnswerElem->Content,"N"))
|
||||||
Gbl.Test.Answer.TF = 'F';
|
Answer->TF = 'F';
|
||||||
else
|
else
|
||||||
Gbl.Test.Answer.TF = ' ';
|
Answer->TF = ' ';
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_UNIQUE_CHOICE:
|
case Tst_ANS_UNIQUE_CHOICE:
|
||||||
case Tst_ANS_MULTIPLE_CHOICE:
|
case Tst_ANS_MULTIPLE_CHOICE:
|
||||||
|
@ -810,7 +819,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
OptionElem = OptionElem->NextBrother, NumOpt++)
|
OptionElem = OptionElem->NextBrother, NumOpt++)
|
||||||
if (!strcmp (OptionElem->TagName,"option"))
|
if (!strcmp (OptionElem->TagName,"option"))
|
||||||
{
|
{
|
||||||
if (!Tst_AllocateTextChoiceAnswer (NumOpt))
|
if (!Tst_AllocateTextChoiceAnswer (Answer,NumOpt))
|
||||||
/* Abort on error */
|
/* Abort on error */
|
||||||
Ale_ShowAlertsAndExit ();
|
Ale_ShowAlertsAndExit ();
|
||||||
|
|
||||||
|
@ -821,13 +830,13 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
{
|
{
|
||||||
if (TextElem->Content)
|
if (TextElem->Content)
|
||||||
{
|
{
|
||||||
Str_Copy (Gbl.Test.Answer.Options[NumOpt].Text,
|
Str_Copy (Answer->Options[NumOpt].Text,
|
||||||
TextElem->Content,
|
TextElem->Content,
|
||||||
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||||
|
|
||||||
/* Convert answer from text to HTML (in database answer text is stored in HTML) */
|
/* Convert answer from text to HTML (in database answer text is stored in HTML) */
|
||||||
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
|
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
|
||||||
Gbl.Test.Answer.Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,true);
|
Answer->Options[NumOpt].Text,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,true);
|
||||||
}
|
}
|
||||||
break; // Only first element "text"
|
break; // Only first element "text"
|
||||||
}
|
}
|
||||||
|
@ -839,19 +848,19 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
{
|
{
|
||||||
if (FeedbackElem->Content)
|
if (FeedbackElem->Content)
|
||||||
{
|
{
|
||||||
Str_Copy (Gbl.Test.Answer.Options[NumOpt].Feedback,
|
Str_Copy (Answer->Options[NumOpt].Feedback,
|
||||||
FeedbackElem->Content,
|
FeedbackElem->Content,
|
||||||
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
Tst_MAX_BYTES_ANSWER_OR_FEEDBACK);
|
||||||
|
|
||||||
/* Convert feedback from text to HTML (in database answer feedback is stored in HTML) */
|
/* Convert feedback from text to HTML (in database answer feedback is stored in HTML) */
|
||||||
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
|
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
|
||||||
Gbl.Test.Answer.Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,true);
|
Answer->Options[NumOpt].Feedback,Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,true);
|
||||||
}
|
}
|
||||||
break; // Only first element "feedback"
|
break; // Only first element "feedback"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Gbl.Test.AnswerType == Tst_ANS_TEXT)
|
if (Gbl.Test.AnswerType == Tst_ANS_TEXT)
|
||||||
Gbl.Test.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 */
|
||||||
for (Attribute = OptionElem->FirstAttribute;
|
for (Attribute = OptionElem->FirstAttribute;
|
||||||
|
@ -859,7 +868,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem)
|
||||||
Attribute = Attribute->Next)
|
Attribute = Attribute->Next)
|
||||||
if (!strcmp (Attribute->AttributeName,"correct"))
|
if (!strcmp (Attribute->AttributeName,"correct"))
|
||||||
{
|
{
|
||||||
Gbl.Test.Answer.Options[NumOpt].Correct = XML_GetAttributteYesNoFromXMLTree (Attribute);
|
Answer->Options[NumOpt].Correct = XML_GetAttributteYesNoFromXMLTree (Attribute);
|
||||||
break; // Only first attribute "correct"
|
break; // Only first attribute "correct"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -902,6 +911,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,
|
||||||
|
const struct Tst_Answer *Answer,
|
||||||
bool QuestionExists)
|
bool QuestionExists)
|
||||||
{
|
{
|
||||||
extern const char *Txt_Existing_question;
|
extern const char *Txt_Existing_question;
|
||||||
|
@ -1004,22 +1014,22 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
|
||||||
{
|
{
|
||||||
case Tst_ANS_INT:
|
case Tst_ANS_INT:
|
||||||
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
||||||
HTM_TxtF ("(%ld)",Gbl.Test.Answer.Integer);
|
HTM_TxtF ("(%ld)",Answer->Integer);
|
||||||
HTM_SPAN_End ();
|
HTM_SPAN_End ();
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_FLOAT:
|
case Tst_ANS_FLOAT:
|
||||||
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
||||||
HTM_Txt ("([");
|
HTM_Txt ("([");
|
||||||
HTM_Double (Gbl.Test.Answer.FloatingPoint[0]);
|
HTM_Double (Answer->FloatingPoint[0]);
|
||||||
HTM_Txt ("; ");
|
HTM_Txt ("; ");
|
||||||
HTM_Double (Gbl.Test.Answer.FloatingPoint[1]);
|
HTM_Double (Answer->FloatingPoint[1]);
|
||||||
HTM_Txt ("])");
|
HTM_Txt ("])");
|
||||||
HTM_SPAN_End ();
|
HTM_SPAN_End ();
|
||||||
break;
|
break;
|
||||||
case Tst_ANS_TRUE_FALSE:
|
case Tst_ANS_TRUE_FALSE:
|
||||||
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
HTM_SPAN_Begin ("class=\"%s\"",ClassStem);
|
||||||
HTM_Txt ("(");
|
HTM_Txt ("(");
|
||||||
Tst_WriteAnsTF (Gbl.Test.Answer.TF);
|
Tst_WriteAnsTF (Answer->TF);
|
||||||
HTM_Txt (")");
|
HTM_Txt (")");
|
||||||
HTM_SPAN_End ();
|
HTM_SPAN_End ();
|
||||||
break;
|
break;
|
||||||
|
@ -1028,15 +1038,15 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
|
||||||
case Tst_ANS_TEXT:
|
case Tst_ANS_TEXT:
|
||||||
HTM_TABLE_Begin (NULL);
|
HTM_TABLE_Begin (NULL);
|
||||||
for (NumOpt = 0;
|
for (NumOpt = 0;
|
||||||
NumOpt < Gbl.Test.Answer.NumOptions;
|
NumOpt < Answer->NumOptions;
|
||||||
NumOpt++)
|
NumOpt++)
|
||||||
{
|
{
|
||||||
/* Convert the answer, that is in HTML, to rigorous HTML */
|
/* Convert the answer, that is in HTML, to rigorous HTML */
|
||||||
AnswerTextLength = strlen (Gbl.Test.Answer.Options[NumOpt].Text) *
|
AnswerTextLength = strlen (Answer->Options[NumOpt].Text) *
|
||||||
Str_MAX_BYTES_PER_CHAR;
|
Str_MAX_BYTES_PER_CHAR;
|
||||||
if ((AnswerText = (char *) malloc (AnswerTextLength + 1)) == NULL)
|
if ((AnswerText = (char *) malloc (AnswerTextLength + 1)) == NULL)
|
||||||
Lay_NotEnoughMemoryExit ();
|
Lay_NotEnoughMemoryExit ();
|
||||||
Str_Copy (AnswerText,Gbl.Test.Answer.Options[NumOpt].Text,
|
Str_Copy (AnswerText,Answer->Options[NumOpt].Text,
|
||||||
AnswerTextLength);
|
AnswerTextLength);
|
||||||
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
|
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
|
||||||
AnswerText,AnswerTextLength,false);
|
AnswerText,AnswerTextLength,false);
|
||||||
|
@ -1044,15 +1054,15 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
|
||||||
/* Convert the feedback, that is in HTML, to rigorous HTML */
|
/* Convert the feedback, that is in HTML, to rigorous HTML */
|
||||||
AnswerFeedbackLength = 0;
|
AnswerFeedbackLength = 0;
|
||||||
AnswerFeedback = NULL;
|
AnswerFeedback = NULL;
|
||||||
if (Gbl.Test.Answer.Options[NumOpt].Feedback)
|
if (Answer->Options[NumOpt].Feedback)
|
||||||
if (Gbl.Test.Answer.Options[NumOpt].Feedback[0])
|
if (Answer->Options[NumOpt].Feedback[0])
|
||||||
{
|
{
|
||||||
AnswerFeedbackLength = strlen (Gbl.Test.Answer.Options[NumOpt].Feedback) *
|
AnswerFeedbackLength = strlen (Answer->Options[NumOpt].Feedback) *
|
||||||
Str_MAX_BYTES_PER_CHAR;
|
Str_MAX_BYTES_PER_CHAR;
|
||||||
if ((AnswerFeedback = (char *) malloc (AnswerFeedbackLength + 1)) == NULL)
|
if ((AnswerFeedback = (char *) malloc (AnswerFeedbackLength + 1)) == NULL)
|
||||||
Lay_NotEnoughMemoryExit ();
|
Lay_NotEnoughMemoryExit ();
|
||||||
Str_Copy (AnswerFeedback,
|
Str_Copy (AnswerFeedback,
|
||||||
Gbl.Test.Answer.Options[NumOpt].Feedback,
|
Answer->Options[NumOpt].Feedback,
|
||||||
AnswerFeedbackLength);
|
AnswerFeedbackLength);
|
||||||
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
|
Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML,
|
||||||
AnswerFeedback,AnswerFeedbackLength,false);
|
AnswerFeedback,AnswerFeedbackLength,false);
|
||||||
|
@ -1062,7 +1072,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
|
||||||
|
|
||||||
/* Put an icon that indicates whether the answer is correct or wrong */
|
/* Put an icon that indicates whether the answer is correct or wrong */
|
||||||
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
|
HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
|
||||||
if (Gbl.Test.Answer.Options[NumOpt].Correct)
|
if (Answer->Options[NumOpt].Correct)
|
||||||
Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,
|
Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,
|
||||||
QuestionExists ? "ICO_HIDDEN CONTEXT_ICO_16x16" :
|
QuestionExists ? "ICO_HIDDEN CONTEXT_ICO_16x16" :
|
||||||
"CONTEXT_ICO_16x16");
|
"CONTEXT_ICO_16x16");
|
||||||
|
|
Loading…
Reference in New Issue