diff --git a/Makefile b/Makefile
index de6eb94f..fd9f9cf6 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \
swad_database.o swad_date.o swad_degree.o swad_degree_config.o \
swad_degree_type.o swad_department.o swad_duplicate.o \
swad_enrolment.o swad_exam.o swad_exam_announcement.o \
- swad_exam_event.o swad_exam_result.o \
+ swad_exam_event.o swad_exam_result.o swad_exam_set.o \
swad_figure.o swad_figure_cache.o swad_file.o swad_file_browser.o \
swad_file_extension.o swad_file_MIME.o swad_firewall.o swad_follow.o \
swad_form.o swad_forum.o \
diff --git a/swad_action.c b/swad_action.c
index 9fd63b30..d3ce9f21 100644
--- a/swad_action.c
+++ b/swad_action.c
@@ -50,6 +50,7 @@
#include "swad_exam_announcement.h"
#include "swad_exam_event.h"
#include "swad_exam_result.h"
+#include "swad_exam_set.h"
#include "swad_enrolment.h"
#include "swad_figure.h"
#include "swad_follow.h"
diff --git a/swad_changelog.h b/swad_changelog.h
index 4cfa6e9e..167b2200 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -548,10 +548,11 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
-#define Log_PLATFORM_VERSION "SWAD 19.214.1 (2020-05-07)"
+#define Log_PLATFORM_VERSION "SWAD 19.215 (2020-05-07)"
#define CSS_FILE "swad19.193.1.css"
#define JS_FILE "swad19.193.1.js"
/*
+ Version 19.215: May 07, 2020 New module exam_set for set of questions. (301695 lines)
Version 19.214.1: May 07, 2020 Change color of dates on current exam event. (301597 lines)
Version 19.214: May 06, 2020 New API function getLocations. (301568 lines)
1 change necessary in database:
diff --git a/swad_exam.c b/swad_exam.c
index 7410a327..6f9c6730 100644
--- a/swad_exam.c
+++ b/swad_exam.c
@@ -38,6 +38,7 @@
#include "swad_exam.h"
#include "swad_exam_event.h"
#include "swad_exam_result.h"
+#include "swad_exam_set.h"
#include "swad_exam_type.h"
#include "swad_figure.h"
#include "swad_form.h"
@@ -65,9 +66,6 @@ extern struct Globals Gbl;
#define Exa_MAX_ANSWERS_PER_QUESTION 10
-#define ExaSet_MAX_SELECTED_QUESTIONS 10000
-#define ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS (ExaSet_MAX_SELECTED_QUESTIONS * (Cns_MAX_DECIMAL_DIGITS_LONG + 1))
-
/* Score range [0...max.score]
will be converted to
grade range [0...max.grade]
@@ -113,7 +111,6 @@ extern struct Globals Gbl;
/*****************************************************************************/
static void Exa_ListAllExams (struct Exa_Exams *Exams);
-static bool Exa_CheckIfICanEditExams (void);
static void Exa_PutIconsListExams (void *Exams);
static void Exa_PutIconToCreateNewExam (struct Exa_Exams *Exams);
static void Exa_PutButtonToCreateNewExam (struct Exa_Exams *Exams);
@@ -131,93 +128,20 @@ static void Exa_PutIconsToRemEditOneExam (struct Exa_Exams *Exams,
const struct Exa_Exam *Exam,
const char *Anchor);
-static void ExaSet_PutParamsOneQst (void *Exams);
static void Exa_PutHiddenParamOrder (Exa_Order_t SelectedOrder);
static Exa_Order_t Exa_GetParamOrder (void);
-static unsigned ExaSet_GetNumQstsInSet (long SetCod);
-
-static void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]);
-
static void Exa_RemoveExamFromAllTables (long ExaCod);
-static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set,
- const char Title[ExaSet_MAX_BYTES_TITLE + 1]);
static bool Exa_CheckIfSimilarExamExists (const struct Exa_Exam *Exam);
-static void Exa_PutFormsOneExam (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set,
- bool ItsANewExam);
-
-static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set,
- unsigned MaxSetInd);
-static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set);
-static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set,
- const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]);
-
-static void Exa_PutFormEditionExam (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- char Txt[Cns_MAX_BYTES_TEXT + 1],
- bool ItsANewExam);
static void Exa_ReceiveExamFieldsFromForm (struct Exa_Exam *Exam,
char Txt[Cns_MAX_BYTES_TEXT + 1]);
static bool Exa_CheckExamFieldsReceivedFromForm (const struct Exa_Exam *Exam);
-static void ExaSet_CreateSet (struct ExaSet_Set *Set);
-static void ExaSet_UpdateSet (const struct ExaSet_Set *Set);
-static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set,
- const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]);
-static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set,
- unsigned NumQstsToExam);
-
static void Exa_CreateExam (struct Exa_Exam *Exam,const char *Txt);
static void Exa_UpdateExam (struct Exa_Exam *Exam,const char *Txt);
-static void ExaSet_PutParamSetCod (long SetCod);
-
-static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod);
-static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd);
-
-static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod);
-
-static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd);
-static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd);
-
-static void ExaSet_ListExamSets (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set);
-static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams,
- const struct Exa_Exam *Exam,
- const struct ExaSet_Set *Set);
-static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams,
- const struct Exa_Exam *Exam,
- unsigned MaxSetInd,
- unsigned NumSets,
- MYSQL_RES *mysql_res,
- bool ICanEditSets);
-static void ExaSet_PutTableHeadingForSets (void);
-
-static void ExaSet_ResetSet (struct ExaSet_Set *Set);
-// static void Exa_PutParamSetCod (void *SetCod);
-static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams,
- unsigned NumQsts,
- MYSQL_RES *mysql_res,
- bool ICanEditQuestions);
-
-static void Exa_PutIconToAddNewQuestions (void *Exams);
-static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams);
-
-static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams);
-static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams);
-
-static void ExaSet_ExchangeSets (long ExaCod,
- unsigned SetIndTop,unsigned SetIndBottom);
-
-static bool Exa_CheckIfEditable (const struct Exa_Exam *Exam);
-
/*****************************************************************************/
/******************************* Reset exams *********************************/
/*****************************************************************************/
@@ -392,7 +316,7 @@ static void Exa_ListAllExams (struct Exa_Exams *Exams)
/************************ Check if I can edit exams **************************/
/*****************************************************************************/
-static bool Exa_CheckIfICanEditExams (void)
+bool Exa_CheckIfICanEditExams (void)
{
switch (Gbl.Usrs.Me.Role.Logged)
{
@@ -784,29 +708,6 @@ static void Exa_PutIconsToRemEditOneExam (struct Exa_Exams *Exams,
Exa_PutParams,Exams);
}
-/*****************************************************************************/
-/************ Put parameter to move/remove one set of questions **************/
-/*****************************************************************************/
-
-void ExaSet_PutParamsOneSet (void *Exams)
- {
- if (Exams)
- {
- Exa_PutParams (Exams);
- ExaSet_PutParamSetCod (((struct Exa_Exams *) Exams)->SetCod);
- }
- }
-
-/*****************************************************************************/
-/**************** Put parameter to move/remove one question ******************/
-/*****************************************************************************/
-
-static void ExaSet_PutParamsOneQst (void *Exams)
- {
- ExaSet_PutParamsOneSet (Exams);
- Tst_PutParamQstCod (&(((struct Exa_Exams *) Exams)->QstCod));
- }
-
/*****************************************************************************/
/*********************** Params used to edit an exam **************************/
/*****************************************************************************/
@@ -845,16 +746,6 @@ long Exa_GetParamExamCod (void)
return Par_GetParToLong ("ExaCod");
}
-/*****************************************************************************/
-/********************** Get parameter with code of set ***********************/
-/*****************************************************************************/
-
-long ExaSet_GetParamSetCod (void)
- {
- /***** Get code of set *****/
- return Par_GetParToLong ("SetCod");
- }
-
/*****************************************************************************/
/******************* Get parameters used to edit an exam **********************/
/*****************************************************************************/
@@ -1043,81 +934,6 @@ void Exa_GetListSelectedExaCods (struct Exa_Exams *Exams)
}
}
-/*****************************************************************************/
-/********************* Get number of questions in a set **********************/
-/*****************************************************************************/
-
-static unsigned ExaSet_GetNumQstsInSet (long SetCod)
- {
- /***** Get number of questions in set from database *****/
- return
- (unsigned) DB_QueryCOUNT ("can not get number of questions in a set",
- "SELECT COUNT(*) FROM exa_questions"
- " WHERE SetCod=%ld",
- SetCod);
- }
-
-/*****************************************************************************/
-/*********************** Get set data using its code *************************/
-/*****************************************************************************/
-
-void ExaSet_GetDataOfSetByCod (struct ExaSet_Set *Set)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
-
- /***** Trivial check *****/
- if (Set->SetCod <= 0)
- {
- /* Initialize to empty set */
- ExaSet_ResetSet (Set);
- return;
- }
-
- /***** Get data of set of questions from database *****/
- if (DB_QuerySELECT (&mysql_res,"can not get set data",
- "SELECT SetCod," // row[0]
- "SetInd," // row[1]
- "NumQstsToExam," // row[2]
- "Title" // row[3]
- " FROM exa_sets"
- " WHERE SetCod=%ld"
- " AND ExaCod=%ld", // Extra check
- Set->SetCod,Set->ExaCod)) // Set found...
- {
- /* Get row */
- row = mysql_fetch_row (mysql_res);
- /*
- row[0] SetCod
- row[1] SetInd
- row[2] NumQstsToExam
- row[3] Title
- */
- /* Get set code (row[0]) */
- Set->SetCod = Str_ConvertStrCodToLongCod (row[0]);
-
- /* Get set index (row[1]) */
- Set->SetInd = Str_ConvertStrToUnsigned (row[1]);
- snprintf (StrSetInd,sizeof (Set->SetInd),
- "%u",
- Set->SetInd);
-
- /* Get set index (row[2]) */
- Set->NumQstsToExam = Str_ConvertStrToUnsigned (row[2]);
-
- /* Get the title of the set (row[3]) */
- Str_Copy (Set->Title,row[3],
- ExaSet_MAX_BYTES_TITLE);
- }
- else
- /* Initialize to empty set */
- ExaSet_ResetSet (Set);
-
- /* Free structure that stores the query result */
- DB_FreeMySQLResult (&mysql_res);
- }
-
/*****************************************************************************/
/********************** Get exam data using its code *************************/
/*****************************************************************************/
@@ -1249,7 +1065,7 @@ void Exa_FreeListExams (struct Exa_Exams *Exams)
/********************** Get exam text from database ************************/
/*****************************************************************************/
-static void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1])
+void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1])
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
@@ -1472,25 +1288,6 @@ void Exa_UnhideExam (void)
Exa_ListAllExams (&Exams);
}
-/*****************************************************************************/
-/************** Check if the title of a set of questions exists **************/
-/*****************************************************************************/
-
-static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set,
- const char Title[ExaSet_MAX_BYTES_TITLE + 1])
- {
- /***** Get number of set of questions with a field value from database *****/
- return (DB_QueryCOUNT ("can not get similar sets of questions",
- "SELECT COUNT(*) FROM exa_sets,exa_exams"
- " WHERE exa_sets.ExaCod=%ld AND exa_sets.Title='%s'"
- " AND exa_sets.SetCod<>%ld"
- " AND exa_sets.ExaCod=exa_exams.ExaCod"
- " AND exa_exams.CrsCod=%ld", // Extra check
- Set->ExaCod,Title,
- Set->SetCod,
- Gbl.Hierarchy.Crs.CrsCod) != 0);
- }
-
/*****************************************************************************/
/******************* Check if the title of an exam exists *******************/
/*****************************************************************************/
@@ -1550,10 +1347,10 @@ void Exa_RequestCreatOrEditExam (void)
/******************** Put forms to create/edit an exam ***********************/
/*****************************************************************************/
-static void Exa_PutFormsOneExam (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set,
- bool ItsANewExam)
+void Exa_PutFormsOneExam (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set,
+ bool ItsANewExam)
{
char Txt[Cns_MAX_BYTES_TEXT + 1];
@@ -1579,283 +1376,10 @@ static void Exa_PutFormsOneExam (struct Exa_Exams *Exams,
/********************* Put a form to create/edit an exam **********************/
/*****************************************************************************/
-static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set,
- unsigned MaxSetInd)
- {
- // extern const char *Hlp_ASSESSMENT_Exams_new_set;
- // extern const char *Hlp_ASSESSMENT_Exams_edit_set;
- extern const char *Txt_New_set_of_questions;
- extern const char *Txt_Create_set_of_questions;
-
- /***** Begin form *****/
- Exams->ExaCod = Exam->ExaCod;
- Frm_StartForm (ActNewExaSet);
- Exa_PutParams (Exams);
-
- /***** Begin box and table *****/
- Box_BoxTableBegin (NULL,Txt_New_set_of_questions,
- NULL,NULL,
- NULL,Box_NOT_CLOSABLE,2);
-
- /***** Table heading *****/
- ExaSet_PutTableHeadingForSets ();
-
- /***** Begin row *****/
- HTM_TR_Begin (NULL);
-
- /***** Empty column for buttons *****/
- HTM_TD_Begin ("class=\"BM\"");
- HTM_TD_End ();
-
- /***** Index *****/
- HTM_TD_Begin ("class=\"RM\"");
- Tst_WriteNumQst (MaxSetInd + 1);
- HTM_TD_End ();
-
- /***** Title *****/
- HTM_TD_Begin ("class=\"LM\"");
- HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set->Title,
- HTM_DONT_SUBMIT_ON_CHANGE,
- "id=\"Title\" required=\"required\""
- " class=\"TITLE_DESCRIPTION_WIDTH\"");
- HTM_TD_End ();
-
- /***** Current number of questions in set *****/
- HTM_TD_Begin ("class=\"RM\"");
- HTM_Unsigned (0); // New set ==> no questions yet
- HTM_TD_End ();
-
- /***** Number of questions to appear in the exam *****/
- HTM_TD_Begin ("class=\"RM\"");
- HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set->NumQstsToExam,
- HTM_DONT_SUBMIT_ON_CHANGE,false,
- "class=\"INPUT_LONG\" required=\"required\"");
- HTM_TD_End ();
-
- /***** End row *****/
- HTM_TR_End ();
-
- /***** End table, send button and end box *****/
- Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_set_of_questions);
-
- /***** End form *****/
- Frm_EndForm ();
- }
-
-/*****************************************************************************/
-/**************** Receive form to create a new set of questions **************/
-/*****************************************************************************/
-
-void ExaSet_ReceiveFormSet (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- bool ItsANewSet;
-
- /***** Check if I can edit exams *****/
- if (!Exa_CheckIfICanEditExams ())
- Lay_NoPermissionExit ();
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- ItsANewSet = (Set.SetCod <= 0);
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
-
- /***** If I can edit exams ==> receive set from form *****/
- ExaSet_ReceiveSetFieldsFromForm (&Set);
- if (ExaSet_CheckSetTitleReceivedFromForm (&Set,Set.Title))
- {
- /***** Create a new exam or update an existing one *****/
- if (ItsANewSet)
- ExaSet_CreateSet (&Set); // Add new set to database
- else
- ExaSet_UpdateSet (&Set); // Update set data in database
- }
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set)
- {
- /***** Get set title *****/
- Par_GetParToText ("Title",Set->Title,ExaSet_MAX_BYTES_TITLE);
-
- /***** Get number of questions in set to appear in exam *****/
- Set->NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam",
- 0,
- UINT_MAX,
- 0);
- }
-
-static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set,
- const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1])
- {
- extern const char *Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X;
- extern const char *Txt_You_must_specify_the_title_of_the_set_of_questions;
- bool NewTitleIsCorrect;
-
- /***** Check if title is correct *****/
- NewTitleIsCorrect = true;
- if (NewTitle[0]) // If there's an set title
- {
- /***** Check if old and new titles are the same
- (this happens when return is pressed without changes) *****/
- if (strcmp (Set->Title,NewTitle)) // Different titles
- {
- /* If title of set was in database... */
- if (ExaSet_CheckIfSimilarSetExists (Set,NewTitle))
- {
- NewTitleIsCorrect = false;
- Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X,
- Set->Title);
- }
- }
- }
- else // If there is not a set title
- {
- NewTitleIsCorrect = false;
- Ale_ShowAlert (Ale_WARNING,Txt_You_must_specify_the_title_of_the_set_of_questions);
- }
-
- return NewTitleIsCorrect;
- }
-
-/*****************************************************************************/
-/************* Receive form to change title of set of questions **************/
-/*****************************************************************************/
-
-void ExaSet_ChangeSetTitle (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- char NewTitle[ExaSet_MAX_BYTES_TITLE + 1];
-
- /***** Check if I can edit exams *****/
- if (!Exa_CheckIfICanEditExams ())
- Lay_NoPermissionExit ();
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
- Exams.SetCod = Set.SetCod;
-
- /***** Get exam and set data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Receive new title from form *****/
- Par_GetParToText ("Title",NewTitle,ExaSet_MAX_BYTES_TITLE);
-
- /***** Check if title should be changed *****/
- if (ExaSet_CheckSetTitleReceivedFromForm (&Set,NewTitle))
- {
- /* Update the table changing old title by new title */
- ExaSet_UpdateSetTitleDB (&Set,NewTitle);
-
- /* Update title */
- Str_Copy (Set.Title,NewTitle,
- ExaSet_MAX_BYTES_TITLE);
- }
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-/*****************************************************************************/
-/***** Receive form to change number of questions to appear in the exam ******/
-/*****************************************************************************/
-
-void ExaSet_ChangeNumQstsToExam (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- unsigned NumQstsToExam;
-
- /***** Check if I can edit exams *****/
- if (!Exa_CheckIfICanEditExams ())
- Lay_NoPermissionExit ();
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
- Exams.SetCod = Set.SetCod;
-
- /***** Get exam and set data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get number of questions in set to appear in exam *****/
- NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam",
- 0,
- UINT_MAX,
- 0);
-
- /***** Check if title should be changed *****/
- if (NumQstsToExam != Set.NumQstsToExam)
- {
- /* Update the table changing old number by new number */
- ExaSet_UpdateNumQstsToExamDB (&Set,NumQstsToExam);
-
- /* Update title */
- Set.NumQstsToExam = NumQstsToExam;
- }
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/********************* Put a form to create/edit an exam **********************/
-/*****************************************************************************/
-
-static void Exa_PutFormEditionExam (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- char Txt[Cns_MAX_BYTES_TEXT + 1],
- bool ItsANewExam)
+void Exa_PutFormEditionExam (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ char Txt[Cns_MAX_BYTES_TEXT + 1],
+ bool ItsANewExam)
{
extern const char *Hlp_ASSESSMENT_Exams_new_exam;
extern const char *Hlp_ASSESSMENT_Exams_edit_exam;
@@ -2059,93 +1583,6 @@ static bool Exa_CheckExamFieldsReceivedFromForm (const struct Exa_Exam *Exam)
return NewExamIsCorrect;
}
-/*****************************************************************************/
-/********************** Create a new set of questions ************************/
-/*****************************************************************************/
-
-static void ExaSet_CreateSet (struct ExaSet_Set *Set)
- {
- extern const char *Txt_Created_new_set_of_questions_X;
- unsigned MaxSetInd;
-
- /***** Get maximum set index *****/
- MaxSetInd = ExaSet_GetMaxSetIndexInExam (Set->ExaCod);
-
- /***** Create a new exam *****/
- Set->SetCod =
- DB_QueryINSERTandReturnCode ("can not create new set of questions",
- "INSERT INTO exa_sets"
- " (ExaCod,SetInd,NumQstsToExam,Title)"
- " VALUES"
- " (%ld,%u,%u,'%s')",
- Set->ExaCod,
- MaxSetInd + 1,
- Set->NumQstsToExam,
- Set->Title);
-
- /***** Write success message *****/
- Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_set_of_questions_X,
- Set->Title);
- }
-
-/*****************************************************************************/
-/******************** Update an existing set of questions ********************/
-/*****************************************************************************/
-
-static void ExaSet_UpdateSet (const struct ExaSet_Set *Set)
- {
- extern const char *Txt_The_set_of_questions_has_been_modified;
-
- /***** Update the data of the set of questions *****/
- DB_QueryUPDATE ("can not update set of questions",
- "UPDATE exa_sets"
- " SET ExaCod=%ld,"
- "SetInd=%u,"
- "NumQstsToExam=%u,"
- "Title='%s'"
- " WHERE SetCod=%ld",
- Set->ExaCod,
- Set->SetInd,
- Set->NumQstsToExam,
- Set->Title,
- Set->SetCod);
-
- /***** Write success message *****/
- Ale_ShowAlert (Ale_SUCCESS,Txt_The_set_of_questions_has_been_modified);
- }
-
-/*****************************************************************************/
-/************************ Update set title in database ***********************/
-/*****************************************************************************/
-
-static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set,
- const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1])
- {
- /***** Update set of questions changing old title by new title *****/
- DB_QueryUPDATE ("can not update the title of a set of questions",
- "UPDATE exa_sets SET Title='%s'"
- " WHERE SetCod=%ld"
- " AND ExaCod=%ld", // Extra check
- NewTitle,
- Set->SetCod,Set->ExaCod);
- }
-
-/*****************************************************************************/
-/********* Update number of questions to appear in exam in database **********/
-/*****************************************************************************/
-
-static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set,
- unsigned NumQstsToExam)
- {
- /***** Update set of questions changing old number by new number *****/
- DB_QueryUPDATE ("can not update the number of questions to appear in exam",
- "UPDATE exa_sets SET NumQstsToExam=%u"
- " WHERE SetCod=%ld"
- " AND ExaCod=%ld", // Extra check
- NumQstsToExam,
- Set->SetCod,Set->ExaCod);
- }
-
/*****************************************************************************/
/**************************** Create a new exam ******************************/
/*****************************************************************************/
@@ -2205,207 +1642,6 @@ static void Exa_UpdateExam (struct Exa_Exam *Exam,const char *Txt)
Ale_ShowAlert (Ale_SUCCESS,Txt_The_exam_has_been_modified);
}
-/*****************************************************************************/
-/******************* Get number of questions of an exam *********************/
-/*****************************************************************************/
-
-unsigned ExaSet_GetNumSetsExam (long ExaCod)
- {
- /***** Get number of sets in an exam from database *****/
- return
- (unsigned) DB_QueryCOUNT ("can not get number of sets in an exam",
- "SELECT COUNT(*) FROM exa_sets"
- " WHERE ExaCod=%ld",
- ExaCod);
- }
-
-/*****************************************************************************/
-/******************* Get number of questions of an exam *********************/
-/*****************************************************************************/
-
-unsigned ExaSet_GetNumQstsExam (long ExaCod)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned NumQsts = 0;
-
- /***** Get total number of questions to appear in exam *****/
- if (!DB_QuerySELECT (&mysql_res,"can not get number of questions in an exam",
- "SELECT SUM(NumQstsToExam) FROM exa_sets"
- " WHERE ExaCod=%ld",
- ExaCod))
- Lay_ShowErrorAndExit ("Error: wrong question index.");
-
- /***** Get number of questions (row[0]) *****/
- row = mysql_fetch_row (mysql_res);
- if (row[0])
- NumQsts = Str_ConvertStrToUnsigned (row[0]);
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return NumQsts;
- }
-
-/*****************************************************************************/
-/********** Request the creation or edition of an set of questions ***********/
-/*****************************************************************************/
-
-void ExaSet_RequestCreatOrEditSet (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- bool ItsANewSet;
- char Txt[Cns_MAX_BYTES_TEXT + 1];
-
- /***** Check if I can edit exams *****/
- if (!Exa_CheckIfICanEditExams ())
- Lay_NoPermissionExit ();
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- ItsANewSet = (Set.SetCod <= 0);
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
-
- /***** Get set data *****/
- if (ItsANewSet)
- /* Initialize to empty set */
- ExaSet_ResetSet (&Set);
- else
- {
- /* Get set data from database */
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
- }
-
- /***** Put form to edit the exam created or updated *****/
- Exa_PutFormEditionExam (&Exams,&Exam,Txt,
- false); // No new exam
- }
-
-/*****************************************************************************/
-/*** Request the selection of questions to be added to a set of questions ****/
-/*****************************************************************************/
-
-void ExaSet_ReqSelectQstsToAddToSet (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- char Txt[Cns_MAX_BYTES_TEXT + 1];
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Exam.ExaCod = Exams.ExaCod;
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Show form to select questions for set *****/
- Tst_RequestSelectTestsForSet (&Exams);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/**************** List several test questions for selection ******************/
-/*****************************************************************************/
-
-void ExaSet_ListQstsToAddToSet (void)
- {
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- char Txt[Cns_MAX_BYTES_TEXT + 1];
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Exam.ExaCod = Exams.ExaCod;
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** List several test questions for selection *****/
- Tst_ListQuestionsToSelectForSet (&Exams);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/**************** Write parameter with index of set of questions *****************/
-/*****************************************************************************/
-
-static void ExaSet_PutParamSetCod (long SetCod)
- {
- Par_PutHiddenParamUnsigned (NULL,"SetCod",SetCod);
- }
-
/*****************************************************************************/
/****************** Write parameter with index of question *******************/
/*****************************************************************************/
@@ -2430,62 +1666,6 @@ unsigned Exa_GetParamQstInd (void)
return (unsigned) QstInd;
}
-/*****************************************************************************/
-/****************** Get set index given exam and set code ********************/
-/*****************************************************************************/
-
-static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- long SetInd;
-
- /***** Get set index from set code *****/
- if (!DB_QuerySELECT (&mysql_res,"can not get set index",
- "SELECT SetInd FROM exa_sets"
- " WHERE SetCod=%u"
- " AND ExaCod=%ld", // Extra check
- SetCod,ExaCod))
- Lay_ShowErrorAndExit ("Error: wrong set code.");
-
- /***** Get set code (row[0]) *****/
- row = mysql_fetch_row (mysql_res);
- SetInd = Str_ConvertStrToUnsigned (row[0]);
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return SetInd;
- }
-
-/*****************************************************************************/
-/****************** Get set code given exam and set index ********************/
-/*****************************************************************************/
-
-static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- long SetCod;
-
- /***** Get set code from set index *****/
- if (!DB_QuerySELECT (&mysql_res,"can not get set code",
- "SELECT SetCod FROM exa_sets"
- " WHERE ExaCod=%ld AND SetInd=%u",
- ExaCod,SetInd))
- Lay_ShowErrorAndExit ("Error: wrong set index.");
-
- /***** Get set code (row[0]) *****/
- row = mysql_fetch_row (mysql_res);
- if ((SetCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
- Lay_ShowErrorAndExit ("Error: wrong set code.");
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return SetCod;
- }
-
/*****************************************************************************/
/************ Get question code given exam and index of question *************/
/*****************************************************************************/
@@ -2514,103 +1694,6 @@ long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd)
return QstCod;
}
-/*****************************************************************************/
-/********************* Get maximum set index in an exam **********************/
-/*****************************************************************************/
-// Question index can be 1, 2, 3...
-// Return 0 if no questions
-
-static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned SetInd = 0;
-
- /***** Get maximum set index in an exam from database *****/
- DB_QuerySELECT (&mysql_res,"can not get max set index",
- "SELECT MAX(SetInd)"
- " FROM exa_sets"
- " WHERE ExaCod=%ld",
- ExaCod);
- row = mysql_fetch_row (mysql_res);
- if (row[0]) // There are sets
- if (sscanf (row[0],"%u",&SetInd) != 1)
- Lay_ShowErrorAndExit ("Error when getting max set index.");
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return SetInd;
- }
-
-/*****************************************************************************/
-/*********** Get previous set index to a given set index in an exam **********/
-/*****************************************************************************/
-// Input set index can be 1, 2, 3... n-1
-// Return set index will be 1, 2, 3... n if previous set exists, or 0 if no previous set
-
-static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned PrevSetInd = 0;
-
- /***** Get previous set index in an exam from database *****/
- // Although indexes are always continuous...
- // ...this implementation works even with non continuous indexes
- if (!DB_QuerySELECT (&mysql_res,"can not get previous set index",
- "SELECT MAX(SetInd) FROM exa_sets"
- " WHERE ExaCod=%ld AND SetInd<%u",
- ExaCod,SetInd))
- Lay_ShowErrorAndExit ("Error: previous set index not found.");
-
- /***** Get previous set index (row[0]) *****/
- row = mysql_fetch_row (mysql_res);
- if (row)
- if (row[0])
- if (sscanf (row[0],"%u",&PrevSetInd) != 1)
- Lay_ShowErrorAndExit ("Error when getting previous set index.");
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return PrevSetInd;
- }
-
-/*****************************************************************************/
-/*************** Get next set index to a given index in an exam **************/
-/*****************************************************************************/
-// Input set index can be 0, 1, 2, 3... n-1
-// Return set index will be 1, 2, 3... n if next set exists, or 0 if no next set
-
-static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned NextSetInd = ExaEvt_AFTER_LAST_QUESTION; // End of sets has been reached
-
- /***** Get next set index in an exam from database *****/
- // Although indexes are always continuous...
- // ...this implementation works even with non continuous indexes
- if (!DB_QuerySELECT (&mysql_res,"can not get next set index",
- "SELECT MIN(SetInd) FROM exa_sets"
- " WHERE ExaCod=%ld AND SetInd>%u",
- ExaCod,SetInd))
- Lay_ShowErrorAndExit ("Error: next set index not found.");
-
- /***** Get next set index (row[0]) *****/
- row = mysql_fetch_row (mysql_res);
- if (row)
- if (row[0])
- if (sscanf (row[0],"%u",&NextSetInd) != 1)
- Lay_ShowErrorAndExit ("Error when getting next set index.");
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- return NextSetInd;
- }
-
/*****************************************************************************/
/*********** Get previous question index to a given index in an exam **********/
/*****************************************************************************/
@@ -2679,320 +1762,6 @@ unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd)
return NextQstInd;
}
-/*****************************************************************************/
-/************************* List the sets of an exam **************************/
-/*****************************************************************************/
-
-static void ExaSet_ListExamSets (struct Exa_Exams *Exams,
- struct Exa_Exam *Exam,
- struct ExaSet_Set *Set)
- {
- extern const char *Hlp_ASSESSMENT_Exams_question_sets;
- extern const char *Txt_Sets_of_questions;
- MYSQL_RES *mysql_res;
- unsigned MaxSetInd;
- unsigned NumSets;
- bool ICanEditSets = Exa_CheckIfEditable (Exam);
-
- /***** Get maximum set index *****/
- MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam->ExaCod);
-
- /***** Get data of set of questions from database *****/
- NumSets = (unsigned)
- DB_QuerySELECT (&mysql_res,"can not get sets of questions",
- "SELECT SetCod," // row[0]
- "SetInd," // row[1]
- "NumQstsToExam," // row[2]
- "Title" // row[3]
- " FROM exa_sets"
- " WHERE ExaCod=%ld"
- " ORDER BY SetInd",
- Exam->ExaCod);
-
- /***** Begin box *****/
- Exams->ExaCod = Exam->ExaCod;
- Box_BoxBegin (NULL,Txt_Sets_of_questions,
- NULL,NULL,
- Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE);
-
- /***** Show table with sets *****/
- if (NumSets)
- ExaSet_ListOneOrMoreSetsForEdition (Exams,Exam,
- MaxSetInd,
- NumSets,mysql_res,
- ICanEditSets);
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- /***** Put forms to create/edit a set *****/
- ExaSet_PutFormNewSet (Exams,Exam,Set,MaxSetInd);
-
- /***** End box *****/
- Box_BoxEnd ();
- }
-
-/*****************************************************************************/
-/************************ List the questions of an exam ***********************/
-/*****************************************************************************/
-
-static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams,
- const struct Exa_Exam *Exam,
- const struct ExaSet_Set *Set)
- {
- extern const char *Hlp_ASSESSMENT_Exams_questions;
- extern const char *Txt_Questions;
- MYSQL_RES *mysql_res;
- unsigned NumQsts;
- bool ICanEditQuestions = Exa_CheckIfEditable (Exam);
-
- /***** Get data of questions from database *****/
- NumQsts = (unsigned)
- DB_QuerySELECT (&mysql_res,"can not get exam questions",
- "SELECT exa_questions.QstCod" // row[0]
- " FROM exa_questions LEFT JOIN tst_questions" // LEFT JOIN because the question could be removed in table of test questions
- " ON (exa_questions.QstCod=tst_questions.QstCod)"
- " WHERE exa_questions.SetCod=%ld"
- " ORDER BY tst_questions.Stem",
- Set->SetCod);
-
- /***** Begin box *****/
- if (ICanEditQuestions)
- Box_BoxBegin (NULL,Txt_Questions,
- Exa_PutIconToAddNewQuestions,Exams,
- Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE);
- else
- Box_BoxBegin (NULL,Txt_Questions,
- NULL,NULL,
- Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE);
-
- /***** Show table with questions *****/
- if (NumQsts)
- ExaSet_ListOneOrMoreQuestionsForEdition (Exams,NumQsts,mysql_res,
- ICanEditQuestions);
-
- /***** Put button to add a new question in this set *****/
- if (ICanEditQuestions) // I can edit questions
- Exa_PutButtonToAddNewQuestions (Exams);
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- /***** End box *****/
- Box_BoxEnd ();
- }
-
-/*****************************************************************************/
-/************************* List exam sets for edition ************************/
-/*****************************************************************************/
-
-static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams,
- const struct Exa_Exam *Exam,
- unsigned MaxSetInd,
- unsigned NumSets,
- MYSQL_RES *mysql_res,
- bool ICanEditSets)
- {
- extern const char *Txt_Sets_of_questions;
- extern const char *Txt_Move_up_X;
- extern const char *Txt_Move_down_X;
- extern const char *Txt_Movement_not_allowed;
- unsigned NumSet;
- struct ExaSet_Set Set;
- MYSQL_ROW row;
- char *Anchor;
- char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
-
- /***** Trivial check *****/
- if (!NumSets)
- return;
-
- /***** Write the heading *****/
- HTM_TABLE_BeginWideMarginPadding (2);
- ExaSet_PutTableHeadingForSets ();
-
- /***** Write rows *****/
- for (NumSet = 0;
- NumSet < NumSets;
- NumSet++)
- {
- Gbl.RowEvenOdd = NumSet % 2;
-
- /***** Create set of questions *****/
- ExaSet_ResetSet (&Set);
-
- /***** Get set data *****/
- row = mysql_fetch_row (mysql_res);
- /*
- row[0] SetCod
- row[1] SetInd
- row[2] NumQstsToExam
- row[3] Title
- */
- /* Get set code (row[0]) */
- Set.SetCod = Str_ConvertStrCodToLongCod (row[0]);
-
- /* Get set index (row[1]) */
- Set.SetInd = Str_ConvertStrToUnsigned (row[1]);
- snprintf (StrSetInd,sizeof (Set.SetInd),
- "%u",
- Set.SetInd);
-
- /* Get set index (row[2]) */
- Set.NumQstsToExam = Str_ConvertStrToUnsigned (row[2]);
-
- /* Get the title of the set (row[3]) */
- Str_Copy (Set.Title,row[3],
- ExaSet_MAX_BYTES_TITLE);
-
- /* Initialize context */
- Exams->SetCod = Set.SetCod;
- Exams->SetInd = Set.SetInd;
-
- /***** Build anchor string *****/
- Frm_SetAnchorStr (Set.SetCod,&Anchor);
-
- /***** Begin first row *****/
- HTM_TR_Begin (NULL);
-
- /***** Icons *****/
- HTM_TD_Begin ("rowspan=\"2\" class=\"BT%u\"",Gbl.RowEvenOdd);
-
- /* Put icon to remove the set */
- if (ICanEditSets)
- {
- Frm_StartForm (ActReqRemExaSet);
- ExaSet_PutParamsOneSet (Exams);
- Ico_PutIconRemove ();
- Frm_EndForm ();
- }
- else
- Ico_PutIconRemovalNotAllowed ();
-
- /* Put icon to move up the question */
- if (ICanEditSets && Set.SetInd > 1)
- {
- Lay_PutContextualLinkOnlyIcon (ActUp_ExaSet,Anchor,
- ExaSet_PutParamsOneSet,Exams,
- "arrow-up.svg",
- Str_BuildStringStr (Txt_Move_up_X,
- StrSetInd));
- Str_FreeString ();
- }
- else
- Ico_PutIconOff ("arrow-up.svg",Txt_Movement_not_allowed);
-
- /* Put icon to move down the set */
- if (ICanEditSets && Set.SetInd < MaxSetInd)
- {
- Lay_PutContextualLinkOnlyIcon (ActDwnExaSet,Anchor,
- ExaSet_PutParamsOneSet,Exams,
- "arrow-down.svg",
- Str_BuildStringStr (Txt_Move_down_X,
- StrSetInd));
- Str_FreeString ();
- }
- else
- Ico_PutIconOff ("arrow-down.svg",Txt_Movement_not_allowed);
-
- HTM_TD_End ();
-
- /***** Index *****/
- HTM_TD_Begin ("rowspan=\"2\" class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
- Tst_WriteNumQst (Set.SetInd);
- HTM_TD_End ();
-
- /***** Title *****/
- HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
- HTM_ARTICLE_Begin (Anchor);
- Frm_StartFormAnchor (ActChgTitExaSet,Anchor);
- ExaSet_PutParamsOneSet (Exams);
- HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set.Title,
- HTM_SUBMIT_ON_CHANGE,
- "id=\"Title\" required=\"required\""
- " class=\"TITLE_DESCRIPTION_WIDTH\"");
- Frm_EndForm ();
- HTM_ARTICLE_End ();
- HTM_TD_End ();
-
- /***** Current number of questions in set *****/
- HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
- HTM_Unsigned (ExaSet_GetNumQstsInSet (Set.SetCod));
- HTM_TD_End ();
-
- /***** Number of questions to appear in exam *****/
- HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
- Frm_StartFormAnchor (ActChgNumQstExaSet,Anchor);
- ExaSet_PutParamsOneSet (Exams);
- HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set.NumQstsToExam,
- HTM_SUBMIT_ON_CHANGE,false,
- "class=\"INPUT_LONG\" required=\"required\"");
- Frm_EndForm ();
- HTM_TD_End ();
-
- /***** End first row *****/
- HTM_TR_End ();
-
- /***** Begin second row *****/
- HTM_TR_Begin (NULL);
-
- /***** Questions *****/
- HTM_TD_Begin ("colspan=\"3\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
-
- /* List questions */
- ExaSet_ListSetQuestions (Exams,Exam,&Set);
-
- HTM_TD_End ();
-
- /***** End second row *****/
- HTM_TR_End ();
-
- /***** Free anchor string *****/
- Frm_FreeAnchorStr (Anchor);
- }
-
- /***** End table *****/
- HTM_TABLE_End ();
- }
-
-/*****************************************************************************/
-/***************** Put table heading for sets of questions *******************/
-/*****************************************************************************/
-
-static void ExaSet_PutTableHeadingForSets (void)
- {
- extern const char *Txt_No_INDEX;
- extern const char *Txt_Set_of_questions;
- extern const char *Txt_Number_of_questions;
- extern const char *Txt_Number_of_questions_in_the_exam;
-
- /***** Begin row *****/
- HTM_TR_Begin (NULL);
-
- /***** Header cells *****/
- HTM_TH_Empty (1);
- HTM_TH (1,1,"RB",Txt_No_INDEX);
- HTM_TH (1,1,"LB",Txt_Set_of_questions);
- HTM_TH (1,1,"RB",Txt_Number_of_questions);
- HTM_TH (1,1,"RB",Txt_Number_of_questions_in_the_exam);
-
- /***** End row *****/
- HTM_TR_End ();
- }
-
-/*****************************************************************************/
-/*************************** Reset set of questions **************************/
-/*****************************************************************************/
-
-static void ExaSet_ResetSet (struct ExaSet_Set *Set)
- {
- Set->ExaCod = -1L;
- Set->SetCod = -1L;
- Set->SetInd = 0;
- Set->Title[0] = '\0';
- Set->NumQstsToExam = 0;
- }
-
/*****************************************************************************/
/*************** Put parameter with set code to edit, remove... **************/
/*****************************************************************************/
@@ -3005,663 +1774,12 @@ static void Exa_PutParamSetCod (void *SetCod) // Should be a pointer to long
}
*/
-/*****************************************************************************/
-/********************* List exam questions for edition ***********************/
-/*****************************************************************************/
-
-static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams,
- unsigned NumQsts,
- MYSQL_RES *mysql_res,
- bool ICanEditQuestions)
- {
- extern const char *Txt_Questions;
- extern const char *Txt_No_INDEX;
- extern const char *Txt_Code;
- extern const char *Txt_Tags;
- extern const char *Txt_Question;
- unsigned NumQst;
- MYSQL_ROW row;
- struct Tst_Question Question;
- bool QuestionExists;
- char *Anchor;
-
- /***** Build anchor string *****/
- Frm_SetAnchorStr (Exams->SetCod,&Anchor);
-
- /***** Write the heading *****/
- HTM_TABLE_BeginWideMarginPadding (2);
- HTM_TR_Begin (NULL);
-
- HTM_TH_Empty (1);
-
- HTM_TH (1,1,"CT",Txt_No_INDEX);
- HTM_TH (1,1,"CT",Txt_Code);
- HTM_TH (1,1,"CT",Txt_Tags);
- HTM_TH (1,1,"CT",Txt_Question);
-
- HTM_TR_End ();
-
- /***** Write rows *****/
- for (NumQst = 0;
- NumQst < NumQsts;
- NumQst++)
- {
- Gbl.RowEvenOdd = NumQst % 2;
-
- /***** Create test question *****/
- Tst_QstConstructor (&Question);
-
- /***** Get question data *****/
- row = mysql_fetch_row (mysql_res);
- /*
- row[0] QstCod
- */
- /* Get question code (row[0]) */
- Exams->QstCod = Question.QstCod = Str_ConvertStrCodToLongCod (row[0]);
-
- /***** Begin row *****/
- HTM_TR_Begin (NULL);
-
- /***** Icons *****/
- HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
-
- /* Put icon to remove the question */
- if (ICanEditQuestions)
- {
- Frm_StartForm (ActReqRemSetQst);
- ExaSet_PutParamsOneQst (Exams);
- Ico_PutIconRemove ();
- Frm_EndForm ();
- }
- else
- Ico_PutIconRemovalNotAllowed ();
-
- /* Put icon to edit the question */
- if (ICanEditQuestions)
- Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,
- Tst_PutParamQstCod,&Question.QstCod);
-
- HTM_TD_End ();
-
- /***** Question *****/
- QuestionExists = Tst_GetQstDataFromDB (&Question);
- Tst_ListQuestionForEdition (&Question,NumQst + 1,QuestionExists,Anchor);
-
- /***** End row *****/
- HTM_TR_End ();
-
- /***** Destroy test question *****/
- Tst_QstDestructor (&Question);
- }
-
- /***** End table *****/
- HTM_TABLE_End ();
-
- /***** Free anchor string *****/
- Frm_FreeAnchorStr (Anchor);
- }
-
-/*****************************************************************************/
-/***************** Put icon to add a new questions to exam *******************/
-/*****************************************************************************/
-
-static void Exa_PutIconToAddNewQuestions (void *Exams)
- {
- extern const char *Txt_Add_questions;
-
- /***** Put form to create a new question *****/
- Ico_PutContextualIconToAdd (ActReqAddQstExaSet,NULL,
- Exa_PutParams,Exams,
- Txt_Add_questions);
- }
-
-/*****************************************************************************/
-/***************** Put button to add new questions to exam *******************/
-/*****************************************************************************/
-
-static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams)
- {
- extern const char *Txt_Add_questions;
-
- Frm_StartForm (ActReqAddQstExaSet);
- ExaSet_PutParamsOneSet (Exams);
- Btn_PutConfirmButtonInline (Txt_Add_questions);
- Frm_EndForm ();
- }
-
-/*****************************************************************************/
-/************* Add selected test questions to set of questions ***************/
-/*****************************************************************************/
-
-void ExaSet_AddQstsToSet (void)
- {
- extern const char *Txt_No_questions_have_been_added;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- char Txt[Cns_MAX_BYTES_TEXT + 1];
- const char *Ptr;
- char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
- long QstCod;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Exam.ExaCod = Exams.ExaCod;
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get selected questions *****/
- /* Allocate space for selected question codes */
- ExaSet_AllocateListSelectedQuestions (&Exams);
-
- /* Get question codes */
- Par_GetParMultiToText ("QstCods",Exams.ListQuestions,
- ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS);
-
- /* Check number of questions */
- if (Tst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected...
- {
- /***** Insert questions in database *****/
- Ptr = Exams.ListQuestions;
- while (*Ptr)
- {
- /* Get next code */
- Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
- if (sscanf (LongStr,"%ld",&QstCod) != 1)
- Lay_ShowErrorAndExit ("Wrong question code.");
-
- /* Insert question in the table of questions */
- DB_QueryINSERT ("can not add question to set",
- "INSERT INTO exa_questions"
- " (SetCod,QstCod)"
- " VALUES"
- " (%ld,%ld)",
- Set.SetCod,QstCod);
- }
- }
- else
- Ale_ShowAlert (Ale_WARNING,Txt_No_questions_have_been_added);
-
- /***** Free space for selected question codes *****/
- ExaSet_FreeListsSelectedQuestions (&Exams);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/****************** Allocate memory for list of questions ********************/
-/*****************************************************************************/
-
-static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams)
- {
- if (!Exams->ListQuestions)
- {
- if ((Exams->ListQuestions = (char *) malloc (ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS + 1)) == NULL)
- Lay_NotEnoughMemoryExit ();
- Exams->ListQuestions[0] = '\0';
- }
- }
-
-/*****************************************************************************/
-/*********** Free memory used by list of selected question codes *************/
-/*****************************************************************************/
-
-static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams)
- {
- if (Exams->ListQuestions)
- {
- free (Exams->ListQuestions);
- Exams->ListQuestions = NULL;
- }
- }
-
-/*****************************************************************************/
-/***************** Request the removal of a set of questions *****************/
-/*****************************************************************************/
-
-void ExaSet_RequestRemoveSet (void)
- {
- extern const char *Txt_Do_you_really_want_to_remove_the_set_of_questions_X;
- extern const char *Txt_Remove_set_of_questions;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Show question and button to remove question *****/
- Ale_ShowAlertAndButton (ActRemExaSet,NULL,NULL,
- ExaSet_PutParamsOneSet,&Exams,
- Btn_REMOVE_BUTTON,Txt_Remove_set_of_questions,
- Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_set_of_questions_X,
- Set.Title);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/************************* Remove a set of questions *************************/
-/*****************************************************************************/
-
-void ExaSet_RemoveSet (void)
- {
- extern const char *Txt_Set_of_questions_removed;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Remove the set from all the tables *****/
- /* Remove questions associated to set */
- DB_QueryDELETE ("can not remove questions associated to set",
- "DELETE FROM exa_questions"
- " USING exa_questions,exa_sets"
- " WHERE exa_questions.SetCod=%ld"
- " AND exa_questions.SetCod=exa_sets.SetCod"
- " AND exa_sets.ExaCod=%ld", // Extra check
- Set.SetCod,Set.ExaCod);
-
- /* Remove the set itself */
- DB_QueryDELETE ("can not remove set",
- "DELETE FROM exa_sets"
- " WHERE SetCod=%ld"
- " AND ExaCod=%ld", // Extra check
- Set.SetCod,Set.ExaCod);
- if (!mysql_affected_rows (&Gbl.mysql))
- Lay_ShowErrorAndExit ("The set to be removed does not exist.");
-
- /* Change index of sets greater than this */
- DB_QueryUPDATE ("can not update indexes of sets",
- "UPDATE exa_sets SET SetInd=SetInd-1"
- " WHERE ExaCod=%ld AND SetInd>%u",
- Set.ExaCod,Set.SetInd);
-
- /***** Write message *****/
- Ale_ShowAlert (Ale_SUCCESS,Txt_Set_of_questions_removed);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/************ Move up position of a set of questions in an exam **************/
-/*****************************************************************************/
-
-void ExaSet_MoveUpSet (void)
- {
- extern const char *Txt_Movement_not_allowed;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- unsigned SetIndTop;
- unsigned SetIndBottom;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get set index *****/
- SetIndBottom = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod);
-
- /***** Move up set *****/
- if (SetIndBottom > 1)
- {
- /* Indexes of sets to be exchanged */
- SetIndTop = ExaSet_GetPrevSetIndexInExam (Exam.ExaCod,SetIndBottom);
- if (!SetIndTop)
- Lay_ShowErrorAndExit ("Wrong index of set.");
-
- /* Exchange sets */
- ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom);
- }
- else
- Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/*********** Move down position of a set of questions in an exam *************/
-/*****************************************************************************/
-
-void ExaSet_MoveDownSet (void)
- {
- extern const char *Txt_Movement_not_allowed;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- unsigned SetIndTop;
- unsigned SetIndBottom;
- unsigned MaxSetInd; // 0 if no sets
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get set index *****/
- SetIndTop = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod);
-
- /***** Get maximum set index *****/
- MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam.ExaCod);
-
- /***** Move down set *****/
- if (SetIndTop < MaxSetInd)
- {
- /* Indexes of sets to be exchanged */
- SetIndBottom = ExaSet_GetNextSetIndexInExam (Exam.ExaCod,SetIndTop);
- if (!SetIndBottom)
- Lay_ShowErrorAndExit ("Wrong index of set.");
-
- /* Exchange sets */
- ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom);
- }
- else
- Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/********************** Request the removal of a question ********************/
-/*****************************************************************************/
-
-void ExaSet_RequestRemoveQstFromSet (void)
- {
- extern const char *Txt_Do_you_really_want_to_remove_the_question_X;
- extern const char *Txt_Remove_question;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- char *Anchor;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get question index *****/
- Exams.QstCod = Tst_GetParamQstCod ();
-
- /***** Build anchor string *****/
- Frm_SetAnchorStr (Set.SetCod,&Anchor);
-
- /***** Show question and button to remove question *****/
- Ale_ShowAlertAndButton (ActRemExaQst,Anchor,NULL,
- ExaSet_PutParamsOneQst,&Exams,
- Btn_REMOVE_BUTTON,Txt_Remove_question,
- Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_question_X,
- Exams.QstCod);
-
- /***** Free anchor string *****/
- Frm_FreeAnchorStr (Anchor);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/****************************** Remove a question ****************************/
-/*****************************************************************************/
-
-void ExaSet_RemoveQstFromSet (void)
- {
- extern const char *Txt_Question_removed;
- struct Exa_Exams Exams;
- struct Exa_Exam Exam;
- struct ExaSet_Set Set;
- long QstCod;
-
- /***** Reset exams context *****/
- Exa_ResetExams (&Exams);
- Exa_ResetExam (&Exam);
- ExaSet_ResetSet (&Set);
-
- /***** Get parameters *****/
- Exa_GetParams (&Exams);
- if (Exams.ExaCod <= 0)
- Lay_WrongExamExit ();
- Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
- Set.SetCod = ExaSet_GetParamSetCod ();
- if (Set.SetCod <= 0)
- Lay_WrongSetExit ();
-
- /***** Get exam data from database *****/
- Exa_GetDataOfExamByCod (&Exam);
- Exams.ExaCod = Exam.ExaCod;
- if (!Exa_CheckIfEditable (&Exam))
- Lay_NoPermissionExit ();
-
- /***** Get set data from database *****/
- ExaSet_GetDataOfSetByCod (&Set);
- Exams.SetCod = Set.SetCod;
-
- /***** Get question index *****/
- QstCod = Tst_GetParamQstCod ();
-
- /***** Remove the question from set *****/
- /* Remove the question itself */
- DB_QueryDELETE ("can not remove a question from a set",
- "DELETE FROM exa_questions"
- " WHERE SetCod=%ld AND QstCod=%ld",
- Set.SetCod,QstCod);
- if (!mysql_affected_rows (&Gbl.mysql))
- Lay_ShowErrorAndExit ("The question to be removed does not exist.");
-
- /***** Write message *****/
- Ale_ShowAlert (Ale_SUCCESS,Txt_Question_removed);
-
- /***** Show current exam and its sets *****/
- Exa_PutFormsOneExam (&Exams,&Exam,&Set,
- false); // It's not a new exam
- }
-
-/*****************************************************************************/
-/*********** Exchange the order of two consecutive sets in an exam ***********/
-/*****************************************************************************/
-
-static void ExaSet_ExchangeSets (long ExaCod,
- unsigned SetIndTop,unsigned SetIndBottom)
- {
- long SetCodTop;
- long SetCodBottom;
-
- /***** Lock table to make the move atomic *****/
- DB_Query ("can not lock tables to exchange sets of questions",
- "LOCK TABLES exa_sets WRITE");
- Gbl.DB.LockedTables = true;
-
- /***** Get set codes of the sets to be moved *****/
- SetCodTop = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndTop);
- SetCodBottom = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndBottom);
-
- /***** Exchange indexes of sets *****/
- /*
- Example:
- SetIndTop = 1; SetCodTop = 218
- SetIndBottom = 2; SetCodBottom = 220
- Step 1 Step 2 Step 3
-+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
-| SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod |
-+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
-| 1 | 218 |>| -2 | 218 |>| -2 | 218 |>| 2 | 218 |
-| 2 | 220 | | 2 | 220 | | 1 | 220 | | 1 | 220 |
-| 3 | 232 | | 3 | 232 | | 3 | 232 | | 3 | 232 |
-+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
- */
- /* Step 1: change temporarily top index to minus bottom index
- in order to not repeat unique index (ExaCod,SetInd) */
- DB_QueryUPDATE ("can not exchange indexes of sets",
- "UPDATE exa_sets SET SetInd=-%u"
- " WHERE ExaCod=%ld AND SetCod=%ld",
- SetIndBottom,
- ExaCod,SetCodTop);
-
- /* Step 2: change bottom index to old top index */
- DB_QueryUPDATE ("can not exchange indexes of sets",
- "UPDATE exa_sets SET SetInd=%u"
- " WHERE ExaCod=%ld AND SetCod=%ld",
- SetIndTop,
- ExaCod,SetCodBottom);
-
- /* Step 3: change top index to old bottom index */
- DB_QueryUPDATE ("can not exchange indexes of sets",
- "UPDATE exa_sets SET SetInd=%u"
- " WHERE ExaCod=%ld AND SetCod=%ld",
- SetIndBottom,
- ExaCod,SetCodTop);
-
- /***** Unlock table *****/
- Gbl.DB.LockedTables = false; // Set to false before the following unlock...
- // ...to not retry the unlock if error in unlocking
- DB_Query ("can not unlock tables after exchanging sets of questions",
- "UNLOCK TABLES");
- }
-
/*****************************************************************************/
/*********** Get number of events and check is edition is possible **********/
/*****************************************************************************/
// Before calling this function, number of events must be calculated
-static bool Exa_CheckIfEditable (const struct Exa_Exam *Exam)
+bool Exa_CheckIfEditable (const struct Exa_Exam *Exam)
{
if (Exa_CheckIfICanEditExams ())
/***** Questions are editable only if exam has no events *****/
diff --git a/swad_exam.h b/swad_exam.h
index 309da2d9..215a9b82 100644
--- a/swad_exam.h
+++ b/swad_exam.h
@@ -45,6 +45,9 @@ void Exa_ResetExams (struct Exa_Exams *Exams);
void Exa_ResetExam (struct Exa_Exam *Exam);
void Exa_SeeAllExams (void);
+
+bool Exa_CheckIfICanEditExams (void);
+
void Exa_SeeOneExam (void);
void Exa_ShowOnlyOneExam (struct Exa_Exams *Exams,
struct Exa_Exam *Exam,
@@ -57,11 +60,9 @@ void Exa_ShowOnlyOneExamBegin (struct Exa_Exams *Exams,
void Exa_ShowOnlyOneExamEnd (void);
void Exa_SetCurrentExaCod (long ExaCod);
-void ExaSet_PutParamsOneSet (void *Exams);
void Exa_PutParams (void *Exams);
void Exa_PutParamExamCod (long ExaCod);
long Exa_GetParamExamCod (void);
-long ExaSet_GetParamSetCod (void);
void Exa_GetParams (struct Exa_Exams *Exams);
void Exa_GetListExams (struct Exa_Exams *Exams,Exa_Order_t SelectedOrder);
@@ -70,6 +71,8 @@ void Exa_GetDataOfExamByCod (struct Exa_Exam *Exam);
void Exa_GetDataOfExamByFolder (struct Exa_Exam *Exam);
void Exa_FreeListExams (struct Exa_Exams *Exams);
+void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]);
+
void Exa_AskRemExam (void);
void Exa_RemoveExam (void);
void Exa_RemoveExamsCrs (long CrsCod);
@@ -78,20 +81,17 @@ void Exa_HideExam (void);
void Exa_UnhideExam (void);
void Exa_RequestCreatOrEditExam (void);
-
-void ExaSet_ReceiveFormSet (void);
-void ExaSet_ChangeSetTitle (void);
-void ExaSet_ChangeNumQstsToExam (void);
+void Exa_PutFormsOneExam (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set,
+ bool ItsANewExam);
+void Exa_PutFormEditionExam (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ char Txt[Cns_MAX_BYTES_TEXT + 1],
+ bool ItsANewExam);
void Exa_ReceiveFormExam (void);
-unsigned ExaSet_GetNumSetsExam (long ExaCod);
-unsigned ExaSet_GetNumQstsExam (long ExaCod);
-
-void ExaSet_RequestCreatOrEditSet (void);
-void ExaSet_ReqSelectQstsToAddToSet (void);
-void ExaSet_ListQstsToAddToSet (void);
-
void Exa_PutParamQstInd (unsigned QstInd);
unsigned Exa_GetParamQstInd (void);
long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd);
@@ -99,16 +99,7 @@ long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd);
unsigned Exa_GetPrevQuestionIndexInExam (long ExaCod,unsigned QstInd);
unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd);
-void ExaSet_AddQstsToSet (void);
-
-void ExaSet_RequestRemoveSet (void);
-void ExaSet_RemoveSet (void);
-
-void ExaSet_MoveUpSet (void);
-void ExaSet_MoveDownSet (void);
-
-void ExaSet_RequestRemoveQstFromSet (void);
-void ExaSet_RemoveQstFromSet (void);
+bool Exa_CheckIfEditable (const struct Exa_Exam *Exam);
unsigned Exa_GetNumCoursesWithExams (Hie_Level_t Scope);
unsigned Exa_GetNumExams (Hie_Level_t Scope);
diff --git a/swad_exam_event.c b/swad_exam_event.c
index e6d9c221..9713f764 100644
--- a/swad_exam_event.c
+++ b/swad_exam_event.c
@@ -37,6 +37,7 @@
#include "swad_exam.h"
#include "swad_exam_event.h"
#include "swad_exam_result.h"
+#include "swad_exam_set.h"
#include "swad_exam_type.h"
#include "swad_form.h"
#include "swad_global.h"
diff --git a/swad_exam_set.c b/swad_exam_set.c
new file mode 100644
index 00000000..63e5e103
--- /dev/null
+++ b/swad_exam_set.c
@@ -0,0 +1,1940 @@
+// swad_exam_set.c: set of questions in exams
+
+/*
+ SWAD (Shared Workspace At a Distance),
+ is a web platform developed at the University of Granada (Spain),
+ and used to support university teaching.
+
+ This file is part of SWAD core.
+ Copyright (C) 1999-2020 Antonio Caņas Vargas
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General 3 License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+#define _GNU_SOURCE // For asprintf
+#include // For DBL_MAX
+#include // For PATH_MAX
+#include // For NULL
+#include // For asprintf
+#include // For calloc
+#include // For string functions
+
+#include "swad_database.h"
+#include "swad_exam.h"
+#include "swad_exam_event.h"
+#include "swad_exam_result.h"
+#include "swad_exam_set.h"
+#include "swad_exam_type.h"
+#include "swad_figure.h"
+#include "swad_form.h"
+#include "swad_global.h"
+#include "swad_HTML.h"
+#include "swad_match.h"
+#include "swad_match_result.h"
+#include "swad_pagination.h"
+#include "swad_role.h"
+#include "swad_test.h"
+#include "swad_test_visibility.h"
+
+/*****************************************************************************/
+/************** External global variables from others modules ****************/
+/*****************************************************************************/
+
+extern struct Globals Gbl;
+
+/*****************************************************************************/
+/***************************** Private constants *****************************/
+/*****************************************************************************/
+
+#define ExaSet_MAX_SELECTED_QUESTIONS 10000
+#define ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS (ExaSet_MAX_SELECTED_QUESTIONS * (Cns_MAX_DECIMAL_DIGITS_LONG + 1))
+
+/*****************************************************************************/
+/******************************* Private types *******************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/***************************** Private variables *****************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/***************************** Private prototypes ****************************/
+/*****************************************************************************/
+
+static void ExaSet_PutParamsOneQst (void *Exams);
+
+static unsigned ExaSet_GetNumQstsInSet (long SetCod);
+
+static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set,
+ const char Title[ExaSet_MAX_BYTES_TITLE + 1]);
+
+static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set,
+ unsigned MaxSetInd);
+static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set);
+static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set,
+ const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]);
+
+static void ExaSet_CreateSet (struct ExaSet_Set *Set);
+static void ExaSet_UpdateSet (const struct ExaSet_Set *Set);
+static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set,
+ const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]);
+static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set,
+ unsigned NumQstsToExam);
+
+static void ExaSet_PutParamSetCod (long SetCod);
+
+static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod);
+static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd);
+
+static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod);
+
+static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd);
+static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd);
+
+static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams,
+ const struct Exa_Exam *Exam,
+ const struct ExaSet_Set *Set);
+static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams,
+ const struct Exa_Exam *Exam,
+ unsigned MaxSetInd,
+ unsigned NumSets,
+ MYSQL_RES *mysql_res,
+ bool ICanEditSets);
+static void ExaSet_PutTableHeadingForSets (void);
+
+static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams,
+ unsigned NumQsts,
+ MYSQL_RES *mysql_res,
+ bool ICanEditQuestions);
+
+static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams);
+static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams);
+
+static void ExaSet_ExchangeSets (long ExaCod,
+ unsigned SetIndTop,unsigned SetIndBottom);
+
+static void ExaSet_PutIconToAddNewQuestions (void *Exams);
+static void ExaSet_PutButtonToAddNewQuestions (struct Exa_Exams *Exams);
+
+/*****************************************************************************/
+/************ Put parameter to move/remove one set of questions **************/
+/*****************************************************************************/
+
+void ExaSet_PutParamsOneSet (void *Exams)
+ {
+ if (Exams)
+ {
+ Exa_PutParams (Exams);
+ ExaSet_PutParamSetCod (((struct Exa_Exams *) Exams)->SetCod);
+ }
+ }
+
+/*****************************************************************************/
+/**************** Put parameter to move/remove one question ******************/
+/*****************************************************************************/
+
+static void ExaSet_PutParamsOneQst (void *Exams)
+ {
+ ExaSet_PutParamsOneSet (Exams);
+ Tst_PutParamQstCod (&(((struct Exa_Exams *) Exams)->QstCod));
+ }
+
+/*****************************************************************************/
+/********************** Get parameter with code of set ***********************/
+/*****************************************************************************/
+
+long ExaSet_GetParamSetCod (void)
+ {
+ /***** Get code of set *****/
+ return Par_GetParToLong ("SetCod");
+ }
+
+/*****************************************************************************/
+/********************* Get number of questions in a set **********************/
+/*****************************************************************************/
+
+static unsigned ExaSet_GetNumQstsInSet (long SetCod)
+ {
+ /***** Get number of questions in set from database *****/
+ return
+ (unsigned) DB_QueryCOUNT ("can not get number of questions in a set",
+ "SELECT COUNT(*) FROM exa_questions"
+ " WHERE SetCod=%ld",
+ SetCod);
+ }
+
+/*****************************************************************************/
+/*********************** Get set data using its code *************************/
+/*****************************************************************************/
+
+void ExaSet_GetDataOfSetByCod (struct ExaSet_Set *Set)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
+
+ /***** Trivial check *****/
+ if (Set->SetCod <= 0)
+ {
+ /* Initialize to empty set */
+ ExaSet_ResetSet (Set);
+ return;
+ }
+
+ /***** Get data of set of questions from database *****/
+ if (DB_QuerySELECT (&mysql_res,"can not get set data",
+ "SELECT SetCod," // row[0]
+ "SetInd," // row[1]
+ "NumQstsToExam," // row[2]
+ "Title" // row[3]
+ " FROM exa_sets"
+ " WHERE SetCod=%ld"
+ " AND ExaCod=%ld", // Extra check
+ Set->SetCod,Set->ExaCod)) // Set found...
+ {
+ /* Get row */
+ row = mysql_fetch_row (mysql_res);
+ /*
+ row[0] SetCod
+ row[1] SetInd
+ row[2] NumQstsToExam
+ row[3] Title
+ */
+ /* Get set code (row[0]) */
+ Set->SetCod = Str_ConvertStrCodToLongCod (row[0]);
+
+ /* Get set index (row[1]) */
+ Set->SetInd = Str_ConvertStrToUnsigned (row[1]);
+ snprintf (StrSetInd,sizeof (Set->SetInd),
+ "%u",
+ Set->SetInd);
+
+ /* Get set index (row[2]) */
+ Set->NumQstsToExam = Str_ConvertStrToUnsigned (row[2]);
+
+ /* Get the title of the set (row[3]) */
+ Str_Copy (Set->Title,row[3],
+ ExaSet_MAX_BYTES_TITLE);
+ }
+ else
+ /* Initialize to empty set */
+ ExaSet_ResetSet (Set);
+
+ /* Free structure that stores the query result */
+ DB_FreeMySQLResult (&mysql_res);
+ }
+
+/*****************************************************************************/
+/************** Check if the title of a set of questions exists **************/
+/*****************************************************************************/
+
+static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set,
+ const char Title[ExaSet_MAX_BYTES_TITLE + 1])
+ {
+ /***** Get number of set of questions with a field value from database *****/
+ return (DB_QueryCOUNT ("can not get similar sets of questions",
+ "SELECT COUNT(*) FROM exa_sets,exa_exams"
+ " WHERE exa_sets.ExaCod=%ld AND exa_sets.Title='%s'"
+ " AND exa_sets.SetCod<>%ld"
+ " AND exa_sets.ExaCod=exa_exams.ExaCod"
+ " AND exa_exams.CrsCod=%ld", // Extra check
+ Set->ExaCod,Title,
+ Set->SetCod,
+ Gbl.Hierarchy.Crs.CrsCod) != 0);
+ }
+
+/*****************************************************************************/
+/********************* Put a form to create/edit an exam **********************/
+/*****************************************************************************/
+
+static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set,
+ unsigned MaxSetInd)
+ {
+ // extern const char *Hlp_ASSESSMENT_Exams_new_set;
+ // extern const char *Hlp_ASSESSMENT_Exams_edit_set;
+ extern const char *Txt_New_set_of_questions;
+ extern const char *Txt_Create_set_of_questions;
+
+ /***** Begin form *****/
+ Exams->ExaCod = Exam->ExaCod;
+ Frm_StartForm (ActNewExaSet);
+ Exa_PutParams (Exams);
+
+ /***** Begin box and table *****/
+ Box_BoxTableBegin (NULL,Txt_New_set_of_questions,
+ NULL,NULL,
+ NULL,Box_NOT_CLOSABLE,2);
+
+ /***** Table heading *****/
+ ExaSet_PutTableHeadingForSets ();
+
+ /***** Begin row *****/
+ HTM_TR_Begin (NULL);
+
+ /***** Empty column for buttons *****/
+ HTM_TD_Begin ("class=\"BM\"");
+ HTM_TD_End ();
+
+ /***** Index *****/
+ HTM_TD_Begin ("class=\"RM\"");
+ Tst_WriteNumQst (MaxSetInd + 1);
+ HTM_TD_End ();
+
+ /***** Title *****/
+ HTM_TD_Begin ("class=\"LM\"");
+ HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set->Title,
+ HTM_DONT_SUBMIT_ON_CHANGE,
+ "id=\"Title\" required=\"required\""
+ " class=\"TITLE_DESCRIPTION_WIDTH\"");
+ HTM_TD_End ();
+
+ /***** Current number of questions in set *****/
+ HTM_TD_Begin ("class=\"RM\"");
+ HTM_Unsigned (0); // New set ==> no questions yet
+ HTM_TD_End ();
+
+ /***** Number of questions to appear in the exam *****/
+ HTM_TD_Begin ("class=\"RM\"");
+ HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set->NumQstsToExam,
+ HTM_DONT_SUBMIT_ON_CHANGE,false,
+ "class=\"INPUT_LONG\" required=\"required\"");
+ HTM_TD_End ();
+
+ /***** End row *****/
+ HTM_TR_End ();
+
+ /***** End table, send button and end box *****/
+ Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_set_of_questions);
+
+ /***** End form *****/
+ Frm_EndForm ();
+ }
+
+/*****************************************************************************/
+/**************** Receive form to create a new set of questions **************/
+/*****************************************************************************/
+
+void ExaSet_ReceiveFormSet (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ bool ItsANewSet;
+
+ /***** Check if I can edit exams *****/
+ if (!Exa_CheckIfICanEditExams ())
+ Lay_NoPermissionExit ();
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ ItsANewSet = (Set.SetCod <= 0);
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+
+ /***** If I can edit exams ==> receive set from form *****/
+ ExaSet_ReceiveSetFieldsFromForm (&Set);
+ if (ExaSet_CheckSetTitleReceivedFromForm (&Set,Set.Title))
+ {
+ /***** Create a new exam or update an existing one *****/
+ if (ItsANewSet)
+ ExaSet_CreateSet (&Set); // Add new set to database
+ else
+ ExaSet_UpdateSet (&Set); // Update set data in database
+ }
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set)
+ {
+ /***** Get set title *****/
+ Par_GetParToText ("Title",Set->Title,ExaSet_MAX_BYTES_TITLE);
+
+ /***** Get number of questions in set to appear in exam *****/
+ Set->NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam",
+ 0,
+ UINT_MAX,
+ 0);
+ }
+
+static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set,
+ const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1])
+ {
+ extern const char *Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X;
+ extern const char *Txt_You_must_specify_the_title_of_the_set_of_questions;
+ bool NewTitleIsCorrect;
+
+ /***** Check if title is correct *****/
+ NewTitleIsCorrect = true;
+ if (NewTitle[0]) // If there's an set title
+ {
+ /***** Check if old and new titles are the same
+ (this happens when return is pressed without changes) *****/
+ if (strcmp (Set->Title,NewTitle)) // Different titles
+ {
+ /* If title of set was in database... */
+ if (ExaSet_CheckIfSimilarSetExists (Set,NewTitle))
+ {
+ NewTitleIsCorrect = false;
+ Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X,
+ Set->Title);
+ }
+ }
+ }
+ else // If there is not a set title
+ {
+ NewTitleIsCorrect = false;
+ Ale_ShowAlert (Ale_WARNING,Txt_You_must_specify_the_title_of_the_set_of_questions);
+ }
+
+ return NewTitleIsCorrect;
+ }
+
+/*****************************************************************************/
+/************* Receive form to change title of set of questions **************/
+/*****************************************************************************/
+
+void ExaSet_ChangeSetTitle (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ char NewTitle[ExaSet_MAX_BYTES_TITLE + 1];
+
+ /***** Check if I can edit exams *****/
+ if (!Exa_CheckIfICanEditExams ())
+ Lay_NoPermissionExit ();
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get exam and set data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Receive new title from form *****/
+ Par_GetParToText ("Title",NewTitle,ExaSet_MAX_BYTES_TITLE);
+
+ /***** Check if title should be changed *****/
+ if (ExaSet_CheckSetTitleReceivedFromForm (&Set,NewTitle))
+ {
+ /* Update the table changing old title by new title */
+ ExaSet_UpdateSetTitleDB (&Set,NewTitle);
+
+ /* Update title */
+ Str_Copy (Set.Title,NewTitle,
+ ExaSet_MAX_BYTES_TITLE);
+ }
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+/*****************************************************************************/
+/***** Receive form to change number of questions to appear in the exam ******/
+/*****************************************************************************/
+
+void ExaSet_ChangeNumQstsToExam (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ unsigned NumQstsToExam;
+
+ /***** Check if I can edit exams *****/
+ if (!Exa_CheckIfICanEditExams ())
+ Lay_NoPermissionExit ();
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get exam and set data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get number of questions in set to appear in exam *****/
+ NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam",
+ 0,
+ UINT_MAX,
+ 0);
+
+ /***** Check if title should be changed *****/
+ if (NumQstsToExam != Set.NumQstsToExam)
+ {
+ /* Update the table changing old number by new number */
+ ExaSet_UpdateNumQstsToExamDB (&Set,NumQstsToExam);
+
+ /* Update title */
+ Set.NumQstsToExam = NumQstsToExam;
+ }
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/********************** Create a new set of questions ************************/
+/*****************************************************************************/
+
+static void ExaSet_CreateSet (struct ExaSet_Set *Set)
+ {
+ extern const char *Txt_Created_new_set_of_questions_X;
+ unsigned MaxSetInd;
+
+ /***** Get maximum set index *****/
+ MaxSetInd = ExaSet_GetMaxSetIndexInExam (Set->ExaCod);
+
+ /***** Create a new exam *****/
+ Set->SetCod =
+ DB_QueryINSERTandReturnCode ("can not create new set of questions",
+ "INSERT INTO exa_sets"
+ " (ExaCod,SetInd,NumQstsToExam,Title)"
+ " VALUES"
+ " (%ld,%u,%u,'%s')",
+ Set->ExaCod,
+ MaxSetInd + 1,
+ Set->NumQstsToExam,
+ Set->Title);
+
+ /***** Write success message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_set_of_questions_X,
+ Set->Title);
+ }
+
+/*****************************************************************************/
+/******************** Update an existing set of questions ********************/
+/*****************************************************************************/
+
+static void ExaSet_UpdateSet (const struct ExaSet_Set *Set)
+ {
+ extern const char *Txt_The_set_of_questions_has_been_modified;
+
+ /***** Update the data of the set of questions *****/
+ DB_QueryUPDATE ("can not update set of questions",
+ "UPDATE exa_sets"
+ " SET ExaCod=%ld,"
+ "SetInd=%u,"
+ "NumQstsToExam=%u,"
+ "Title='%s'"
+ " WHERE SetCod=%ld",
+ Set->ExaCod,
+ Set->SetInd,
+ Set->NumQstsToExam,
+ Set->Title,
+ Set->SetCod);
+
+ /***** Write success message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_The_set_of_questions_has_been_modified);
+ }
+
+/*****************************************************************************/
+/************************ Update set title in database ***********************/
+/*****************************************************************************/
+
+static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set,
+ const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1])
+ {
+ /***** Update set of questions changing old title by new title *****/
+ DB_QueryUPDATE ("can not update the title of a set of questions",
+ "UPDATE exa_sets SET Title='%s'"
+ " WHERE SetCod=%ld"
+ " AND ExaCod=%ld", // Extra check
+ NewTitle,
+ Set->SetCod,Set->ExaCod);
+ }
+
+/*****************************************************************************/
+/********* Update number of questions to appear in exam in database **********/
+/*****************************************************************************/
+
+static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set,
+ unsigned NumQstsToExam)
+ {
+ /***** Update set of questions changing old number by new number *****/
+ DB_QueryUPDATE ("can not update the number of questions to appear in exam",
+ "UPDATE exa_sets SET NumQstsToExam=%u"
+ " WHERE SetCod=%ld"
+ " AND ExaCod=%ld", // Extra check
+ NumQstsToExam,
+ Set->SetCod,Set->ExaCod);
+ }
+
+/*****************************************************************************/
+/******************* Get number of questions of an exam *********************/
+/*****************************************************************************/
+
+unsigned ExaSet_GetNumSetsExam (long ExaCod)
+ {
+ /***** Get number of sets in an exam from database *****/
+ return
+ (unsigned) DB_QueryCOUNT ("can not get number of sets in an exam",
+ "SELECT COUNT(*) FROM exa_sets"
+ " WHERE ExaCod=%ld",
+ ExaCod);
+ }
+
+/*****************************************************************************/
+/******************* Get number of questions of an exam *********************/
+/*****************************************************************************/
+
+unsigned ExaSet_GetNumQstsExam (long ExaCod)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned NumQsts = 0;
+
+ /***** Get total number of questions to appear in exam *****/
+ if (!DB_QuerySELECT (&mysql_res,"can not get number of questions in an exam",
+ "SELECT SUM(NumQstsToExam) FROM exa_sets"
+ " WHERE ExaCod=%ld",
+ ExaCod))
+ Lay_ShowErrorAndExit ("Error: wrong question index.");
+
+ /***** Get number of questions (row[0]) *****/
+ row = mysql_fetch_row (mysql_res);
+ if (row[0])
+ NumQsts = Str_ConvertStrToUnsigned (row[0]);
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return NumQsts;
+ }
+
+/*****************************************************************************/
+/********** Request the creation or edition of an set of questions ***********/
+/*****************************************************************************/
+
+void ExaSet_RequestCreatOrEditSet (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ bool ItsANewSet;
+ char Txt[Cns_MAX_BYTES_TEXT + 1];
+
+ /***** Check if I can edit exams *****/
+ if (!Exa_CheckIfICanEditExams ())
+ Lay_NoPermissionExit ();
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ ItsANewSet = (Set.SetCod <= 0);
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
+
+ /***** Get set data *****/
+ if (ItsANewSet)
+ /* Initialize to empty set */
+ ExaSet_ResetSet (&Set);
+ else
+ {
+ /* Get set data from database */
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+ }
+
+ /***** Put form to edit the exam created or updated *****/
+ Exa_PutFormEditionExam (&Exams,&Exam,Txt,
+ false); // No new exam
+ }
+
+/*****************************************************************************/
+/*** Request the selection of questions to be added to a set of questions ****/
+/*****************************************************************************/
+
+void ExaSet_ReqSelectQstsToAddToSet (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ char Txt[Cns_MAX_BYTES_TEXT + 1];
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Exam.ExaCod = Exams.ExaCod;
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Show form to select questions for set *****/
+ Tst_RequestSelectTestsForSet (&Exams);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/**************** List several test questions for selection ******************/
+/*****************************************************************************/
+
+void ExaSet_ListQstsToAddToSet (void)
+ {
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ char Txt[Cns_MAX_BYTES_TEXT + 1];
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Exam.ExaCod = Exams.ExaCod;
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** List several test questions for selection *****/
+ Tst_ListQuestionsToSelectForSet (&Exams);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/**************** Write parameter with index of set of questions *****************/
+/*****************************************************************************/
+
+static void ExaSet_PutParamSetCod (long SetCod)
+ {
+ Par_PutHiddenParamUnsigned (NULL,"SetCod",SetCod);
+ }
+
+/*****************************************************************************/
+/****************** Get set index given exam and set code ********************/
+/*****************************************************************************/
+
+static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ long SetInd;
+
+ /***** Get set index from set code *****/
+ if (!DB_QuerySELECT (&mysql_res,"can not get set index",
+ "SELECT SetInd FROM exa_sets"
+ " WHERE SetCod=%u"
+ " AND ExaCod=%ld", // Extra check
+ SetCod,ExaCod))
+ Lay_ShowErrorAndExit ("Error: wrong set code.");
+
+ /***** Get set code (row[0]) *****/
+ row = mysql_fetch_row (mysql_res);
+ SetInd = Str_ConvertStrToUnsigned (row[0]);
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return SetInd;
+ }
+
+/*****************************************************************************/
+/****************** Get set code given exam and set index ********************/
+/*****************************************************************************/
+
+static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ long SetCod;
+
+ /***** Get set code from set index *****/
+ if (!DB_QuerySELECT (&mysql_res,"can not get set code",
+ "SELECT SetCod FROM exa_sets"
+ " WHERE ExaCod=%ld AND SetInd=%u",
+ ExaCod,SetInd))
+ Lay_ShowErrorAndExit ("Error: wrong set index.");
+
+ /***** Get set code (row[0]) *****/
+ row = mysql_fetch_row (mysql_res);
+ if ((SetCod = Str_ConvertStrCodToLongCod (row[0])) <= 0)
+ Lay_ShowErrorAndExit ("Error: wrong set code.");
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return SetCod;
+ }
+
+/*****************************************************************************/
+/********************* Get maximum set index in an exam **********************/
+/*****************************************************************************/
+// Question index can be 1, 2, 3...
+// Return 0 if no questions
+
+static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned SetInd = 0;
+
+ /***** Get maximum set index in an exam from database *****/
+ DB_QuerySELECT (&mysql_res,"can not get max set index",
+ "SELECT MAX(SetInd)"
+ " FROM exa_sets"
+ " WHERE ExaCod=%ld",
+ ExaCod);
+ row = mysql_fetch_row (mysql_res);
+ if (row[0]) // There are sets
+ if (sscanf (row[0],"%u",&SetInd) != 1)
+ Lay_ShowErrorAndExit ("Error when getting max set index.");
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return SetInd;
+ }
+
+/*****************************************************************************/
+/*********** Get previous set index to a given set index in an exam **********/
+/*****************************************************************************/
+// Input set index can be 1, 2, 3... n-1
+// Return set index will be 1, 2, 3... n if previous set exists, or 0 if no previous set
+
+static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned PrevSetInd = 0;
+
+ /***** Get previous set index in an exam from database *****/
+ // Although indexes are always continuous...
+ // ...this implementation works even with non continuous indexes
+ if (!DB_QuerySELECT (&mysql_res,"can not get previous set index",
+ "SELECT MAX(SetInd) FROM exa_sets"
+ " WHERE ExaCod=%ld AND SetInd<%u",
+ ExaCod,SetInd))
+ Lay_ShowErrorAndExit ("Error: previous set index not found.");
+
+ /***** Get previous set index (row[0]) *****/
+ row = mysql_fetch_row (mysql_res);
+ if (row)
+ if (row[0])
+ if (sscanf (row[0],"%u",&PrevSetInd) != 1)
+ Lay_ShowErrorAndExit ("Error when getting previous set index.");
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return PrevSetInd;
+ }
+
+/*****************************************************************************/
+/*************** Get next set index to a given index in an exam **************/
+/*****************************************************************************/
+// Input set index can be 0, 1, 2, 3... n-1
+// Return set index will be 1, 2, 3... n if next set exists, or 0 if no next set
+
+static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned NextSetInd = ExaEvt_AFTER_LAST_QUESTION; // End of sets has been reached
+
+ /***** Get next set index in an exam from database *****/
+ // Although indexes are always continuous...
+ // ...this implementation works even with non continuous indexes
+ if (!DB_QuerySELECT (&mysql_res,"can not get next set index",
+ "SELECT MIN(SetInd) FROM exa_sets"
+ " WHERE ExaCod=%ld AND SetInd>%u",
+ ExaCod,SetInd))
+ Lay_ShowErrorAndExit ("Error: next set index not found.");
+
+ /***** Get next set index (row[0]) *****/
+ row = mysql_fetch_row (mysql_res);
+ if (row)
+ if (row[0])
+ if (sscanf (row[0],"%u",&NextSetInd) != 1)
+ Lay_ShowErrorAndExit ("Error when getting next set index.");
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ return NextSetInd;
+ }
+
+/*****************************************************************************/
+/************************* List the sets of an exam **************************/
+/*****************************************************************************/
+
+void ExaSet_ListExamSets (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set)
+ {
+ extern const char *Hlp_ASSESSMENT_Exams_question_sets;
+ extern const char *Txt_Sets_of_questions;
+ MYSQL_RES *mysql_res;
+ unsigned MaxSetInd;
+ unsigned NumSets;
+ bool ICanEditSets = Exa_CheckIfEditable (Exam);
+
+ /***** Get maximum set index *****/
+ MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam->ExaCod);
+
+ /***** Get data of set of questions from database *****/
+ NumSets = (unsigned)
+ DB_QuerySELECT (&mysql_res,"can not get sets of questions",
+ "SELECT SetCod," // row[0]
+ "SetInd," // row[1]
+ "NumQstsToExam," // row[2]
+ "Title" // row[3]
+ " FROM exa_sets"
+ " WHERE ExaCod=%ld"
+ " ORDER BY SetInd",
+ Exam->ExaCod);
+
+ /***** Begin box *****/
+ Exams->ExaCod = Exam->ExaCod;
+ Box_BoxBegin (NULL,Txt_Sets_of_questions,
+ NULL,NULL,
+ Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE);
+
+ /***** Show table with sets *****/
+ if (NumSets)
+ ExaSet_ListOneOrMoreSetsForEdition (Exams,Exam,
+ MaxSetInd,
+ NumSets,mysql_res,
+ ICanEditSets);
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ /***** Put forms to create/edit a set *****/
+ ExaSet_PutFormNewSet (Exams,Exam,Set,MaxSetInd);
+
+ /***** End box *****/
+ Box_BoxEnd ();
+ }
+
+/*****************************************************************************/
+/************************ List the questions of an exam ***********************/
+/*****************************************************************************/
+
+static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams,
+ const struct Exa_Exam *Exam,
+ const struct ExaSet_Set *Set)
+ {
+ extern const char *Hlp_ASSESSMENT_Exams_questions;
+ extern const char *Txt_Questions;
+ MYSQL_RES *mysql_res;
+ unsigned NumQsts;
+ bool ICanEditQuestions = Exa_CheckIfEditable (Exam);
+
+ /***** Get data of questions from database *****/
+ NumQsts = (unsigned)
+ DB_QuerySELECT (&mysql_res,"can not get exam questions",
+ "SELECT exa_questions.QstCod" // row[0]
+ " FROM exa_questions LEFT JOIN tst_questions" // LEFT JOIN because the question could be removed in table of test questions
+ " ON (exa_questions.QstCod=tst_questions.QstCod)"
+ " WHERE exa_questions.SetCod=%ld"
+ " ORDER BY tst_questions.Stem",
+ Set->SetCod);
+
+ /***** Begin box *****/
+ if (ICanEditQuestions)
+ Box_BoxBegin (NULL,Txt_Questions,
+ ExaSet_PutIconToAddNewQuestions,Exams,
+ Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE);
+ else
+ Box_BoxBegin (NULL,Txt_Questions,
+ NULL,NULL,
+ Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE);
+
+ /***** Show table with questions *****/
+ if (NumQsts)
+ ExaSet_ListOneOrMoreQuestionsForEdition (Exams,NumQsts,mysql_res,
+ ICanEditQuestions);
+
+ /***** Put button to add a new question in this set *****/
+ if (ICanEditQuestions) // I can edit questions
+ ExaSet_PutButtonToAddNewQuestions (Exams);
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ /***** End box *****/
+ Box_BoxEnd ();
+ }
+
+/*****************************************************************************/
+/************************* List exam sets for edition ************************/
+/*****************************************************************************/
+
+static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams,
+ const struct Exa_Exam *Exam,
+ unsigned MaxSetInd,
+ unsigned NumSets,
+ MYSQL_RES *mysql_res,
+ bool ICanEditSets)
+ {
+ extern const char *Txt_Sets_of_questions;
+ extern const char *Txt_Move_up_X;
+ extern const char *Txt_Move_down_X;
+ extern const char *Txt_Movement_not_allowed;
+ unsigned NumSet;
+ struct ExaSet_Set Set;
+ MYSQL_ROW row;
+ char *Anchor;
+ char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
+
+ /***** Trivial check *****/
+ if (!NumSets)
+ return;
+
+ /***** Write the heading *****/
+ HTM_TABLE_BeginWideMarginPadding (2);
+ ExaSet_PutTableHeadingForSets ();
+
+ /***** Write rows *****/
+ for (NumSet = 0;
+ NumSet < NumSets;
+ NumSet++)
+ {
+ Gbl.RowEvenOdd = NumSet % 2;
+
+ /***** Create set of questions *****/
+ ExaSet_ResetSet (&Set);
+
+ /***** Get set data *****/
+ row = mysql_fetch_row (mysql_res);
+ /*
+ row[0] SetCod
+ row[1] SetInd
+ row[2] NumQstsToExam
+ row[3] Title
+ */
+ /* Get set code (row[0]) */
+ Set.SetCod = Str_ConvertStrCodToLongCod (row[0]);
+
+ /* Get set index (row[1]) */
+ Set.SetInd = Str_ConvertStrToUnsigned (row[1]);
+ snprintf (StrSetInd,sizeof (Set.SetInd),
+ "%u",
+ Set.SetInd);
+
+ /* Get set index (row[2]) */
+ Set.NumQstsToExam = Str_ConvertStrToUnsigned (row[2]);
+
+ /* Get the title of the set (row[3]) */
+ Str_Copy (Set.Title,row[3],
+ ExaSet_MAX_BYTES_TITLE);
+
+ /* Initialize context */
+ Exams->SetCod = Set.SetCod;
+ Exams->SetInd = Set.SetInd;
+
+ /***** Build anchor string *****/
+ Frm_SetAnchorStr (Set.SetCod,&Anchor);
+
+ /***** Begin first row *****/
+ HTM_TR_Begin (NULL);
+
+ /***** Icons *****/
+ HTM_TD_Begin ("rowspan=\"2\" class=\"BT%u\"",Gbl.RowEvenOdd);
+
+ /* Put icon to remove the set */
+ if (ICanEditSets)
+ {
+ Frm_StartForm (ActReqRemExaSet);
+ ExaSet_PutParamsOneSet (Exams);
+ Ico_PutIconRemove ();
+ Frm_EndForm ();
+ }
+ else
+ Ico_PutIconRemovalNotAllowed ();
+
+ /* Put icon to move up the question */
+ if (ICanEditSets && Set.SetInd > 1)
+ {
+ Lay_PutContextualLinkOnlyIcon (ActUp_ExaSet,Anchor,
+ ExaSet_PutParamsOneSet,Exams,
+ "arrow-up.svg",
+ Str_BuildStringStr (Txt_Move_up_X,
+ StrSetInd));
+ Str_FreeString ();
+ }
+ else
+ Ico_PutIconOff ("arrow-up.svg",Txt_Movement_not_allowed);
+
+ /* Put icon to move down the set */
+ if (ICanEditSets && Set.SetInd < MaxSetInd)
+ {
+ Lay_PutContextualLinkOnlyIcon (ActDwnExaSet,Anchor,
+ ExaSet_PutParamsOneSet,Exams,
+ "arrow-down.svg",
+ Str_BuildStringStr (Txt_Move_down_X,
+ StrSetInd));
+ Str_FreeString ();
+ }
+ else
+ Ico_PutIconOff ("arrow-down.svg",Txt_Movement_not_allowed);
+
+ HTM_TD_End ();
+
+ /***** Index *****/
+ HTM_TD_Begin ("rowspan=\"2\" class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
+ Tst_WriteNumQst (Set.SetInd);
+ HTM_TD_End ();
+
+ /***** Title *****/
+ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
+ HTM_ARTICLE_Begin (Anchor);
+ Frm_StartFormAnchor (ActChgTitExaSet,Anchor);
+ ExaSet_PutParamsOneSet (Exams);
+ HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set.Title,
+ HTM_SUBMIT_ON_CHANGE,
+ "id=\"Title\" required=\"required\""
+ " class=\"TITLE_DESCRIPTION_WIDTH\"");
+ Frm_EndForm ();
+ HTM_ARTICLE_End ();
+ HTM_TD_End ();
+
+ /***** Current number of questions in set *****/
+ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
+ HTM_Unsigned (ExaSet_GetNumQstsInSet (Set.SetCod));
+ HTM_TD_End ();
+
+ /***** Number of questions to appear in exam *****/
+ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd);
+ Frm_StartFormAnchor (ActChgNumQstExaSet,Anchor);
+ ExaSet_PutParamsOneSet (Exams);
+ HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set.NumQstsToExam,
+ HTM_SUBMIT_ON_CHANGE,false,
+ "class=\"INPUT_LONG\" required=\"required\"");
+ Frm_EndForm ();
+ HTM_TD_End ();
+
+ /***** End first row *****/
+ HTM_TR_End ();
+
+ /***** Begin second row *****/
+ HTM_TR_Begin (NULL);
+
+ /***** Questions *****/
+ HTM_TD_Begin ("colspan=\"3\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
+
+ /* List questions */
+ ExaSet_ListSetQuestions (Exams,Exam,&Set);
+
+ HTM_TD_End ();
+
+ /***** End second row *****/
+ HTM_TR_End ();
+
+ /***** Free anchor string *****/
+ Frm_FreeAnchorStr (Anchor);
+ }
+
+ /***** End table *****/
+ HTM_TABLE_End ();
+ }
+
+/*****************************************************************************/
+/***************** Put table heading for sets of questions *******************/
+/*****************************************************************************/
+
+static void ExaSet_PutTableHeadingForSets (void)
+ {
+ extern const char *Txt_No_INDEX;
+ extern const char *Txt_Set_of_questions;
+ extern const char *Txt_Number_of_questions;
+ extern const char *Txt_Number_of_questions_in_the_exam;
+
+ /***** Begin row *****/
+ HTM_TR_Begin (NULL);
+
+ /***** Header cells *****/
+ HTM_TH_Empty (1);
+ HTM_TH (1,1,"RB",Txt_No_INDEX);
+ HTM_TH (1,1,"LB",Txt_Set_of_questions);
+ HTM_TH (1,1,"RB",Txt_Number_of_questions);
+ HTM_TH (1,1,"RB",Txt_Number_of_questions_in_the_exam);
+
+ /***** End row *****/
+ HTM_TR_End ();
+ }
+
+/*****************************************************************************/
+/*************************** Reset set of questions **************************/
+/*****************************************************************************/
+
+void ExaSet_ResetSet (struct ExaSet_Set *Set)
+ {
+ Set->ExaCod = -1L;
+ Set->SetCod = -1L;
+ Set->SetInd = 0;
+ Set->Title[0] = '\0';
+ Set->NumQstsToExam = 0;
+ }
+
+/*****************************************************************************/
+/********************* List exam questions for edition ***********************/
+/*****************************************************************************/
+
+static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams,
+ unsigned NumQsts,
+ MYSQL_RES *mysql_res,
+ bool ICanEditQuestions)
+ {
+ extern const char *Txt_Questions;
+ extern const char *Txt_No_INDEX;
+ extern const char *Txt_Code;
+ extern const char *Txt_Tags;
+ extern const char *Txt_Question;
+ unsigned NumQst;
+ MYSQL_ROW row;
+ struct Tst_Question Question;
+ bool QuestionExists;
+ char *Anchor;
+
+ /***** Build anchor string *****/
+ Frm_SetAnchorStr (Exams->SetCod,&Anchor);
+
+ /***** Write the heading *****/
+ HTM_TABLE_BeginWideMarginPadding (2);
+ HTM_TR_Begin (NULL);
+
+ HTM_TH_Empty (1);
+
+ HTM_TH (1,1,"CT",Txt_No_INDEX);
+ HTM_TH (1,1,"CT",Txt_Code);
+ HTM_TH (1,1,"CT",Txt_Tags);
+ HTM_TH (1,1,"CT",Txt_Question);
+
+ HTM_TR_End ();
+
+ /***** Write rows *****/
+ for (NumQst = 0;
+ NumQst < NumQsts;
+ NumQst++)
+ {
+ Gbl.RowEvenOdd = NumQst % 2;
+
+ /***** Create test question *****/
+ Tst_QstConstructor (&Question);
+
+ /***** Get question data *****/
+ row = mysql_fetch_row (mysql_res);
+ /*
+ row[0] QstCod
+ */
+ /* Get question code (row[0]) */
+ Exams->QstCod = Question.QstCod = Str_ConvertStrCodToLongCod (row[0]);
+
+ /***** Begin row *****/
+ HTM_TR_Begin (NULL);
+
+ /***** Icons *****/
+ HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd);
+
+ /* Put icon to remove the question */
+ if (ICanEditQuestions)
+ {
+ Frm_StartForm (ActReqRemSetQst);
+ ExaSet_PutParamsOneQst (Exams);
+ Ico_PutIconRemove ();
+ Frm_EndForm ();
+ }
+ else
+ Ico_PutIconRemovalNotAllowed ();
+
+ /* Put icon to edit the question */
+ if (ICanEditQuestions)
+ Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,
+ Tst_PutParamQstCod,&Question.QstCod);
+
+ HTM_TD_End ();
+
+ /***** Question *****/
+ QuestionExists = Tst_GetQstDataFromDB (&Question);
+ Tst_ListQuestionForEdition (&Question,NumQst + 1,QuestionExists,Anchor);
+
+ /***** End row *****/
+ HTM_TR_End ();
+
+ /***** Destroy test question *****/
+ Tst_QstDestructor (&Question);
+ }
+
+ /***** End table *****/
+ HTM_TABLE_End ();
+
+ /***** Free anchor string *****/
+ Frm_FreeAnchorStr (Anchor);
+ }
+
+/*****************************************************************************/
+/************* Add selected test questions to set of questions ***************/
+/*****************************************************************************/
+
+void ExaSet_AddQstsToSet (void)
+ {
+ extern const char *Txt_No_questions_have_been_added;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ char Txt[Cns_MAX_BYTES_TEXT + 1];
+ const char *Ptr;
+ char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
+ long QstCod;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Exam.ExaCod = Exams.ExaCod;
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ Exa_GetExamTxtFromDB (Exam.ExaCod,Txt);
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get selected questions *****/
+ /* Allocate space for selected question codes */
+ ExaSet_AllocateListSelectedQuestions (&Exams);
+
+ /* Get question codes */
+ Par_GetParMultiToText ("QstCods",Exams.ListQuestions,
+ ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS);
+
+ /* Check number of questions */
+ if (Tst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected...
+ {
+ /***** Insert questions in database *****/
+ Ptr = Exams.ListQuestions;
+ while (*Ptr)
+ {
+ /* Get next code */
+ Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
+ if (sscanf (LongStr,"%ld",&QstCod) != 1)
+ Lay_ShowErrorAndExit ("Wrong question code.");
+
+ /* Insert question in the table of questions */
+ DB_QueryINSERT ("can not add question to set",
+ "INSERT INTO exa_questions"
+ " (SetCod,QstCod)"
+ " VALUES"
+ " (%ld,%ld)",
+ Set.SetCod,QstCod);
+ }
+ }
+ else
+ Ale_ShowAlert (Ale_WARNING,Txt_No_questions_have_been_added);
+
+ /***** Free space for selected question codes *****/
+ ExaSet_FreeListsSelectedQuestions (&Exams);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/****************** Allocate memory for list of questions ********************/
+/*****************************************************************************/
+
+static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams)
+ {
+ if (!Exams->ListQuestions)
+ {
+ if ((Exams->ListQuestions = (char *) malloc (ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS + 1)) == NULL)
+ Lay_NotEnoughMemoryExit ();
+ Exams->ListQuestions[0] = '\0';
+ }
+ }
+
+/*****************************************************************************/
+/*********** Free memory used by list of selected question codes *************/
+/*****************************************************************************/
+
+static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams)
+ {
+ if (Exams->ListQuestions)
+ {
+ free (Exams->ListQuestions);
+ Exams->ListQuestions = NULL;
+ }
+ }
+
+/*****************************************************************************/
+/***************** Request the removal of a set of questions *****************/
+/*****************************************************************************/
+
+void ExaSet_RequestRemoveSet (void)
+ {
+ extern const char *Txt_Do_you_really_want_to_remove_the_set_of_questions_X;
+ extern const char *Txt_Remove_set_of_questions;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Show question and button to remove question *****/
+ Ale_ShowAlertAndButton (ActRemExaSet,NULL,NULL,
+ ExaSet_PutParamsOneSet,&Exams,
+ Btn_REMOVE_BUTTON,Txt_Remove_set_of_questions,
+ Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_set_of_questions_X,
+ Set.Title);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/************************* Remove a set of questions *************************/
+/*****************************************************************************/
+
+void ExaSet_RemoveSet (void)
+ {
+ extern const char *Txt_Set_of_questions_removed;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Remove the set from all the tables *****/
+ /* Remove questions associated to set */
+ DB_QueryDELETE ("can not remove questions associated to set",
+ "DELETE FROM exa_questions"
+ " USING exa_questions,exa_sets"
+ " WHERE exa_questions.SetCod=%ld"
+ " AND exa_questions.SetCod=exa_sets.SetCod"
+ " AND exa_sets.ExaCod=%ld", // Extra check
+ Set.SetCod,Set.ExaCod);
+
+ /* Remove the set itself */
+ DB_QueryDELETE ("can not remove set",
+ "DELETE FROM exa_sets"
+ " WHERE SetCod=%ld"
+ " AND ExaCod=%ld", // Extra check
+ Set.SetCod,Set.ExaCod);
+ if (!mysql_affected_rows (&Gbl.mysql))
+ Lay_ShowErrorAndExit ("The set to be removed does not exist.");
+
+ /* Change index of sets greater than this */
+ DB_QueryUPDATE ("can not update indexes of sets",
+ "UPDATE exa_sets SET SetInd=SetInd-1"
+ " WHERE ExaCod=%ld AND SetInd>%u",
+ Set.ExaCod,Set.SetInd);
+
+ /***** Write message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_Set_of_questions_removed);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/************ Move up position of a set of questions in an exam **************/
+/*****************************************************************************/
+
+void ExaSet_MoveUpSet (void)
+ {
+ extern const char *Txt_Movement_not_allowed;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ unsigned SetIndTop;
+ unsigned SetIndBottom;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get set index *****/
+ SetIndBottom = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod);
+
+ /***** Move up set *****/
+ if (SetIndBottom > 1)
+ {
+ /* Indexes of sets to be exchanged */
+ SetIndTop = ExaSet_GetPrevSetIndexInExam (Exam.ExaCod,SetIndBottom);
+ if (!SetIndTop)
+ Lay_ShowErrorAndExit ("Wrong index of set.");
+
+ /* Exchange sets */
+ ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom);
+ }
+ else
+ Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/*********** Move down position of a set of questions in an exam *************/
+/*****************************************************************************/
+
+void ExaSet_MoveDownSet (void)
+ {
+ extern const char *Txt_Movement_not_allowed;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ unsigned SetIndTop;
+ unsigned SetIndBottom;
+ unsigned MaxSetInd; // 0 if no sets
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get set index *****/
+ SetIndTop = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod);
+
+ /***** Get maximum set index *****/
+ MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam.ExaCod);
+
+ /***** Move down set *****/
+ if (SetIndTop < MaxSetInd)
+ {
+ /* Indexes of sets to be exchanged */
+ SetIndBottom = ExaSet_GetNextSetIndexInExam (Exam.ExaCod,SetIndTop);
+ if (!SetIndBottom)
+ Lay_ShowErrorAndExit ("Wrong index of set.");
+
+ /* Exchange sets */
+ ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom);
+ }
+ else
+ Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/********************** Request the removal of a question ********************/
+/*****************************************************************************/
+
+void ExaSet_RequestRemoveQstFromSet (void)
+ {
+ extern const char *Txt_Do_you_really_want_to_remove_the_question_X;
+ extern const char *Txt_Remove_question;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ char *Anchor;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get question index *****/
+ Exams.QstCod = Tst_GetParamQstCod ();
+
+ /***** Build anchor string *****/
+ Frm_SetAnchorStr (Set.SetCod,&Anchor);
+
+ /***** Show question and button to remove question *****/
+ Ale_ShowAlertAndButton (ActRemExaQst,Anchor,NULL,
+ ExaSet_PutParamsOneQst,&Exams,
+ Btn_REMOVE_BUTTON,Txt_Remove_question,
+ Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_question_X,
+ Exams.QstCod);
+
+ /***** Free anchor string *****/
+ Frm_FreeAnchorStr (Anchor);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/****************************** Remove a question ****************************/
+/*****************************************************************************/
+
+void ExaSet_RemoveQstFromSet (void)
+ {
+ extern const char *Txt_Question_removed;
+ struct Exa_Exams Exams;
+ struct Exa_Exam Exam;
+ struct ExaSet_Set Set;
+ long QstCod;
+
+ /***** Reset exams context *****/
+ Exa_ResetExams (&Exams);
+ Exa_ResetExam (&Exam);
+ ExaSet_ResetSet (&Set);
+
+ /***** Get parameters *****/
+ Exa_GetParams (&Exams);
+ if (Exams.ExaCod <= 0)
+ Lay_WrongExamExit ();
+ Set.ExaCod = Exam.ExaCod = Exams.ExaCod;
+ Set.SetCod = ExaSet_GetParamSetCod ();
+ if (Set.SetCod <= 0)
+ Lay_WrongSetExit ();
+
+ /***** Get exam data from database *****/
+ Exa_GetDataOfExamByCod (&Exam);
+ Exams.ExaCod = Exam.ExaCod;
+ if (!Exa_CheckIfEditable (&Exam))
+ Lay_NoPermissionExit ();
+
+ /***** Get set data from database *****/
+ ExaSet_GetDataOfSetByCod (&Set);
+ Exams.SetCod = Set.SetCod;
+
+ /***** Get question index *****/
+ QstCod = Tst_GetParamQstCod ();
+
+ /***** Remove the question from set *****/
+ /* Remove the question itself */
+ DB_QueryDELETE ("can not remove a question from a set",
+ "DELETE FROM exa_questions"
+ " WHERE SetCod=%ld AND QstCod=%ld",
+ Set.SetCod,QstCod);
+ if (!mysql_affected_rows (&Gbl.mysql))
+ Lay_ShowErrorAndExit ("The question to be removed does not exist.");
+
+ /***** Write message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_Question_removed);
+
+ /***** Show current exam and its sets *****/
+ Exa_PutFormsOneExam (&Exams,&Exam,&Set,
+ false); // It's not a new exam
+ }
+
+/*****************************************************************************/
+/*********** Exchange the order of two consecutive sets in an exam ***********/
+/*****************************************************************************/
+
+static void ExaSet_ExchangeSets (long ExaCod,
+ unsigned SetIndTop,unsigned SetIndBottom)
+ {
+ long SetCodTop;
+ long SetCodBottom;
+
+ /***** Lock table to make the move atomic *****/
+ DB_Query ("can not lock tables to exchange sets of questions",
+ "LOCK TABLES exa_sets WRITE");
+ Gbl.DB.LockedTables = true;
+
+ /***** Get set codes of the sets to be moved *****/
+ SetCodTop = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndTop);
+ SetCodBottom = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndBottom);
+
+ /***** Exchange indexes of sets *****/
+ /*
+ Example:
+ SetIndTop = 1; SetCodTop = 218
+ SetIndBottom = 2; SetCodBottom = 220
+ Step 1 Step 2 Step 3
++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
+| SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod |
++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
+| 1 | 218 |>| -2 | 218 |>| -2 | 218 |>| 2 | 218 |
+| 2 | 220 | | 2 | 220 | | 1 | 220 | | 1 | 220 |
+| 3 | 232 | | 3 | 232 | | 3 | 232 | | 3 | 232 |
++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+
+ */
+ /* Step 1: change temporarily top index to minus bottom index
+ in order to not repeat unique index (ExaCod,SetInd) */
+ DB_QueryUPDATE ("can not exchange indexes of sets",
+ "UPDATE exa_sets SET SetInd=-%u"
+ " WHERE ExaCod=%ld AND SetCod=%ld",
+ SetIndBottom,
+ ExaCod,SetCodTop);
+
+ /* Step 2: change bottom index to old top index */
+ DB_QueryUPDATE ("can not exchange indexes of sets",
+ "UPDATE exa_sets SET SetInd=%u"
+ " WHERE ExaCod=%ld AND SetCod=%ld",
+ SetIndTop,
+ ExaCod,SetCodBottom);
+
+ /* Step 3: change top index to old bottom index */
+ DB_QueryUPDATE ("can not exchange indexes of sets",
+ "UPDATE exa_sets SET SetInd=%u"
+ " WHERE ExaCod=%ld AND SetCod=%ld",
+ SetIndBottom,
+ ExaCod,SetCodTop);
+
+ /***** Unlock table *****/
+ Gbl.DB.LockedTables = false; // Set to false before the following unlock...
+ // ...to not retry the unlock if error in unlocking
+ DB_Query ("can not unlock tables after exchanging sets of questions",
+ "UNLOCK TABLES");
+ }
+
+/*****************************************************************************/
+/***************** Put icon to add a new questions to exam *******************/
+/*****************************************************************************/
+
+static void ExaSet_PutIconToAddNewQuestions (void *Exams)
+ {
+ extern const char *Txt_Add_questions;
+
+ /***** Put form to create a new question *****/
+ Ico_PutContextualIconToAdd (ActReqAddQstExaSet,NULL,
+ Exa_PutParams,Exams,
+ Txt_Add_questions);
+ }
+
+/*****************************************************************************/
+/***************** Put button to add new questions to exam *******************/
+/*****************************************************************************/
+
+static void ExaSet_PutButtonToAddNewQuestions (struct Exa_Exams *Exams)
+ {
+ extern const char *Txt_Add_questions;
+
+ Frm_StartForm (ActReqAddQstExaSet);
+ ExaSet_PutParamsOneSet (Exams);
+ Btn_PutConfirmButtonInline (Txt_Add_questions);
+ Frm_EndForm ();
+ }
diff --git a/swad_exam_set.h b/swad_exam_set.h
new file mode 100644
index 00000000..592d2811
--- /dev/null
+++ b/swad_exam_set.h
@@ -0,0 +1,75 @@
+// swad_exam_set.h: set of questions in exams
+
+#ifndef _SWAD_EXA_SET
+#define _SWAD_EXA_SET
+/*
+ SWAD (Shared Workspace At a Distance),
+ is a web platform developed at the University of Granada (Spain),
+ and used to support university teaching.
+
+ This file is part of SWAD core.
+ Copyright (C) 1999-2020 Antonio Caņas Vargas
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General 3 License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+// #include "swad_date.h"
+// #include "swad_exam_event.h"
+#include "swad_exam_type.h"
+// #include "swad_scope.h"
+
+/*****************************************************************************/
+/************************** Public types and constants ***********************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/***************************** Public prototypes *****************************/
+/*****************************************************************************/
+
+void ExaSet_PutParamsOneSet (void *Exams);
+long ExaSet_GetParamSetCod (void);
+
+void ExaSet_ReceiveFormSet (void);
+void ExaSet_ChangeSetTitle (void);
+void ExaSet_ChangeNumQstsToExam (void);
+
+unsigned ExaSet_GetNumSetsExam (long ExaCod);
+unsigned ExaSet_GetNumQstsExam (long ExaCod);
+
+void ExaSet_RequestCreatOrEditSet (void);
+void ExaSet_ReqSelectQstsToAddToSet (void);
+void ExaSet_ListQstsToAddToSet (void);
+
+void ExaSet_ListExamSets (struct Exa_Exams *Exams,
+ struct Exa_Exam *Exam,
+ struct ExaSet_Set *Set);
+
+void ExaSet_ResetSet (struct ExaSet_Set *Set);
+
+void ExaSet_AddQstsToSet (void);
+
+void ExaSet_RequestRemoveSet (void);
+void ExaSet_RemoveSet (void);
+
+void ExaSet_MoveUpSet (void);
+void ExaSet_MoveDownSet (void);
+
+void ExaSet_RequestRemoveQstFromSet (void);
+void ExaSet_RemoveQstFromSet (void);
+
+#endif
diff --git a/swad_test.c b/swad_test.c
index 0322ea96..a1db9219 100644
--- a/swad_test.c
+++ b/swad_test.c
@@ -40,6 +40,7 @@
#include "swad_action.h"
#include "swad_box.h"
#include "swad_database.h"
+#include "swad_exam_set.h"
#include "swad_figure.h"
#include "swad_form.h"
#include "swad_global.h"