swad-core/swad_degree_type.c

1066 lines
38 KiB
C

// swad_degree_type.c: degree types
/*
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-2019 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 Public 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 <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <ctype.h> // For isprint, isspace, etc.
#include <linux/stddef.h> // For NULL
#include <stdbool.h> // For boolean type
#include <stdio.h> // For fprintf, etc.
#include <stdlib.h> // For exit, system, calloc, free, etc.
#include <string.h> // For string functions
#include <mysql/mysql.h> // To access MySQL databases
#include "swad_box.h"
#include "swad_config.h"
#include "swad_database.h"
#include "swad_degree.h"
#include "swad_degree_type.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_parameter.h"
#include "swad_table.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/**************************** Public constants *******************************/
/*****************************************************************************/
/*****************************************************************************/
/****************************** Private types ********************************/
/*****************************************************************************/
/*****************************************************************************/
/**************************** Private variables ******************************/
/*****************************************************************************/
static struct DegreeType *DT_EditingDegTyp = NULL; // Static variable to keep the degree type being edited
/*****************************************************************************/
/*************************** Private prototypes ******************************/
/*****************************************************************************/
static void DT_SeeDegreeTypes (Act_Action_t NextAction,Hie_Level_t Scope,
DT_Order_t DefaultOrder);
static DT_Order_t DT_GetParamDegTypOrder (DT_Order_t DefaultOrder);
static void DT_ListDegreeTypes (Act_Action_t NextAction,DT_Order_t SelectedOrder);
static void DT_EditDegreeTypesInternal (void);
static void DT_PutIconsEditingDegreeTypes (void);
static void DT_ListDegreeTypesForSeeing (void);
static void DT_PutIconsListingDegTypes (void);
static void DT_PutIconToEditDegTypes (void);
static void DT_ListDegreeTypesForEdition (void);
static void DT_PutFormToCreateDegreeType (void);
static void DT_PutHeadDegreeTypesForSeeing (Act_Action_t NextAction,DT_Order_t SelectedOrder);
static void DT_PutHeadDegreeTypesForEdition (void);
static void DT_CreateDegreeType (struct DegreeType *DegTyp);
static void DT_PutParamOtherDegTypCod (long DegTypCod);
static unsigned DT_CountNumDegsOfType (long DegTypCod);
static void DT_RemoveDegreeTypeCompletely (long DegTypCod);
static bool DT_CheckIfDegreeTypeNameExists (const char *DegTypName,long DegTypCod);
static void DT_EditingDegreeTypeConstructor (void);
static void DT_EditingDegreeTypeDestructor (void);
/*****************************************************************************/
/************** Show selector of degree types for statistics *****************/
/*****************************************************************************/
void DT_WriteSelectorDegreeTypes (void)
{
extern const char *Txt_Any_type_of_degree;
unsigned NumDegTyp;
/***** Form to select degree types *****/
/* Get list of degree types */
DT_GetListDegreeTypes (Hie_SYS,DT_ORDER_BY_DEGREE_TYPE);
/* List degree types */
fprintf (Gbl.F.Out,"<select id=\"OthDegTypCod\" name=\"OthDegTypCod\""
" onchange=\"document.getElementById('%s').submit();\">",
Gbl.Form.Id);
fprintf (Gbl.F.Out,"<option value=\"-1\"");
if (Gbl.Stat.DegTypCod == -1L)
fprintf (Gbl.F.Out," selected=\"selected\"");
fprintf (Gbl.F.Out,">%s</option>",Txt_Any_type_of_degree);
for (NumDegTyp = 0;
NumDegTyp < Gbl.DegTypes.Num;
NumDegTyp++)
{
fprintf (Gbl.F.Out,"<option value=\"%ld\"",Gbl.DegTypes.Lst[NumDegTyp].DegTypCod );
if (Gbl.DegTypes.Lst[NumDegTyp].DegTypCod == Gbl.Stat.DegTypCod)
fprintf (Gbl.F.Out," selected=\"selected\"");
fprintf (Gbl.F.Out,">%s</option>",Gbl.DegTypes.Lst[NumDegTyp].DegTypName);
}
fprintf (Gbl.F.Out,"</select>");
/***** Free list of degree types *****/
DT_FreeListDegreeTypes ();
}
/*****************************************************************************/
/***************************** Show degree types *****************************/
/*****************************************************************************/
void DT_SeeDegreeTypesInDegTab (void)
{
DT_SeeDegreeTypes (ActSeeDegTyp,Hie_SYS,
DT_ORDER_BY_DEGREE_TYPE); // Default order if not specified
}
void DT_SeeDegreeTypesInStaTab (void)
{
DT_SeeDegreeTypes (ActSeeUseGbl,Gbl.Scope.Current,
DT_ORDER_BY_NUM_DEGREES); // Default order if not specified
}
static void DT_SeeDegreeTypes (Act_Action_t NextAction,Hie_Level_t Scope,
DT_Order_t DefaultOrder)
{
DT_Order_t SelectedOrder;
/***** Get parameter with the type of order in the list of degree types *****/
SelectedOrder = DT_GetParamDegTypOrder (DefaultOrder);
/***** Get list of degree types *****/
DT_GetListDegreeTypes (Scope,SelectedOrder);
/***** List degree types *****/
DT_ListDegreeTypes (NextAction,SelectedOrder);
/***** Free list of degree types *****/
DT_FreeListDegreeTypes ();
}
/*****************************************************************************/
/******* Get parameter with the type or order in list of degree types ********/
/*****************************************************************************/
static DT_Order_t DT_GetParamDegTypOrder (DT_Order_t DefaultOrder)
{
return (DT_Order_t) Par_GetParToUnsignedLong ("Order",
0,
DT_NUM_ORDERS - 1,
(unsigned long) DefaultOrder);
}
/*****************************************************************************/
/***************************** List degree types *****************************/
/*****************************************************************************/
// This function can be called from:
// - centre tab => NextAction = ActSeeDegTyp
// - statistic tab => NextAction = ActSeeUseGbl
static void DT_ListDegreeTypes (Act_Action_t NextAction,DT_Order_t SelectedOrder)
{
extern const char *Hlp_CENTRE_DegreeTypes;
extern const char *Hlp_ANALYTICS_Figures_types_of_degree;
extern const char *Txt_Types_of_degree;
extern const char *Txt_No_types_of_degree;
extern const char *Txt_Create_another_type_of_degree;
extern const char *Txt_Create_type_of_degree;
/***** Start box *****/
switch (NextAction)
{
case ActSeeDegTyp:
Box_StartBox (NULL,Txt_Types_of_degree,DT_PutIconsListingDegTypes,
Hlp_CENTRE_DegreeTypes,Box_NOT_CLOSABLE);
break;
case ActSeeUseGbl:
Box_StartBox (NULL,Txt_Types_of_degree,DT_PutIconToEditDegTypes,
Hlp_ANALYTICS_Figures_types_of_degree,Box_NOT_CLOSABLE);
break;
default: // Bad call
return;
}
if (Gbl.DegTypes.Num)
{
/***** Write heading *****/
Tbl_StartTableWideMargin (2);
DT_PutHeadDegreeTypesForSeeing (NextAction,SelectedOrder);
/***** List current degree types for seeing *****/
DT_ListDegreeTypesForSeeing ();
/***** End table *****/
Tbl_EndTable ();
}
else // No degree types created
Ale_ShowAlert (Ale_INFO,Txt_No_types_of_degree);
/***** Button to create degree type *****/
if (DT_CheckIfICanCreateDegreeTypes ())
{
Frm_StartForm (ActEdiDegTyp);
Btn_PutConfirmButton (Gbl.DegTypes.Num ? Txt_Create_another_type_of_degree :
Txt_Create_type_of_degree);
Frm_EndForm ();
}
/***** End box *****/
Box_EndBox ();
}
/*****************************************************************************/
/************************ Put forms to edit degree types *********************/
/*****************************************************************************/
void DT_EditDegreeTypes (void)
{
/***** Degree type constructor *****/
DT_EditingDegreeTypeConstructor ();
/***** Edit degree types *****/
DT_EditDegreeTypesInternal ();
/***** Degree type destructor *****/
DT_EditingDegreeTypeDestructor ();
}
static void DT_EditDegreeTypesInternal (void)
{
extern const char *Hlp_CENTRE_DegreeTypes_edit;
extern const char *Txt_Types_of_degree;
/***** Get list of degree types *****/
DT_GetListDegreeTypes (Hie_SYS,DT_ORDER_BY_DEGREE_TYPE);
/***** Start box *****/
Box_StartBox (NULL,Txt_Types_of_degree,DT_PutIconsEditingDegreeTypes,
Hlp_CENTRE_DegreeTypes_edit,Box_NOT_CLOSABLE);
/***** Put a form to create a new degree type *****/
DT_PutFormToCreateDegreeType ();
/***** Forms to edit current degree types *****/
if (Gbl.DegTypes.Num)
DT_ListDegreeTypesForEdition ();
/***** End box *****/
Box_EndBox ();
/***** Free list of degree types *****/
DT_FreeListDegreeTypes ();
}
/*****************************************************************************/
/************ Put contextual icons when editing degree types *****************/
/*****************************************************************************/
static void DT_PutIconsEditingDegreeTypes (void)
{
/***** Put icon to viee degree types *****/
DT_PutIconToViewDegreeTypes ();
/***** Put icon to view degrees *****/
Deg_PutIconToViewDegrees ();
/***** Put icon to show a figure *****/
Gbl.Figures.FigureType = Fig_DEGREE_TYPES;
Fig_PutIconToShowFigure ();
}
/*****************************************************************************/
/******************* Put link (form) to view degree types ********************/
/*****************************************************************************/
void DT_PutIconToViewDegreeTypes (void)
{
extern const char *Txt_Types_of_degree;
Lay_PutContextualLinkOnlyIcon (ActSeeDegTyp,NULL,NULL,
"sitemap.svg",
Txt_Types_of_degree);
}
/*****************************************************************************/
/******************* List current degree types for seeing ********************/
/*****************************************************************************/
static void DT_ListDegreeTypesForSeeing (void)
{
unsigned NumDegTyp;
const char *BgColor;
/***** List degree types with forms for edition *****/
for (NumDegTyp = 0;
NumDegTyp < Gbl.DegTypes.Num;
NumDegTyp++)
{
BgColor = (Gbl.DegTypes.Lst[NumDegTyp].DegTypCod ==
Gbl.Hierarchy.Deg.DegTypCod) ? "LIGHT_BLUE" :
Gbl.ColorRows[Gbl.RowEvenOdd];
/* Number of degree type in this list */
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"DAT_N RIGHT_MIDDLE %s\">"
"%u"
"</td>",
BgColor,NumDegTyp + 1);
/* Name of degree type */
fprintf (Gbl.F.Out,"<td class=\"DAT_N LEFT_MIDDLE %s\">"
"%s"
"</td>",
BgColor,Gbl.DegTypes.Lst[NumDegTyp].DegTypName);
/* Number of degrees of this type */
fprintf (Gbl.F.Out,"<td class=\"DAT_N RIGHT_MIDDLE %s\">"
"%u"
"</td>"
"</tr>",
BgColor,Gbl.DegTypes.Lst[NumDegTyp].NumDegs);
Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd;
}
}
/*****************************************************************************/
/************** Put contextual icons in list of degree types *****************/
/*****************************************************************************/
static void DT_PutIconsListingDegTypes (void)
{
/***** Put icon to edit degree types *****/
DT_PutIconToEditDegTypes ();
/***** Put icon to view degrees *****/
Deg_PutIconToViewDegrees ();
/***** Put icon to show a figure *****/
Gbl.Figures.FigureType = Fig_DEGREE_TYPES;
Fig_PutIconToShowFigure ();
}
/*****************************************************************************/
/******************* Put link (form) to edit degree types ********************/
/*****************************************************************************/
static void DT_PutIconToEditDegTypes (void)
{
if (Gbl.Hierarchy.Level == Hie_CTR && // Only editable if centre tab is visible
DT_CheckIfICanCreateDegreeTypes ())
Ico_PutContextualIconToEdit (ActEdiDegTyp,NULL);
}
/*****************************************************************************/
/******************* List current degree types for edition *******************/
/*****************************************************************************/
static void DT_ListDegreeTypesForEdition (void)
{
unsigned NumDegTyp;
/***** Write heading *****/
Tbl_StartTableWide (2);
DT_PutHeadDegreeTypesForEdition ();
/***** List degree types with forms for edition *****/
for (NumDegTyp = 0;
NumDegTyp < Gbl.DegTypes.Num;
NumDegTyp++)
{
/* Put icon to remove degree type */
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"BM\">");
if (Gbl.DegTypes.Lst[NumDegTyp].NumDegs) // Degree type has degrees => deletion forbidden
Ico_PutIconRemovalNotAllowed ();
else
{
Frm_StartForm (ActRemDegTyp);
DT_PutParamOtherDegTypCod (Gbl.DegTypes.Lst[NumDegTyp].DegTypCod);
Ico_PutIconRemove ();
Frm_EndForm ();
}
/* Degree type code */
fprintf (Gbl.F.Out,"</td>"
"<td class=\"DAT CODE\">"
"%ld"
"</td>",
Gbl.DegTypes.Lst[NumDegTyp].DegTypCod);
/* Name of degree type */
fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">");
Frm_StartForm (ActRenDegTyp);
DT_PutParamOtherDegTypCod (Gbl.DegTypes.Lst[NumDegTyp].DegTypCod);
fprintf (Gbl.F.Out,"<input type=\"text\" name=\"DegTypName\""
" size=\"25\" maxlength=\"%u\" value=\"%s\""
" required=\"required\""
" onchange=\"document.getElementById('%s').submit();\" />",
Deg_MAX_CHARS_DEGREE_TYPE_NAME,
Gbl.DegTypes.Lst[NumDegTyp].DegTypName,
Gbl.Form.Id);
Frm_EndForm ();
fprintf (Gbl.F.Out,"</td>");
/* Number of degrees of this type */
fprintf (Gbl.F.Out,"<td class=\"DAT RIGHT_MIDDLE\">"
"%u"
"</td>"
"</tr>",
Gbl.DegTypes.Lst[NumDegTyp].NumDegs);
}
/***** End table *****/
Tbl_EndTable ();
}
/*****************************************************************************/
/******************** Check if I can create degree types *********************/
/*****************************************************************************/
bool DT_CheckIfICanCreateDegreeTypes (void)
{
return (Gbl.Usrs.Me.Role.Logged == Rol_SYS_ADM);
}
/*****************************************************************************/
/******************** Put a form to create a new degree type *****************/
/*****************************************************************************/
static void DT_PutFormToCreateDegreeType (void)
{
extern const char *Txt_New_type_of_degree;
extern const char *Txt_Create_type_of_degree;
/***** Start form *****/
Frm_StartForm (ActNewDegTyp);
/***** Start box and table *****/
Box_StartBoxTable (NULL,Txt_New_type_of_degree,NULL,
NULL,Box_NOT_CLOSABLE,2);
/***** Write heading *****/
DT_PutHeadDegreeTypesForEdition ();
/***** Column to remove degree type, disabled here *****/
fprintf (Gbl.F.Out,"<tr>"
"<td class=\"BM\"></td>");
/***** Degree type code *****/
fprintf (Gbl.F.Out,"<td class=\"CODE\"></td>");
/***** Degree type name *****/
fprintf (Gbl.F.Out,"<td class=\"LEFT_MIDDLE\">"
"<input type=\"text\" name=\"DegTypName\""
" size=\"25\" maxlength=\"%u\" value=\"%s\""
" required=\"required\" />"
"</td>",
Deg_MAX_CHARS_DEGREE_TYPE_NAME,DT_EditingDegTyp->DegTypName);
/***** Number of degrees of this degree type ****/
fprintf (Gbl.F.Out,"<td class=\"DAT RIGHT_MIDDLE\">"
"0"
"</td>"
"</tr>");
/***** End table, send button and end box *****/
Box_EndBoxTableWithButton (Btn_CREATE_BUTTON,Txt_Create_type_of_degree);
/***** End form *****/
Frm_EndForm ();
}
/*****************************************************************************/
/***************** Write header with fields of a degree type *****************/
/*****************************************************************************/
static void DT_PutHeadDegreeTypesForSeeing (Act_Action_t NextAction,DT_Order_t SelectedOrder)
{
extern const char *Txt_DEGREE_TYPES_HELP_ORDER[DT_NUM_ORDERS];
extern const char *Txt_DEGREE_TYPES_ORDER[DT_NUM_ORDERS];
DT_Order_t Order;
fprintf (Gbl.F.Out,"<tr>"
"<th></th>");
for (Order = DT_ORDER_BY_DEGREE_TYPE;
Order <= DT_ORDER_BY_NUM_DEGREES;
Order++)
{
fprintf (Gbl.F.Out,"<th class=\"%s\">",
Order == DT_ORDER_BY_DEGREE_TYPE ? "LEFT_MIDDLE" :
"RIGHT_MIDDLE");
/* Start form to change order */
Frm_StartForm (NextAction);
if (NextAction == ActSeeUseGbl)
Fig_PutHiddenParamFigures ();
Par_PutHiddenParamUnsigned ("Order",(unsigned) Order);
/* Link with the head of this column */
Frm_LinkFormSubmit (Txt_DEGREE_TYPES_HELP_ORDER[Order],"TIT_TBL",NULL);
if (Order == SelectedOrder)
fprintf (Gbl.F.Out,"<u>");
fprintf (Gbl.F.Out,"%s",Txt_DEGREE_TYPES_ORDER[Order]);
if (Order == SelectedOrder)
fprintf (Gbl.F.Out,"</u>");
fprintf (Gbl.F.Out,"</a>");
/* End form */
Frm_EndForm ();
fprintf (Gbl.F.Out,"</th>");
}
}
/*****************************************************************************/
/***************** Write header with fields of a degree type *****************/
/*****************************************************************************/
static void DT_PutHeadDegreeTypesForEdition (void)
{
extern const char *Txt_Code;
extern const char *Txt_Type_of_degree;
extern const char *Txt_Degrees;
fprintf (Gbl.F.Out,"<tr>"
"<th class=\"BM\"></th>"
"<th class=\"CENTER_MIDDLE\">"
"%s"
"</th>"
"<th class=\"CENTER_MIDDLE\">"
"%s"
"</th>"
"<th class=\"RIGHT_MIDDLE\">"
"%s"
"</th>"
"</tr>",
Txt_Code,
Txt_Type_of_degree,
Txt_Degrees);
}
/*****************************************************************************/
/************************** Create a new degree type *************************/
/*****************************************************************************/
static void DT_CreateDegreeType (struct DegreeType *DegTyp)
{
/***** Create a new degree type *****/
DB_QueryINSERT ("can not create a new type of degree",
"INSERT INTO deg_types SET DegTypName='%s'",
DegTyp->DegTypName);
}
/*****************************************************************************/
/**************** Create a list with all the degree types ********************/
/*****************************************************************************/
void DT_GetListDegreeTypes (Hie_Level_t Scope,DT_Order_t Order)
{
static const char *OrderBySubQuery[DT_NUM_ORDERS] =
{
"DegTypName", // DT_ORDER_BY_DEGREE_TYPE
"NumDegs DESC,DegTypName", // DT_ORDER_BY_NUM_DEGREES
};
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRow;
/***** Get types of degree from database *****/
switch (Scope)
{
case Hie_SYS:
/* Get
all degree types with degrees
union with
all degree types without any degree */
Gbl.DegTypes.Num = (unsigned) DB_QuerySELECT (&mysql_res,"can not get types of degree",
"(SELECT deg_types.DegTypCod,deg_types.DegTypName,"
"COUNT(degrees.DegCod) AS NumDegs"
" FROM degrees,deg_types"
" WHERE degrees.DegTypCod=deg_types.DegTypCod"
" GROUP BY degrees.DegTypCod)"
" UNION "
"(SELECT DegTypCod,DegTypName,0 AS NumDegs" // Do not use '0' because NumDegs will be casted to string and order will be wrong
" FROM deg_types"
" WHERE DegTypCod NOT IN"
" (SELECT DegTypCod FROM degrees))"
" ORDER BY %s",
OrderBySubQuery[Order]);
break;
case Hie_CTY:
/* Get only degree types with degrees in the current country */
Gbl.DegTypes.Num = (unsigned) DB_QuerySELECT (&mysql_res,"can not get types of degree",
"SELECT deg_types.DegTypCod,deg_types.DegTypName,"
"COUNT(degrees.DegCod) AS NumDegs"
" FROM institutions,centres,degrees,deg_types"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegTypCod=deg_types.DegTypCod"
" GROUP BY degrees.DegTypCod"
" ORDER BY %s",
Gbl.Hierarchy.Cty.CtyCod,
OrderBySubQuery[Order]);
break;
case Hie_INS:
/* Get only degree types with degrees in the current institution */
Gbl.DegTypes.Num = (unsigned) DB_QuerySELECT (&mysql_res,"can not get types of degree",
"SELECT deg_types.DegTypCod,deg_types.DegTypName,"
"COUNT(degrees.DegCod) AS NumDegs"
" FROM centres,degrees,deg_types"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegTypCod=deg_types.DegTypCod"
" GROUP BY degrees.DegTypCod"
" ORDER BY %s",
Gbl.Hierarchy.Ins.InsCod,
OrderBySubQuery[Order]);
break;
case Hie_CTR:
/* Get only degree types with degrees in the current centre */
Gbl.DegTypes.Num = (unsigned) DB_QuerySELECT (&mysql_res,"can not get types of degree",
"SELECT deg_types.DegTypCod,deg_types.DegTypName,"
"COUNT(degrees.DegCod) AS NumDegs"
" FROM degrees,deg_types"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegTypCod=deg_types.DegTypCod"
" GROUP BY degrees.DegTypCod"
" ORDER BY %s",
Gbl.Hierarchy.Ctr.CtrCod,
OrderBySubQuery[Order]);
break;
case Hie_DEG:
case Hie_CRS:
/* Get only degree types with degrees in the current degree */
Gbl.DegTypes.Num = (unsigned) DB_QuerySELECT (&mysql_res,"can not get types of degree",
"SELECT deg_types.DegTypCod,deg_types.DegTypName,"
"COUNT(degrees.DegCod) AS NumDegs"
" FROM degrees,deg_types"
" WHERE degrees.DegCod=%ld"
" AND degrees.DegTypCod=deg_types.DegTypCod"
" GROUP BY degrees.DegTypCod"
" ORDER BY %s",
Gbl.Hierarchy.Deg.DegCod,
OrderBySubQuery[Order]);
break;
default:
Lay_WrongScopeExit ();
break;
}
/***** Get degree types *****/
if (Gbl.DegTypes.Num)
{
/***** Create a list of degree types *****/
if ((Gbl.DegTypes.Lst = (struct DegreeType *)
calloc (Gbl.DegTypes.Num,
sizeof (struct DegreeType))) == NULL)
Lay_NotEnoughMemoryExit ();
/***** Get degree types *****/
for (NumRow = 0;
NumRow < Gbl.DegTypes.Num;
NumRow++)
{
/* Get next degree type */
row = mysql_fetch_row (mysql_res);
/* Get degree type code (row[0]) */
if ((Gbl.DegTypes.Lst[NumRow].DegTypCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of type of degree.");
/* Get degree type name (row[1]) */
Str_Copy (Gbl.DegTypes.Lst[NumRow].DegTypName,row[1],
Deg_MAX_BYTES_DEGREE_TYPE_NAME);
/* Number of degrees of this type (row[2]) */
if (sscanf (row[2],"%u",&Gbl.DegTypes.Lst[NumRow].NumDegs) != 1)
Lay_ShowErrorAndExit ("Error when getting number of degrees of a type");
}
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/********* Free list of degree types and list of degrees of each type ********/
/*****************************************************************************/
void DT_FreeListDegreeTypes (void)
{
/***** Free memory used by the list of degree types *****/
if (Gbl.DegTypes.Lst)
{
free ((void *) Gbl.DegTypes.Lst);
Gbl.DegTypes.Lst = NULL;
Gbl.DegTypes.Num = 0;
}
}
/*****************************************************************************/
/***************** Receive form to create a new degree type ******************/
/*****************************************************************************/
void DT_RecFormNewDegreeType (void)
{
extern const char *Txt_The_type_of_degree_X_already_exists;
extern const char *Txt_Created_new_type_of_degree_X;
extern const char *Txt_You_must_specify_the_name_of_the_new_type_of_degree;
/***** Degree type constructor *****/
DT_EditingDegreeTypeConstructor ();
/***** Get parameters from form *****/
/* Get the name of degree type */
Par_GetParToText ("DegTypName",DT_EditingDegTyp->DegTypName,Deg_MAX_BYTES_DEGREE_TYPE_NAME);
if (DT_EditingDegTyp->DegTypName[0]) // If there's a degree type name
{
/***** If name of degree type was in database... *****/
if (DT_CheckIfDegreeTypeNameExists (DT_EditingDegTyp->DegTypName,-1L))
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_The_type_of_degree_X_already_exists,
DT_EditingDegTyp->DegTypName);
else // Add new degree type to database
{
DT_CreateDegreeType (DT_EditingDegTyp);
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_Created_new_type_of_degree_X,
DT_EditingDegTyp->DegTypName);
}
}
else // If there is not a degree type name
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_You_must_specify_the_name_of_the_new_type_of_degree);
}
/*****************************************************************************/
/**************************** Remove a degree type ***************************/
/*****************************************************************************/
void DT_RemoveDegreeType (void)
{
extern const char *Txt_To_remove_a_type_of_degree_you_must_first_remove_all_degrees_of_that_type;
extern const char *Txt_Type_of_degree_X_removed;
/***** Degree type constructor *****/
DT_EditingDegreeTypeConstructor ();
/***** Get the code of the degree type *****/
DT_EditingDegTyp->DegTypCod = DT_GetAndCheckParamOtherDegTypCod (1);
/***** Get data of the degree type from database *****/
if (!DT_GetDataOfDegreeTypeByCod (DT_EditingDegTyp))
Lay_ShowErrorAndExit ("Code of type of degree not found.");
/***** Check if this degree type has degrees *****/
if (DT_EditingDegTyp->NumDegs) // Degree type has degrees => don't remove
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_To_remove_a_type_of_degree_you_must_first_remove_all_degrees_of_that_type);
else // Degree type has no degrees => remove it
{
/***** Remove degree type *****/
DT_RemoveDegreeTypeCompletely (DT_EditingDegTyp->DegTypCod);
/***** Write message to show the change made *****/
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_Type_of_degree_X_removed,
DT_EditingDegTyp->DegTypName);
}
}
/*****************************************************************************/
/***************** Write parameter with code of degree type ******************/
/*****************************************************************************/
static void DT_PutParamOtherDegTypCod (long DegTypCod)
{
Par_PutHiddenParamLong ("OthDegTypCod",DegTypCod);
}
/*****************************************************************************/
/******************* Get parameter with code of degree type ******************/
/*****************************************************************************/
long DT_GetAndCheckParamOtherDegTypCod (long MinCodAllowed)
{
long DegTypCod;
/***** Get and check parameter with code of degree type *****/
if ((DegTypCod = Par_GetParToLong ("OthDegTypCod")) < MinCodAllowed)
Lay_ShowErrorAndExit ("Code of degree type is missing or invalid.");
return DegTypCod;
}
/*****************************************************************************/
/**************** Count number of degrees in a degree type ******************/
/*****************************************************************************/
static unsigned DT_CountNumDegsOfType (long DegTypCod)
{
/***** Get number of degrees of a type from database *****/
return
(unsigned) DB_QueryCOUNT ("can not get number of degrees of a type",
"SELECT COUNT(*) FROM degrees"
" WHERE DegTypCod=%ld",
DegTypCod);
}
/*****************************************************************************/
/****************** Get data of a degree type from its code ******************/
/*****************************************************************************/
bool DT_GetDataOfDegreeTypeByCod (struct DegreeType *DegTyp)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
bool DegTypFound = false;
if (DegTyp->DegTypCod <= 0)
{
DegTyp->DegTypCod = -1L;
DegTyp->DegTypName[0] = '\0';
DegTyp->NumDegs = 0;
return false;
}
/***** Get the name of a type of degree from database *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get the name of a type of degree",
"SELECT DegTypName FROM deg_types WHERE DegTypCod=%ld",
DegTyp->DegTypCod);
if (NumRows == 1)
{
/***** Get data of degree type *****/
row = mysql_fetch_row (mysql_res);
/* Get the name of the degree type (row[0]) */
Str_Copy (DegTyp->DegTypName,row[0],
Deg_MAX_BYTES_DEGREE_TYPE_NAME);
/* Count number of degrees of this type */
DegTyp->NumDegs = DT_CountNumDegsOfType (DegTyp->DegTypCod);
/* Set return value */
DegTypFound = true;
}
else if (NumRows == 0)
{
DegTyp->DegTypCod = -1L;
DegTyp->DegTypName[0] = '\0';
DegTyp->NumDegs = 0;
return false;
}
else // NumRows > 1
Lay_ShowErrorAndExit ("Type of degree repeated in database.");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
return DegTypFound;
}
/*****************************************************************************/
/******************** Remove a degree type and its degrees *******************/
/*****************************************************************************/
static void DT_RemoveDegreeTypeCompletely (long DegTypCod)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRow,NumRows;
long DegCod;
/***** Get degrees of a type from database *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get degrees of a type",
"SELECT DegCod FROM degrees WHERE DegTypCod=%ld",
DegTypCod);
/* Get degrees of this type */
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
/* Get next degree */
row = mysql_fetch_row (mysql_res);
/* Get degree code (row[0]) */
if ((DegCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of degree.");
/* Remove degree */
Deg_RemoveDegreeCompletely (DegCod);
}
/* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res);
/***** Remove the degree type *****/
DB_QueryDELETE ("can not remove a type of degree",
"DELETE FROM deg_types WHERE DegTypCod=%ld",
DegTypCod);
}
/*****************************************************************************/
/**************************** Rename a degree type ***************************/
/*****************************************************************************/
void DT_RenameDegreeType (void)
{
extern const char *Txt_You_can_not_leave_the_name_of_the_type_of_degree_X_empty;
extern const char *Txt_The_type_of_degree_X_already_exists;
extern const char *Txt_The_type_of_degree_X_has_been_renamed_as_Y;
extern const char *Txt_The_name_of_the_type_of_degree_X_has_not_changed;
char NewNameDegTyp[Deg_MAX_BYTES_DEGREE_TYPE_NAME + 1];
/***** Degree type constructor *****/
DT_EditingDegreeTypeConstructor ();
/***** Get parameters from form *****/
/* Get the code of the degree type */
DT_EditingDegTyp->DegTypCod = DT_GetAndCheckParamOtherDegTypCod (1);
/* Get the new name for the degree type */
Par_GetParToText ("DegTypName",NewNameDegTyp,Deg_MAX_BYTES_DEGREE_TYPE_NAME);
/***** Get from the database the old name of the degree type *****/
if (!DT_GetDataOfDegreeTypeByCod (DT_EditingDegTyp))
Lay_ShowErrorAndExit ("Code of type of degree not found.");
/***** Check if new name is empty *****/
if (!NewNameDegTyp[0])
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_You_can_not_leave_the_name_of_the_type_of_degree_X_empty,
DT_EditingDegTyp->DegTypName);
else
{
/***** Check if old and new names are the same
(this happens when return is pressed without changes) *****/
if (strcmp (DT_EditingDegTyp->DegTypName,NewNameDegTyp)) // Different names
{
/***** If degree type was in database... *****/
if (DT_CheckIfDegreeTypeNameExists (NewNameDegTyp,DT_EditingDegTyp->DegTypCod))
Ale_CreateAlert (Ale_WARNING,NULL,
Txt_The_type_of_degree_X_already_exists,
NewNameDegTyp);
else
{
/* Update the table changing old name by new name */
DB_QueryUPDATE ("can not update the type of a degree",
"UPDATE deg_types SET DegTypName='%s'"
" WHERE DegTypCod=%ld",
NewNameDegTyp,DT_EditingDegTyp->DegTypCod);
/* Write message to show the change made */
Ale_CreateAlert (Ale_SUCCESS,NULL,
Txt_The_type_of_degree_X_has_been_renamed_as_Y,
DT_EditingDegTyp->DegTypName,NewNameDegTyp);
}
}
else // The same name
Ale_CreateAlert (Ale_INFO,NULL,
Txt_The_name_of_the_type_of_degree_X_has_not_changed,
NewNameDegTyp);
}
/***** Set degree type name *****/
Str_Copy (DT_EditingDegTyp->DegTypName,NewNameDegTyp,
Deg_MAX_BYTES_DEGREE_TYPE_NAME);
}
/*****************************************************************************/
/****************** Check if name of degree type exists **********************/
/*****************************************************************************/
static bool DT_CheckIfDegreeTypeNameExists (const char *DegTypName,long DegTypCod)
{
/***** Get number of degree types with a name from database *****/
return (DB_QueryCOUNT ("can not check if the name of a type of degree"
" already existed",
"SELECT COUNT(*) FROM deg_types"
" WHERE DegTypName='%s' AND DegTypCod<>%ld",
DegTypName,DegTypCod) != 0);
}
/*****************************************************************************/
/********** Show message of success after changing a degree type *************/
/*****************************************************************************/
void DT_ContEditAfterChgDegTyp (void)
{
/***** Show possible delayed alerts *****/
Ale_ShowAlerts (NULL);
/***** Show the form again *****/
DT_EditDegreeTypesInternal ();
/***** Degree type destructor *****/
DT_EditingDegreeTypeDestructor ();
}
/*****************************************************************************/
/********************* Degree type constructor/destructor ********************/
/*****************************************************************************/
static void DT_EditingDegreeTypeConstructor (void)
{
/***** Pointer must be NULL *****/
if (DT_EditingDegTyp != NULL)
Lay_ShowErrorAndExit ("Error initializing degree type.");
/***** Allocate memory for degree type *****/
if ((DT_EditingDegTyp = (struct DegreeType *) malloc (sizeof (struct DegreeType))) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for degree type.");
/***** Reset degree type *****/
DT_EditingDegTyp->DegTypCod = -1L;
DT_EditingDegTyp->DegTypName[0] = '\0';
DT_EditingDegTyp->NumDegs = 0;
}
static void DT_EditingDegreeTypeDestructor (void)
{
/***** Free memory used for degree type *****/
if (DT_EditingDegTyp != NULL)
{
free ((void *) DT_EditingDegTyp);
DT_EditingDegTyp = NULL;
}
}