// swad_indicators.c: indicators of courses
/*
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 .
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include // For NULL
#include // For aprintf
#include // To access MySQL databases
#include "swad_action.h"
#include "swad_box.h"
#include "swad_database.h"
#include "swad_form.h"
#include "swad_forum.h"
#include "swad_global.h"
#include "swad_indicator.h"
#include "swad_parameter.h"
#include "swad_table.h"
#include "swad_theme.h"
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/*************************** Internal constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Internal types ******************************/
/*****************************************************************************/
typedef enum
{
Ind_INDICATORS_BRIEF,
Ind_INDICATORS_FULL,
} Ind_IndicatorsLayout_t;
/*****************************************************************************/
/***************************** Internal prototypes ***************************/
/*****************************************************************************/
static void Ind_GetParamsIndicators (void);
static void Ind_GetParamNumIndicators (void);
static unsigned Ind_GetTableOfCourses (MYSQL_RES **mysql_res);
static bool Ind_GetIfShowBigList (unsigned NumCrss);
static void Ind_PutButtonToConfirmIWantToSeeBigList (unsigned NumCrss);
static void Ind_PutParamsConfirmIWantToSeeBigList (void);
static void Ind_GetNumCoursesWithIndicators (unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS],
unsigned NumCrss,MYSQL_RES *mysql_res);
static void Ind_ShowNumCoursesWithIndicators (unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS],
unsigned NumCrss,bool PutForm);
static void Ind_ShowTableOfCoursesWithIndicators (Ind_IndicatorsLayout_t IndicatorsLayout,
unsigned NumCrss,MYSQL_RES *mysql_res);
static unsigned Ind_GetAndUpdateNumIndicatorsCrs (long CrsCod);
static void Ind_StoreIndicatorsCrsIntoDB (long CrsCod,unsigned NumIndicators);
static unsigned long Ind_GetNumFilesInDocumZonesOfCrsFromDB (long CrsCod);
static unsigned long Ind_GetNumFilesInShareZonesOfCrsFromDB (long CrsCod);
static unsigned long Ind_GetNumFilesInAssigZonesOfCrsFromDB (long CrsCod);
static unsigned long Ind_GetNumFilesInWorksZonesOfCrsFromDB (long CrsCod);
/*****************************************************************************/
/******************* Request showing statistics of courses *******************/
/*****************************************************************************/
void Ind_ReqIndicatorsCourses (void)
{
extern const char *Hlp_ANALYTICS_Indicators;
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_Scope;
extern const char *Txt_Types_of_degree;
extern const char *Txt_only_if_the_scope_is_X;
extern const char *Txt_Department;
extern const char *Txt_Any_department;
extern const char *Txt_No_of_indicators;
extern const char *Txt_Indicators_of_courses;
extern const char *Txt_Show_more_details;
MYSQL_RES *mysql_res;
unsigned NumCrss;
unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS];
unsigned NumCrssToList;
unsigned Ind;
/***** Get parameters *****/
Ind_GetParamsIndicators ();
/***** Start box *****/
Box_StartBox (NULL,Txt_Indicators_of_courses,NULL,
Hlp_ANALYTICS_Indicators,Box_NOT_CLOSABLE);
/***** Form to update indicators *****/
/* Start form and table */
Frm_StartForm (ActReqStaCrs);
Tbl_TABLE_BeginWidePadding (2);
/* Scope */
Tbl_TR_Begin (NULL);
Tbl_TD_Begin ("class=\"RIGHT_MIDDLE\"");
fprintf (Gbl.F.Out,"",
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Scope);
Tbl_TD_End ();
Tbl_TD_Begin ("class=\"LEFT_MIDDLE\"");
Sco_PutSelectorScope ("ScopeInd",true);
Tbl_TD_End ();
Tbl_TR_End ();
/* Compute stats for a type of degree */
Tbl_TR_Begin (NULL);
Tbl_TD_Begin ("class=\"RIGHT_MIDDLE\"");
fprintf (Gbl.F.Out,"",
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Types_of_degree);
Tbl_TD_End ();
Tbl_TD_Begin ("class=\"DAT LEFT_MIDDLE\"");
DT_WriteSelectorDegreeTypes ();
fprintf (Gbl.F.Out," (");
fprintf (Gbl.F.Out,Txt_only_if_the_scope_is_X,
Cfg_PLATFORM_SHORT_NAME);
fprintf (Gbl.F.Out,")");
Tbl_TD_End ();
Tbl_TR_End ();
/* Compute stats for courses with teachers belonging to any department or to a particular departament? */
Tbl_TR_Begin (NULL);
Tbl_TD_Begin ("class=\"RIGHT_MIDDLE\"");
fprintf (Gbl.F.Out,"",
Dpt_PARAM_DPT_COD_NAME,
The_ClassFormInBox[Gbl.Prefs.Theme],Txt_Department);
Tbl_TD_End ();
Tbl_TD_Begin ("class=\"LEFT_MIDDLE\"");
Dpt_WriteSelectorDepartment (Gbl.Hierarchy.Ins.InsCod, // Departments in current insitution
Gbl.Stat.DptCod, // Selected department
"INDICATORS_INPUT", // Selector class
-1L, // First option
Txt_Any_department, // Text when no department selected
true); // Submit on change
Tbl_TD_End ();
Tbl_TR_End ();
/***** Get courses from database *****/
/* The result will contain courses with any number of indicators
If Gbl.Stat.NumIndicators < 0 ==> all courses in result will be listed
If Gbl.Stat.NumIndicators >= 0 ==> only those courses in result
with Gbl.Stat.NumIndicators set to yes
will be listed */
NumCrss = Ind_GetTableOfCourses (&mysql_res);
/***** Get vector with numbers of courses with 0, 1, 2... indicators set to yes *****/
Ind_GetNumCoursesWithIndicators (NumCrssWithIndicatorYes,NumCrss,mysql_res);
/* Selection of the number of indicators */
Tbl_TR_Begin (NULL);
Tbl_TD_Begin ("class=\"RIGHT_TOP %s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
fprintf (Gbl.F.Out,"%s:",Txt_No_of_indicators);
Tbl_TD_End ();
Tbl_TD_Begin ("class=\"LEFT_TOP\"");
Ind_ShowNumCoursesWithIndicators (NumCrssWithIndicatorYes,NumCrss,true);
Tbl_TD_End ();
Tbl_TR_End ();
/* End table and form */
Tbl_TABLE_End ();
Frm_EndForm ();
/***** Show the stats of courses *****/
for (Ind = 0, NumCrssToList = 0;
Ind <= Ind_NUM_INDICATORS;
Ind++)
if (Gbl.Stat.IndicatorsSelected[Ind])
NumCrssToList += NumCrssWithIndicatorYes[Ind];
if (Ind_GetIfShowBigList (NumCrssToList))
{
/* Show table */
Ind_ShowTableOfCoursesWithIndicators (Ind_INDICATORS_BRIEF,NumCrss,mysql_res);
/* Button to show more details */
Frm_StartForm (ActSeeAllStaCrs);
Sco_PutParamScope ("ScopeInd",Gbl.Scope.Current);
Par_PutHiddenParamLong ("OthDegTypCod",Gbl.Stat.DegTypCod);
Par_PutHiddenParamLong (Dpt_PARAM_DPT_COD_NAME,Gbl.Stat.DptCod);
if (Gbl.Stat.StrIndicatorsSelected[0])
Par_PutHiddenParamString ("Indicators",Gbl.Stat.StrIndicatorsSelected);
Btn_PutConfirmButton (Txt_Show_more_details);
Frm_EndForm ();
}
/***** End box *****/
Box_EndBox ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/************* Get parameters related to indicators of courses ***************/
/*****************************************************************************/
static void Ind_GetParamsIndicators (void)
{
/***** Get scope *****/
Gbl.Scope.Allowed = 1 << Hie_SYS |
1 << Hie_CTY |
1 << Hie_INS |
1 << Hie_CTR |
1 << Hie_DEG |
1 << Hie_CRS;
Gbl.Scope.Default = Hie_CRS;
Sco_GetScope ("ScopeInd");
/***** Get degree type code *****/
Gbl.Stat.DegTypCod = (Gbl.Scope.Current == Hie_SYS) ?
DT_GetAndCheckParamOtherDegTypCod (-1L) : // -1L (any degree type) is allowed here
-1L;
/***** Get department code *****/
Gbl.Stat.DptCod = Dpt_GetAndCheckParamDptCod (-1L); // -1L (any department) is allowed here
/***** Get number of indicators *****/
Ind_GetParamNumIndicators ();
}
/*****************************************************************************/
/*********************** Show statistics of courses **************************/
/*****************************************************************************/
void Ind_ShowIndicatorsCourses (void)
{
MYSQL_RES *mysql_res;
unsigned NumCrss;
unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS];
/***** Get parameters *****/
Ind_GetParamsIndicators ();
/***** Get courses from database *****/
NumCrss = Ind_GetTableOfCourses (&mysql_res);
/***** Get vector with numbers of courses with 0, 1, 2... indicators set to yes *****/
Ind_GetNumCoursesWithIndicators (NumCrssWithIndicatorYes,NumCrss,mysql_res);
/***** Show table with numbers of courses with 0, 1, 2... indicators set to yes *****/
Ind_ShowNumCoursesWithIndicators (NumCrssWithIndicatorYes,NumCrss,false);
/***** Show the stats of courses *****/
Ind_ShowTableOfCoursesWithIndicators (Ind_INDICATORS_FULL,NumCrss,mysql_res);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
/*****************************************************************************/
/*************** Get parameter with the number of indicators *****************/
/*****************************************************************************/
static void Ind_GetParamNumIndicators (void)
{
unsigned Ind;
const char *Ptr;
char LongStr[1 + 10 + 1];
long Indicator;
/***** Get parameter multiple with list of indicators selected *****/
Par_GetParMultiToText ("Indicators",Gbl.Stat.StrIndicatorsSelected,Ind_MAX_SIZE_INDICATORS_SELECTED);
/***** Set which indicators have been selected (checkboxes on) *****/
if (Gbl.Stat.StrIndicatorsSelected[0])
{
/* Reset all indicators */
for (Ind = 0;
Ind <= Ind_NUM_INDICATORS;
Ind++)
Gbl.Stat.IndicatorsSelected[Ind] = false;
/* Set indicators selected */
for (Ptr = Gbl.Stat.StrIndicatorsSelected;
*Ptr;
)
{
/* Get next indicator selected */
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,1 + 10);
Indicator = Str_ConvertStrCodToLongCod (LongStr);
/* Set each indicator in list StrIndicatorsSelected as selected */
for (Ind = 0;
Ind <= Ind_NUM_INDICATORS;
Ind++)
if ((long) Ind == Indicator)
Gbl.Stat.IndicatorsSelected[Ind] = true;
}
}
else
/* Set all indicators */
for (Ind = 0;
Ind <= Ind_NUM_INDICATORS;
Ind++)
Gbl.Stat.IndicatorsSelected[Ind] = true;
}
/*****************************************************************************/
/******************* Build query to get table of courses *********************/
/*****************************************************************************/
// Return the number of courses found
static unsigned Ind_GetTableOfCourses (MYSQL_RES **mysql_res)
{
unsigned NumCrss = 0; // Initialized to avoid warning
switch (Gbl.Scope.Current)
{
case Hie_SYS:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
{
if (Gbl.Stat.DegTypCod > 0)
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses,crs_usr,usr_data"
" WHERE degrees.DegTypCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Stat.DegTypCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses,crs_usr,usr_data"
" WHERE degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
}
else
{
if (Gbl.Stat.DegTypCod > 0)
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses"
" WHERE degrees.DegTypCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Stat.DegTypCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses"
" WHERE degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName");
}
break;
case Hie_CTY:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM institutions,centres,degrees,courses,crs_usr,usr_data"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Cty.CtyCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM institutions,centres,degrees,courses"
" WHERE institutions.CtyCod=%ld"
" AND institutions.InsCod=centres.InsCod"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Cty.CtyCod);
break;
case Hie_INS:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM centres,degrees,courses,crs_usr,usr_data"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Ins.InsCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM centres,degrees,courses"
" WHERE centres.InsCod=%ld"
" AND centres.CtrCod=degrees.CtrCod"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Ins.InsCod);
break;
case Hie_CTR:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses,crs_usr,usr_data"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Ctr.CtrCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses"
" WHERE degrees.CtrCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Ctr.CtrCod);
break;
case Hie_DEG:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses,crs_usr,usr_data"
" WHERE degrees.DegCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Deg.DegCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses"
" WHERE degrees.DegCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Deg.DegCod);
break;
case Hie_CRS:
if (Gbl.Stat.DptCod >= 0) // 0 means another department
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT DISTINCTROW degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses,crs_usr,usr_data"
" WHERE courses.CrsCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" AND courses.CrsCod=crs_usr.CrsCod"
" AND crs_usr.CrsCod=%ld"
" AND crs_usr.Role=%u"
" AND crs_usr.UsrCod=usr_data.UsrCod"
" AND usr_data.DptCod=%ld"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod,
(unsigned) Rol_TCH,
Gbl.Stat.DptCod);
else
NumCrss =
(unsigned) DB_QuerySELECT (mysql_res,"can not get courses",
"SELECT degrees.FullName,courses.FullName,courses.CrsCod,courses.InsCrsCod"
" FROM degrees,courses"
" WHERE courses.CrsCod=%ld"
" AND degrees.DegCod=courses.DegCod"
" ORDER BY degrees.FullName,courses.FullName",
Gbl.Hierarchy.Crs.CrsCod);
break;
default:
Lay_WrongScopeExit ();
break;
}
return NumCrss;
}
/*****************************************************************************/
/******* Show form to confirm that I want to see a big list of courses *******/
/*****************************************************************************/
static bool Ind_GetIfShowBigList (unsigned NumCrss)
{
bool ShowBigList;
/***** If list of courses is too big... *****/
if (NumCrss <= Cfg_MIN_NUM_COURSES_TO_CONFIRM_SHOW_BIG_LIST)
return true; // List is not too big ==> show it
/***** Get parameter with user's confirmation to see a big list of courses *****/
if (!(ShowBigList = Par_GetParToBool ("ShowBigList")))
Ind_PutButtonToConfirmIWantToSeeBigList (NumCrss);
return ShowBigList;
}
/*****************************************************************************/
/****** Show form to confirm that I want to see a big list of courses ********/
/*****************************************************************************/
static void Ind_PutButtonToConfirmIWantToSeeBigList (unsigned NumCrss)
{
extern const char *Txt_The_list_of_X_courses_is_too_large_to_be_displayed;
extern const char *Txt_Show_anyway;
/***** Show alert and button to confirm that I want to see the big list *****/
Ale_ShowAlertAndButton (Gbl.Action.Act,NULL,NULL,
Ind_PutParamsConfirmIWantToSeeBigList,
Btn_CONFIRM_BUTTON,Txt_Show_anyway,
Ale_WARNING,Txt_The_list_of_X_courses_is_too_large_to_be_displayed,
NumCrss);
}
static void Ind_PutParamsConfirmIWantToSeeBigList (void)
{
Sco_PutParamScope ("ScopeInd",Gbl.Scope.Current);
Par_PutHiddenParamLong ("OthDegTypCod",Gbl.Stat.DegTypCod);
Par_PutHiddenParamLong (Dpt_PARAM_DPT_COD_NAME,Gbl.Stat.DptCod);
if (Gbl.Stat.StrIndicatorsSelected[0])
Par_PutHiddenParamString ("Indicators",Gbl.Stat.StrIndicatorsSelected);
Par_PutHiddenParamChar ("ShowBigList",'Y');
}
/*****************************************************************************/
/** Get vector with numbers of courses with 0, 1, 2... indicators set to yes */
/*****************************************************************************/
static void Ind_GetNumCoursesWithIndicators (unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS],
unsigned NumCrss,MYSQL_RES *mysql_res)
{
MYSQL_ROW row;
unsigned NumCrs;
long CrsCod;
unsigned Ind;
unsigned NumIndicators;
/***** Reset counters of courses with each number of indicators *****/
for (Ind = 0;
Ind <= Ind_NUM_INDICATORS;
Ind++)
NumCrssWithIndicatorYes[Ind] = 0;
/***** List courses *****/
for (Gbl.RowEvenOdd = 1, NumCrs = 0;
NumCrs < NumCrss;
NumCrs++, Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd)
{
/* Get next course */
row = mysql_fetch_row (mysql_res);
/* Get course code (row[2]) */
if ((CrsCod = Str_ConvertStrCodToLongCod (row[2])) < 0)
Lay_ShowErrorAndExit ("Wrong code of course.");
/* Get stored number of indicators of this course */
NumIndicators = Ind_GetAndUpdateNumIndicatorsCrs (CrsCod);
NumCrssWithIndicatorYes[NumIndicators]++;
}
}
/*****************************************************************************/
/** Show table with numbers of courses with 0, 1, 2... indicators set to yes */
/*****************************************************************************/
static void Ind_ShowNumCoursesWithIndicators (unsigned NumCrssWithIndicatorYes[1 + Ind_NUM_INDICATORS],
unsigned NumCrss,bool PutForm)
{
extern const char *Txt_Indicators;
extern const char *Txt_Courses;
extern const char *Txt_Total;
unsigned Ind;
const char *Class;
const char *ClassNormal = "DAT_LIGHT RIGHT_MIDDLE";
const char *ClassHighlight = "DAT RIGHT_MIDDLE LIGHT_BLUE";
/***** Write number of courses with each number of indicators valid *****/
Tbl_TABLE_BeginPadding (2);
Tbl_TR_Begin (NULL);
if (PutForm)
Tbl_TH_Empty (1);
fprintf (Gbl.F.Out,"