Version19.149

This commit is contained in:
acanas 2020-03-18 01:57:08 +01:00
parent 11d934a3cc
commit 6e9aed2d76
7 changed files with 481 additions and 366 deletions

View File

@ -497,7 +497,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.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)

View File

@ -1875,6 +1875,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
MYSQL_ROW row; MYSQL_ROW row;
long QstCod; long QstCod;
struct Tst_Question Question; struct Tst_Question Question;
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 *****/

View File

@ -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;

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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);

View File

@ -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");