2014-12-01 23:55:08 +01:00
// swad_timetable.c: timetables
/*
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 .
2016-01-01 20:19:43 +01:00
Copyright ( C ) 1999 - 2016 Antonio Ca <EFBFBD> as Vargas
2014-12-01 23:55:08 +01:00
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 <linux/stddef.h> // For NULL
# include <stdio.h> // For fprintf, etc.
# include <string.h> // For string functions
2015-12-01 00:38:22 +01:00
# include "swad_calendar.h"
2014-12-01 23:55:08 +01:00
# include "swad_database.h"
# include "swad_global.h"
# include "swad_parameter.h"
# include "swad_text.h"
# include "swad_timetable.h"
/*****************************************************************************/
/*************************** External constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl ;
/*****************************************************************************/
/*************************** Internal constants ******************************/
/*****************************************************************************/
2015-11-30 20:47:37 +01:00
# define TT_START_HOUR 6 // Day starts at 6:00
# define TT_HOURS_PER_DAY 16 // From 6:00 to 22:00
# define TT_DAYS 7 // Seven days per week
2014-12-01 23:55:08 +01:00
# define TT_MAX_COLUMNS_PER_CELL 3 // Maximum number of items (i.e. classes) in a timetable cell (1, 2, 3 or 4)
# define TT_NUM_MINICOLUMNS_PER_DAY 6 // Least common multiple of 1,2,3,...,TT_MAX_COLUMNS_PER_CELL
# define TT_PERCENT_WIDTH_OF_A_MINICOLUMN 2 // Width (%) of each minicolumn
# define TT_PERCENT_WIDTH_OF_A_DAY (TT_PERCENT_WIDTH_OF_A_MINICOLUMN*TT_NUM_MINICOLUMNS_PER_DAY) // Width (%) of each day
# define TT_PERCENT_WIDTH_OF_ALL_DAYS (TT_PERCENT_WIDTH_OF_A_DAY*TT_DAYS) // Width (%) of all days
# define TT_PERCENT_WIDTH_OF_A_SEPARATION_COLUMN 1 // Width (%) of left and right columns (frame)
# define TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN ((100-TT_PERCENT_WIDTH_OF_ALL_DAYS-TT_PERCENT_WIDTH_OF_A_SEPARATION_COLUMN*2) / 2) // Width (%) of the separation columns
# define TT_MAX_BYTES_STR_CLASS_TYPE 256
# define TT_MAX_BYTES_STR_DURATION ((2+1+2+1+1)*Str_LENGTH_STR_HEX) // "hh:mm h"
# define TT_MAX_LENGTH_PLACE 32
/*****************************************************************************/
/******************************* Internal types ******************************/
/*****************************************************************************/
/*****************************************************************************/
/************************* Internal global variables *************************/
/*****************************************************************************/
char TimeTableCharsDays [ TT_DAYS ] = // TODO: Change from Spanish to numbers, also in database
{
' L ' , // Monday
' M ' , // Tuesday
' X ' , // Wednesday
' J ' , // Thursday
' V ' , // Friday
' S ' , // Saturday
' D ' , // Sunday
} ;
char * TimeTableStrsClassTypeDB [ TT_NUM_CLASS_TYPES ] = // TODO: Change from Spanish to English, also in database
{
" libre " ,
" teoria " ,
" practicas " ,
" tutorias " ,
} ;
struct TimeTableColumn
{
long CrsCod ; // Course code (-1 if no course selected)
long GrpCod ; // Group code (-1 if no group selected)
TT_HourType_t HourType ;
TT_ClassType_t ClassType ;
unsigned Duration ;
char Place [ TT_MAX_BYTES_PLACE + 1 ] ;
char Group [ TT_MAX_BYTES_GROUP + 1 ] ;
} ;
struct
{
unsigned NumColumns ;
struct TimeTableColumn Columns [ TT_MAX_COLUMNS_PER_CELL ] ;
} TimeTable [ TT_DAYS ] [ TT_HOURS_PER_DAY * 2 ] ;
bool TimeTableHoursChecked [ TT_HOURS_PER_DAY * 2 ] ;
/*****************************************************************************/
/***************************** Internal prototypes **************************/
/*****************************************************************************/
static void TT_ShowTimeTableGrpsSelected ( void ) ;
static void TT_GetParamsTimeTable ( void ) ;
2016-03-18 14:07:21 +01:00
static void TT_PutContextualIcons ( void ) ;
2016-11-26 22:07:52 +01:00
static void TT_PutFormToSelectWhichGroupsToShow ( void ) ;
2015-12-01 00:38:22 +01:00
2016-03-18 14:17:19 +01:00
static void TT_PutIconToViewCrsTT ( void ) ;
static void TT_PutIconToViewMyTT ( void ) ;
2014-12-01 23:55:08 +01:00
static void TT_WriteCrsTimeTableIntoDB ( long CrsCod ) ;
static void TT_WriteTutTimeTableIntoDB ( long UsrCod ) ;
2016-03-18 14:07:21 +01:00
static void TT_CreatTimeTableFromDB ( long UsrCod ) ;
2014-12-01 23:55:08 +01:00
static void TT_ModifTimeTable ( void ) ;
2016-03-18 14:07:21 +01:00
static void TT_DrawTimeTable ( void ) ;
2014-12-01 23:55:08 +01:00
static void TT_TimeTableDrawAdjustRow ( void ) ;
static void TT_TimeTableDrawDaysCells ( void ) ;
static unsigned TT_TimeTableCalculateColsToDraw ( unsigned Day , unsigned Hour ) ;
static void TT_DrawCellAlignTimeTable ( void ) ;
2016-03-18 14:07:21 +01:00
static void TT_TimeTableDrawCell ( unsigned Day , unsigned Hour , unsigned Column , unsigned ColSpan ,
2014-12-01 23:55:08 +01:00
long CrsCod , TT_HourType_t HourType , TT_ClassType_t ClassType , unsigned Duration , char * Group , long GrpCod , char * Place ) ;
/*****************************************************************************/
/*********** Show whether only my groups or all groups are shown *************/
/*****************************************************************************/
static void TT_ShowTimeTableGrpsSelected ( void )
{
extern const char * Txt_Groups_OF_A_USER ;
extern const char * Txt_All_groups ;
2016-03-18 22:17:35 +01:00
fprintf ( Gbl . F . Out , " <div class= \" TIT_CLASSPHOTO CENTER_MIDDLE \" > " ) ;
2014-12-01 23:55:08 +01:00
switch ( Gbl . CurrentCrs . Grps . WhichGrps )
{
case Grp_ONLY_MY_GROUPS :
fprintf ( Gbl . F . Out , Txt_Groups_OF_A_USER ,
Gbl . Usrs . Me . UsrDat . FullName ) ;
break ;
case Grp_ALL_GROUPS :
fprintf ( Gbl . F . Out , " %s " , Txt_All_groups ) ;
break ;
}
2016-03-18 22:17:35 +01:00
fprintf ( Gbl . F . Out , " </div> " ) ;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************** Get paramaters for timetable editing *******************/
/*****************************************************************************/
static void TT_GetParamsTimeTable ( void )
{
char UnsignedStr [ 10 + 1 ] ;
char LongStr [ 1 + 10 + 1 ] ;
char StrClassType [ TT_MAX_BYTES_STR_CLASS_TYPE + 1 ] ;
char StrDuration [ TT_MAX_BYTES_STR_DURATION + 1 ] ;
unsigned Hours , Minutes ;
/***** Get day (0: monday, 1: tuesday,..., 4: friday *****/
Par_GetParToText ( " ModTTDay " , UnsignedStr , 2 ) ;
if ( sscanf ( UnsignedStr , " %u " , & Gbl . TimeTable . Day ) ! = 1 )
Lay_ShowErrorAndExit ( " Day is missing. " ) ;
/***** Get hour *****/
Par_GetParToText ( " ModTTHour " , UnsignedStr , 2 ) ;
if ( sscanf ( UnsignedStr , " %u " , & Gbl . TimeTable . Hour ) ! = 1 )
Lay_ShowErrorAndExit ( " Hour is missing. " ) ;
/***** Get number of column *****/
Par_GetParToText ( " ModTTCol " , UnsignedStr , 2 ) ;
if ( sscanf ( UnsignedStr , " %u " , & Gbl . TimeTable . Column ) ! = 1 )
Lay_ShowErrorAndExit ( " Column is missing. " ) ;
/***** Get class type *****/
Par_GetParToText ( " ModTTCellType " , StrClassType , TT_MAX_BYTES_STR_CLASS_TYPE ) ;
for ( Gbl . TimeTable . ClassType = ( TT_ClassType_t ) 0 ;
Gbl . TimeTable . ClassType < ( TT_ClassType_t ) TT_NUM_CLASS_TYPES ;
Gbl . TimeTable . ClassType + + )
if ( ! strcmp ( StrClassType , TimeTableStrsClassTypeDB [ Gbl . TimeTable . ClassType ] ) )
break ;
if ( Gbl . TimeTable . ClassType = = ( TT_ClassType_t ) TT_NUM_CLASS_TYPES )
Lay_ShowErrorAndExit ( " Type of timetable cell is missing. " ) ;
/***** Get class duration *****/
Par_GetParToText ( " ModTTDur " , StrDuration , TT_MAX_BYTES_STR_DURATION ) ;
if ( sscanf ( StrDuration , " %u:%u " , & Hours , & Minutes ) ! = 2 )
Lay_ShowErrorAndExit ( " Duration is missing. " ) ;
Gbl . TimeTable . Duration = Hours * 2 + Minutes / 30 ;
/***** Get group *****/
Par_GetParToText ( " ModHorGrp " , Gbl . TimeTable . Group , TT_MAX_BYTES_GROUP ) ;
/***** Get group code *****/
Par_GetParToText ( " ModTTGrpCod " , LongStr , 1 + 10 ) ;
if ( LongStr [ 0 ] )
{
if ( sscanf ( LongStr , " %ld " , & Gbl . TimeTable . GrpCod ) ! = 1 )
Lay_ShowErrorAndExit ( " Wrong code of group. " ) ;
}
else
Gbl . TimeTable . GrpCod = - 1 ;
/***** Get place *****/
Par_GetParToText ( " ModHorLugar " , Gbl . TimeTable . Place , TT_MAX_BYTES_PLACE ) ;
}
/*****************************************************************************/
/**************************** Show class timetable ***************************/
/*****************************************************************************/
void TT_ShowClassTimeTable ( void )
{
2016-11-26 21:12:23 +01:00
extern const char * Hlp_COURSE_Timetable ;
2016-11-26 20:58:12 +01:00
extern const char * Hlp_PROFILE_Timetable ;
2015-01-02 12:57:26 +01:00
extern const char * Txt_TIMETABLE_TYPES [ TT_NUM_TIMETABLE_TYPES ] ;
2016-11-26 20:58:12 +01:00
const char * Help [ TT_NUM_TIMETABLE_TYPES ] =
{
2016-11-26 21:12:23 +01:00
Hlp_COURSE_Timetable , // TT_COURSE_TIMETABLE
2016-11-26 20:58:12 +01:00
Hlp_PROFILE_Timetable , // TT_MY_TIMETABLE
NULL , // TT_TUTOR_TIMETABLE
} ;
2016-11-26 22:02:42 +01:00
Act_Action_t ActChgTT1stDay [ TT_NUM_TIMETABLE_TYPES ] =
{
ActChgCrsTT1stDay , // TT_COURSE_TIMETABLE
ActChgMyTT1stDay , // TT_MY_TIMETABLE
ActUnk , // TT_TUTOR_TIMETABLE
} ;
2016-03-18 14:07:21 +01:00
bool PrintView = ( Gbl . Action . Act = = ActPrnCrsTT | |
Gbl . Action . Act = = ActPrnMyTT ) ; ;
2014-12-01 23:55:08 +01:00
2015-12-01 00:38:22 +01:00
/***** Initializations *****/
2016-01-17 15:10:54 +01:00
switch ( Gbl . Action . Act )
2014-12-01 23:55:08 +01:00
{
2015-12-01 00:38:22 +01:00
case ActSeeCrsTT :
case ActPrnCrsTT :
case ActChgCrsTT1stDay :
2016-03-18 14:07:21 +01:00
Gbl . TimeTable . Type = TT_COURSE_TIMETABLE ;
2014-12-01 23:55:08 +01:00
break ;
2015-12-01 00:38:22 +01:00
case ActSeeMyTT :
case ActPrnMyTT :
case ActChgMyTT1stDay :
2016-03-18 14:07:21 +01:00
Gbl . TimeTable . Type = TT_MY_TIMETABLE ;
2014-12-01 23:55:08 +01:00
break ;
2015-12-01 00:38:22 +01:00
default :
Lay_ShowErrorAndExit ( " Wrong action. " ) ;
2014-12-01 23:55:08 +01:00
}
2016-03-18 14:07:21 +01:00
Gbl . TimeTable . ContextualIcons . PutIconPrint = ! PrintView ;
Gbl . TimeTable . ContextualIcons . PutIconEditCrsTT = ( Gbl . TimeTable . Type = = TT_COURSE_TIMETABLE & &
! PrintView & &
Gbl . Usrs . Me . LoggedRole > = Rol_TEACHER ) ;
Gbl . TimeTable . ContextualIcons . PutIconEditOfficeHours = ( Gbl . TimeTable . Type = = TT_MY_TIMETABLE & &
! PrintView & &
( Gbl . Usrs . Me . AvailableRoles & ( 1 < < Rol_TEACHER ) ) ) ;
2015-12-01 00:38:22 +01:00
/***** Get whether to show only my groups or all groups *****/
Grp_GetParamWhichGrps ( ) ;
2014-12-01 23:55:08 +01:00
2014-12-08 17:35:48 +01:00
/***** Start frame *****/
2016-03-18 14:07:21 +01:00
Lay_StartRoundFrame ( " 100% " , Txt_TIMETABLE_TYPES [ Gbl . TimeTable . Type ] ,
( Gbl . TimeTable . ContextualIcons . PutIconEditCrsTT | |
Gbl . TimeTable . ContextualIcons . PutIconEditOfficeHours | |
Gbl . TimeTable . ContextualIcons . PutIconPrint ) ? TT_PutContextualIcons :
2016-11-12 22:00:50 +01:00
NULL ,
2016-11-26 20:58:12 +01:00
Help [ Gbl . TimeTable . Type ] ) ;
2014-12-08 17:35:48 +01:00
/***** Start time table drawing *****/
2016-03-18 14:07:21 +01:00
if ( Gbl . TimeTable . Type = = TT_COURSE_TIMETABLE )
2016-03-18 22:17:35 +01:00
Lay_WriteHeaderClassPhoto ( PrintView , false ,
2014-12-08 17:35:48 +01:00
Gbl . CurrentIns . Ins . InsCod , Gbl . CurrentDeg . Deg . DegCod , Gbl . CurrentCrs . Crs . CrsCod ) ;
if ( PrintView )
2015-01-02 12:57:26 +01:00
/***** Show whether only my groups or all groups are selected *****/
TT_ShowTimeTableGrpsSelected ( ) ;
else
2014-12-01 23:55:08 +01:00
{
2015-12-01 00:38:22 +01:00
/***** Select whether show only my groups or all groups *****/
2016-11-26 22:02:42 +01:00
if ( Gbl . CurrentCrs . Grps . NumGrps )
2016-11-26 22:07:52 +01:00
TT_PutFormToSelectWhichGroupsToShow ( ) ;
2015-12-01 00:38:22 +01:00
/***** Show form to change first day of week *****/
2016-11-26 22:02:42 +01:00
Cal_ShowFormToSelFirstDayOfWeek ( ActChgTT1stDay [ Gbl . TimeTable . Type ] ,
2016-11-14 10:05:41 +01:00
" ICO25x25 " ) ;
2014-12-01 23:55:08 +01:00
}
/***** Show the time table *****/
2016-03-18 14:07:21 +01:00
TT_ShowTimeTable ( Gbl . Usrs . Me . UsrDat . UsrCod ) ;
2014-12-01 23:55:08 +01:00
2014-12-08 17:35:48 +01:00
/***** End frame *****/
2016-03-18 14:07:21 +01:00
Lay_EndRoundFrame ( ) ;
}
/*****************************************************************************/
/***************** Put contextual icons above the time table *****************/
/*****************************************************************************/
static void TT_PutContextualIcons ( void )
{
extern const char * Txt_Edit ;
extern const char * Txt_Edit_office_hours ;
extern const char * Txt_Print ;
if ( Gbl . TimeTable . ContextualIcons . PutIconEditCrsTT )
Lay_PutContextualLink ( ActEdiCrsTT , Grp_PutParamWhichGrps ,
" edit64x64.png " ,
2016-07-01 16:32:42 +02:00
Txt_Edit , NULL ,
NULL ) ;
2016-03-18 14:07:21 +01:00
if ( Gbl . TimeTable . ContextualIcons . PutIconEditOfficeHours )
2016-07-01 16:32:42 +02:00
Lay_PutContextualLink ( ActEdiTut , NULL ,
" edit64x64.png " ,
Txt_Edit_office_hours , NULL ,
NULL ) ;
2016-03-18 14:07:21 +01:00
if ( Gbl . TimeTable . ContextualIcons . PutIconPrint )
Lay_PutContextualLink ( Gbl . TimeTable . Type = = TT_COURSE_TIMETABLE ? ActPrnCrsTT :
2016-07-01 16:32:42 +02:00
ActPrnMyTT ,
Grp_PutParamWhichGrps ,
" print64x64.png " ,
Txt_Print , NULL ,
NULL ) ;
2014-12-01 23:55:08 +01:00
}
2016-11-26 22:07:52 +01:00
/*****************************************************************************/
/***************** Put form to select which groups to show *******************/
/*****************************************************************************/
static void TT_PutFormToSelectWhichGroupsToShow ( void )
{
Act_Action_t ActSeeTT [ TT_NUM_TIMETABLE_TYPES ] =
{
ActSeeCrsTT , // TT_COURSE_TIMETABLE
ActSeeMyTT , // TT_MY_TIMETABLE
ActUnk , // TT_TUTOR_TIMETABLE
} ;
Act_FormStart ( ActSeeTT [ Gbl . TimeTable . Type ] ) ;
Grp_ShowSelectorWhichGrps ( ) ;
Act_FormEnd ( ) ;
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/********************** Show course timetable for edition ********************/
/*****************************************************************************/
void TT_EditCrsTimeTable ( void )
{
2016-11-26 21:12:23 +01:00
extern const char * Hlp_COURSE_Timetable ;
2015-04-12 01:40:51 +02:00
extern const char * Txt_TIMETABLE_TYPES [ TT_NUM_TIMETABLE_TYPES ] ;
2014-12-01 23:55:08 +01:00
/***** Editable time table *****/
2016-03-18 14:07:21 +01:00
Gbl . TimeTable . Type = TT_COURSE_TIMETABLE ;
2016-03-18 14:17:19 +01:00
Lay_StartRoundFrame ( " 100% " , Txt_TIMETABLE_TYPES [ Gbl . TimeTable . Type ] ,
2016-11-26 21:12:23 +01:00
TT_PutIconToViewCrsTT , Hlp_COURSE_Timetable ) ;
2016-03-18 14:07:21 +01:00
TT_ShowTimeTable ( Gbl . Usrs . Me . UsrDat . UsrCod ) ;
2015-04-12 18:01:06 +02:00
Lay_EndRoundFrame ( ) ;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Show tutor timetable for edition **********************/
/*****************************************************************************/
2016-11-26 20:58:12 +01:00
void TT_EditMyTutTimeTable ( void )
2014-12-01 23:55:08 +01:00
{
2016-11-26 20:58:12 +01:00
extern const char * Hlp_PROFILE_Timetable ;
2015-01-02 12:57:26 +01:00
extern const char * Txt_TIMETABLE_TYPES [ TT_NUM_TIMETABLE_TYPES ] ;
2014-12-01 23:55:08 +01:00
/***** Time table *****/
2016-03-18 14:07:21 +01:00
Gbl . TimeTable . Type = TT_TUTOR_TIMETABLE ;
2016-03-18 14:17:19 +01:00
Lay_StartRoundFrame ( " 100% " , Txt_TIMETABLE_TYPES [ Gbl . TimeTable . Type ] ,
2016-11-26 20:58:12 +01:00
TT_PutIconToViewMyTT , Hlp_PROFILE_Timetable ) ;
2016-03-18 14:07:21 +01:00
TT_ShowTimeTable ( Gbl . Usrs . Me . UsrDat . UsrCod ) ;
2015-04-12 18:01:06 +02:00
Lay_EndRoundFrame ( ) ;
2014-12-01 23:55:08 +01:00
}
2016-03-18 14:17:19 +01:00
/*****************************************************************************/
/********************** Put icon to view course timetable ********************/
/*****************************************************************************/
static void TT_PutIconToViewCrsTT ( void )
{
extern const char * Txt_Show_timetable ;
/***** Link (form) to see course timetable *****/
2016-07-01 16:32:42 +02:00
Lay_PutContextualLink ( ActSeeCrsTT , NULL ,
2016-11-26 20:58:12 +01:00
" eye-on64x64.png " ,
2016-07-01 16:32:42 +02:00
Txt_Show_timetable , NULL ,
NULL ) ;
2016-03-18 14:17:19 +01:00
}
/*****************************************************************************/
/************************ Put icon to view my timetable **********************/
/*****************************************************************************/
static void TT_PutIconToViewMyTT ( void )
{
extern const char * Txt_Show_timetable ;
/***** Link (form) to see my timetable *****/
2016-07-01 16:32:42 +02:00
Lay_PutContextualLink ( ActSeeMyTT , NULL ,
2016-11-26 20:58:12 +01:00
" eye-on64x64.png " ,
2016-07-01 16:32:42 +02:00
Txt_Show_timetable , NULL ,
NULL ) ;
2016-03-18 14:17:19 +01:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*********** Show course timetable or tutor timetable of a teacher ***********/
/*****************************************************************************/
2016-03-18 14:07:21 +01:00
void TT_ShowTimeTable ( long UsrCod )
2014-12-01 23:55:08 +01:00
{
/***** Create an internal table with the timetable from database *****/
2016-03-18 14:07:21 +01:00
TT_CreatTimeTableFromDB ( UsrCod ) ;
2014-12-01 23:55:08 +01:00
/***** If timetable must be modified... *****/
2016-01-17 15:10:54 +01:00
if ( Gbl . Action . Act = = ActChgCrsTT | |
Gbl . Action . Act = = ActChgTut )
2014-12-01 23:55:08 +01:00
{
/* Get parameters for time table editing */
TT_GetParamsTimeTable ( ) ;
/* Modify timetable in memory */
TT_ModifTimeTable ( ) ;
/* Write a new timetable in database */
2016-03-18 14:07:21 +01:00
switch ( Gbl . TimeTable . Type )
2014-12-01 23:55:08 +01:00
{
case TT_COURSE_TIMETABLE :
TT_WriteCrsTimeTableIntoDB ( Gbl . CurrentCrs . Crs . CrsCod ) ;
break ;
case TT_TUTOR_TIMETABLE :
TT_WriteTutTimeTableIntoDB ( UsrCod ) ;
break ;
default :
break ;
}
/* Get a new table from database */
2016-03-18 14:07:21 +01:00
TT_CreatTimeTableFromDB ( UsrCod ) ;
2014-12-01 23:55:08 +01:00
}
/***** Draw timetable *****/
2016-03-18 14:07:21 +01:00
TT_DrawTimeTable ( ) ;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Write course timetable into database ********************/
/*****************************************************************************/
static void TT_WriteCrsTimeTableIntoDB ( long CrsCod )
{
char Query [ 1024 ] ;
unsigned Hour , Day , Column ;
/***** Remove former timetable *****/
sprintf ( Query , " DELETE FROM timetable_crs WHERE CrsCod='%ld' " , CrsCod ) ;
DB_QueryDELETE ( Query , " can not remove former timetable " ) ;
/***** Go across the timetable inserting classes into database *****/
for ( Day = 0 ;
Day < TT_DAYS ;
Day + + )
for ( Hour = 0 ;
Hour < TT_HOURS_PER_DAY * 2 ;
Hour + + )
for ( Column = 0 ;
Column < TT_MAX_COLUMNS_PER_CELL ;
Column + + )
if ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType = = TT_FIRST_HOUR & &
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration > 0 )
{
sprintf ( Query , " INSERT INTO timetable_crs (CrsCod,GrpCod,Day,Hour,Duration,ClassType,Place,GroupName) "
" VALUES ('%ld','%ld','%c','%u','%d','%s','%s','%s') " ,
CrsCod ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . GrpCod ,
TimeTableCharsDays [ Day ] ,
Hour ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ,
TimeTableStrsClassTypeDB [ TimeTable [ Day ] [ Hour ] . Columns [ Column ] . ClassType ] ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Place ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Group ) ;
DB_QueryINSERT ( Query , " can not create course timetable " ) ;
}
}
/*****************************************************************************/
/********************* Write tutor timetable into database *******************/
/*****************************************************************************/
static void TT_WriteTutTimeTableIntoDB ( long UsrCod )
{
char Query [ 1024 ] ;
unsigned Hour , Day , Column ;
/***** Remove former timetable *****/
sprintf ( Query , " DELETE FROM timetable_tut WHERE UsrCod='%ld' " , UsrCod ) ;
DB_QueryDELETE ( Query , " can not remove former timetable " ) ;
/***** Loop over timetable *****/
for ( Day = 0 ;
Day < TT_DAYS ;
Day + + )
for ( Hour = 0 ;
Hour < TT_HOURS_PER_DAY * 2 ;
Hour + + )
for ( Column = 0 ;
Column < TT_MAX_COLUMNS_PER_CELL ;
Column + + )
if ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType = = TT_FIRST_HOUR & &
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration > 0 )
{
sprintf ( Query , " INSERT INTO timetable_tut (UsrCod,Day,Hour,Duration,Place) "
" VALUES ('%ld','%c','%u','%d','%s') " ,
UsrCod , TimeTableCharsDays [ Day ] , Hour ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Place ) ;
DB_QueryINSERT ( Query , " can not create office timetable " ) ;
}
}
/*****************************************************************************/
/********** Create an internal table with timetable from database ************/
/*****************************************************************************/
2016-03-18 14:07:21 +01:00
static void TT_CreatTimeTableFromDB ( long UsrCod )
2014-12-01 23:55:08 +01:00
{
extern const char * Txt_Incomplete_timetable_for_lack_of_space ;
char Query [ 4096 ] ;
MYSQL_RES * mysql_res ;
MYSQL_ROW row ;
unsigned long NumRow , NumRows ;
unsigned Hour , Day , Column , FirstFreeColumn , Duration , H ;
long GrpCod ;
TT_ClassType_t ClassType = TT_NO_CLASS ; // Initialized to avoid warning
bool TimeTableIsIncomplete = false ;
bool TimeTableHasSpaceForThisClass ;
bool Found ;
/***** Initialize timetable to all free *****/
for ( Day = 0 ;
Day < TT_DAYS ;
Day + + )
for ( Hour = 0 ;
Hour < TT_HOURS_PER_DAY * 2 ;
Hour + + )
{
TimeTable [ Day ] [ Hour ] . NumColumns = 0 ;
for ( Column = 0 ;
Column < TT_MAX_COLUMNS_PER_CELL ;
Column + + )
{
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . CrsCod = - 1L ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . GrpCod = - 1L ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType = TT_FREE_HOUR ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . ClassType = TT_NO_CLASS ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration = 0 ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Group [ 0 ] = ' \0 ' ;
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Place [ 0 ] = ' \0 ' ;
}
}
/***** Get timetable from database *****/
2016-03-18 14:07:21 +01:00
switch ( Gbl . TimeTable . Type )
2014-12-01 23:55:08 +01:00
{
case TT_MY_TIMETABLE :
switch ( Gbl . CurrentCrs . Grps . WhichGrps )
{
case Grp_ONLY_MY_GROUPS :
sprintf ( Query , " SELECT timetable_crs.Day,timetable_crs.Hour,timetable_crs.Duration,timetable_crs.Place, "
" timetable_crs.ClassType,timetable_crs.GroupName,timetable_crs.GrpCod,timetable_crs.CrsCod "
" FROM timetable_crs,crs_usr "
" WHERE crs_usr.UsrCod='%ld' AND timetable_crs.GrpCod='-1' AND timetable_crs.CrsCod=crs_usr.CrsCod "
" UNION DISTINCT "
" SELECT timetable_crs.Day,timetable_crs.Hour,timetable_crs.Duration,timetable_crs.Place, "
" timetable_crs.ClassType,timetable_crs.GroupName,timetable_crs.GrpCod,timetable_crs.CrsCod "
" FROM timetable_crs,crs_grp_usr "
" WHERE crs_grp_usr.UsrCod='%ld' AND timetable_crs.GrpCod=crs_grp_usr.GrpCod "
" UNION "
" SELECT Day,Hour,Duration,Place, "
" 'tutorias' AS ClassType,'' AS GroupName,'-1' AS GrpCod,'-1' AS CrsCod "
" FROM timetable_tut "
" WHERE UsrCod='%ld' "
" ORDER BY Day,Hour,ClassType,GroupName,GrpCod,Place,Duration DESC,CrsCod " ,
UsrCod , UsrCod , UsrCod ) ;
break ;
case Grp_ALL_GROUPS :
sprintf ( Query , " SELECT timetable_crs.Day,timetable_crs.Hour,timetable_crs.Duration,timetable_crs.Place, "
" timetable_crs.ClassType,timetable_crs.GroupName,timetable_crs.GrpCod,timetable_crs.CrsCod "
" FROM timetable_crs,crs_usr "
" WHERE crs_usr.UsrCod='%ld' AND timetable_crs.CrsCod=crs_usr.CrsCod "
" UNION "
" SELECT Day,Hour,Duration,Place, "
" 'tutorias' AS ClassType,'' AS GroupName,'-1' AS GrpCod,'-1' AS CrsCod "
" FROM timetable_tut "
" WHERE UsrCod='%ld' "
" ORDER BY Day,Hour,ClassType, "
" GroupName,GrpCod,Place,Duration DESC,CrsCod " ,
UsrCod , UsrCod ) ;
break ;
}
break ;
case TT_COURSE_TIMETABLE :
if ( Gbl . CurrentCrs . Grps . WhichGrps = = Grp_ALL_GROUPS | |
2016-01-17 15:10:54 +01:00
Gbl . Action . Act = = ActEdiCrsTT | |
Gbl . Action . Act = = ActChgCrsTT ) // If we are editing, all groups are shown
2014-12-01 23:55:08 +01:00
sprintf ( Query , " SELECT Day,Hour,Duration,Place,ClassType,GroupName,GrpCod "
" FROM timetable_crs "
" WHERE CrsCod='%ld' "
" ORDER BY Day,Hour,ClassType,GroupName,GrpCod,Place,Duration DESC " ,
Gbl . CurrentCrs . Crs . CrsCod ) ;
else
sprintf ( Query , " SELECT timetable_crs.Day,timetable_crs.Hour,timetable_crs.Duration,timetable_crs.Place,timetable_crs.ClassType,timetable_crs.GroupName,timetable_crs.GrpCod "
" FROM timetable_crs,crs_usr "
" WHERE timetable_crs.CrsCod='%ld' AND timetable_crs.GrpCod='-1' AND crs_usr.UsrCod='%ld' AND timetable_crs.CrsCod=crs_usr.CrsCod "
" UNION DISTINCT "
" SELECT timetable_crs.Day,timetable_crs.Hour,timetable_crs.Duration,timetable_crs.Place, "
" timetable_crs.ClassType,timetable_crs.GroupName,timetable_crs.GrpCod "
" FROM timetable_crs,crs_grp_usr "
" WHERE timetable_crs.CrsCod='%ld' AND crs_grp_usr.UsrCod='%ld' AND timetable_crs.GrpCod=crs_grp_usr.GrpCod "
" ORDER BY Day,Hour,ClassType,GroupName,GrpCod,Place,Duration DESC " ,
Gbl . CurrentCrs . Crs . CrsCod , UsrCod ,
Gbl . CurrentCrs . Crs . CrsCod , UsrCod ) ;
break ;
case TT_TUTOR_TIMETABLE :
sprintf ( Query , " SELECT Day,Hour,Duration,Place "
" FROM timetable_tut "
" WHERE UsrCod='%ld' "
" ORDER BY Day,Hour,Place,Duration DESC " ,
UsrCod ) ;
break ;
}
NumRows = DB_QuerySELECT ( Query , & mysql_res , " can not get timetable " ) ;
/***** Build the table depending on the number of rows of the timetable *****/
for ( NumRow = 0 ;
NumRow < NumRows ;
NumRow + + )
{
row = mysql_fetch_row ( mysql_res ) ;
2016-03-18 14:07:21 +01:00
if ( Gbl . TimeTable . Type = = TT_MY_TIMETABLE | |
Gbl . TimeTable . Type = = TT_COURSE_TIMETABLE )
2014-12-01 23:55:08 +01:00
/* Group code */
if ( sscanf ( row [ 6 ] , " %ld " , & GrpCod ) ! = 1 )
GrpCod = - 1 ;
/* Day of week (row[0]) */
for ( Day = 0 ;
Day < TT_DAYS ;
Day + + )
if ( Str_ConvertToUpperLetter ( row [ 0 ] [ 0 ] ) = = TimeTableCharsDays [ Day ] )
break ;
if ( Day = = TT_DAYS )
Lay_ShowErrorAndExit ( " Wrong day of week in timetable. " ) ;
/* Hour (row[1]) */
if ( sscanf ( row [ 1 ] , " %u " , & Hour ) ! = 1 )
Lay_ShowErrorAndExit ( " Wrong hour in timetable. " ) ;
/* Duration (row[2]) */
if ( sscanf ( row [ 2 ] , " %u " , & Duration ) ! = 1 )
Lay_ShowErrorAndExit ( " Wrong duration in timetable. " ) ;
/* Type of class */
2016-03-18 14:07:21 +01:00
switch ( Gbl . TimeTable . Type )
2014-12-01 23:55:08 +01:00
{
case TT_COURSE_TIMETABLE :
case TT_MY_TIMETABLE :
for ( ClassType = TT_THEORY_CLASS , Found = false ;
ClassType < = TT_TUTOR_CLASS ;
ClassType + + )
if ( ! strcmp ( row [ 4 ] , TimeTableStrsClassTypeDB [ ClassType ] ) )
{
Found = true ;
break ;
}
if ( ! Found )
Lay_ShowErrorAndExit ( " Wrong type of class in timetable. " ) ;
break ;
case TT_TUTOR_TIMETABLE :
ClassType = TT_TUTOR_CLASS ;
break ;
}
/* Cell has been read without errors. */
if ( TimeTable [ Day ] [ Hour ] . NumColumns < TT_MAX_COLUMNS_PER_CELL ) // If there's place for another column in this cell...
{
/* Find the first free column for this day-hour */
FirstFreeColumn = TT_MAX_COLUMNS_PER_CELL ;
for ( Column = 0 ;
Column < TT_MAX_COLUMNS_PER_CELL ;
Column + + )
if ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType = = TT_FREE_HOUR )
{
FirstFreeColumn = Column ;
break ;
}
if ( FirstFreeColumn < TT_MAX_COLUMNS_PER_CELL ) // If there's place for another column in this cell
{
/* Check if there's place for all the rows of this class */
TimeTableHasSpaceForThisClass = true ;
for ( H = Hour + 1 ;
H < Hour + Duration & & H < TT_HOURS_PER_DAY * 2 ;
H + + )
if ( TimeTable [ Day ] [ H ] . Columns [ FirstFreeColumn ] . HourType ! = TT_FREE_HOUR )
{
TimeTableIsIncomplete = true ;
TimeTableHasSpaceForThisClass = false ;
break ;
}
if ( TimeTableHasSpaceForThisClass )
{
TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . ClassType = ClassType ;
TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . Duration = Duration ;
TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . HourType = TT_FIRST_HOUR ;
for ( H = Hour + 1 ;
H < Hour + Duration & & H < TT_HOURS_PER_DAY * 2 ;
H + + )
{
TimeTable [ Day ] [ H ] . Columns [ FirstFreeColumn ] . HourType = TT_NEXT_HOUR ;
TimeTable [ Day ] [ H ] . NumColumns + + ;
}
/* Group and place */
2016-03-18 14:07:21 +01:00
switch ( Gbl . TimeTable . Type )
2014-12-01 23:55:08 +01:00
{
case TT_MY_TIMETABLE :
case TT_COURSE_TIMETABLE :
TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . CrsCod =
2016-03-18 14:07:21 +01:00
( Gbl . TimeTable . Type = = TT_MY_TIMETABLE ? Str_ConvertStrCodToLongCod ( row [ 7 ] ) :
Gbl . CurrentCrs . Crs . CrsCod ) ;
2014-12-01 23:55:08 +01:00
strcpy ( TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . Group , row [ 5 ] ) ;
TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . GrpCod = GrpCod ;
// no break;
case TT_TUTOR_TIMETABLE :
strcpy ( TimeTable [ Day ] [ Hour ] . Columns [ FirstFreeColumn ] . Place , row [ 3 ] ) ;
break ;
}
/* Increment number of items in this cell */
TimeTable [ Day ] [ Hour ] . NumColumns + + ;
}
}
else
TimeTableIsIncomplete = true ;
}
else
TimeTableIsIncomplete = true ;
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult ( & mysql_res ) ;
if ( TimeTableIsIncomplete )
2016-11-13 20:54:06 +01:00
Lay_ShowAlert ( Lay_INFO , Txt_Incomplete_timetable_for_lack_of_space ) ;
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*********************** Modify a class in timetable *************************/
/*****************************************************************************/
static void TT_ModifTimeTable ( void )
{
if ( TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . HourType = = TT_FIRST_HOUR )
{
/***** Free this cell *****/
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . GrpCod = - 1 ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . HourType = TT_FREE_HOUR ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . ClassType = TT_NO_CLASS ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Duration = 0 ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Group [ 0 ] = ' \0 ' ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Place [ 0 ] = ' \0 ' ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . NumColumns - - ;
}
if ( Gbl . TimeTable . ClassType ! = TT_NO_CLASS & & Gbl . TimeTable . Duration > 0 & &
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . NumColumns < TT_MAX_COLUMNS_PER_CELL )
{
/***** Change this cell *****/
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . NumColumns + + ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . GrpCod = Gbl . TimeTable . GrpCod ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . HourType = TT_FIRST_HOUR ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . ClassType = Gbl . TimeTable . ClassType ;
TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Duration = Gbl . TimeTable . Duration ;
strcpy ( TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Group , Gbl . TimeTable . Group ) ;
strcpy ( TimeTable [ Gbl . TimeTable . Day ] [ Gbl . TimeTable . Hour ] . Columns [ Gbl . TimeTable . Column ] . Place , Gbl . TimeTable . Place ) ;
}
}
/*****************************************************************************/
/********************* Draw timetable using internal table *******************/
/*****************************************************************************/
2016-03-18 14:07:21 +01:00
static void TT_DrawTimeTable ( void )
2014-12-01 23:55:08 +01:00
{
bool Editing = false ;
2015-11-30 21:23:14 +01:00
unsigned DayColumn ; // Column from left (0) to right (6)
unsigned Day ; // Day of week
unsigned Hour ;
unsigned H ;
unsigned Column ;
unsigned ColumnsToDraw ;
unsigned ColumnsToDrawIncludingExtraColumn ;
unsigned ContinuousFreeMinicolumns ;
2014-12-01 23:55:08 +01:00
2016-01-17 15:10:54 +01:00
switch ( Gbl . Action . Act )
2014-12-01 23:55:08 +01:00
{
2015-12-01 00:38:22 +01:00
case ActSeeCrsTT : case ActPrnCrsTT : case ActChgCrsTT1stDay :
case ActSeeMyTT : case ActPrnMyTT : case ActChgMyTT1stDay :
2014-12-01 23:55:08 +01:00
case ActSeeRecOneTch : case ActSeeRecSevTch :
Editing = false ;
break ;
2015-12-01 00:38:22 +01:00
case ActEdiCrsTT : case ActChgCrsTT :
2014-12-01 23:55:08 +01:00
case ActEdiTut : case ActChgTut :
// If editing and there's place for more columns, a potential new column is added at the end of each day
Editing = true ;
break ;
}
/***** Table start *****/
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <table id= \" timetable \" > " ) ;
2014-12-01 23:55:08 +01:00
/***** Top row used for column adjustement *****/
TT_TimeTableDrawAdjustRow ( ) ;
/***** Row with day names *****/
fprintf ( Gbl . F . Out , " <tr> "
2015-11-30 20:47:37 +01:00
" <td rowspan= \" 2 \" class= \" TT_TXT RIGHT_MIDDLE \" "
" style= \" width:%u%%; height:40px; \" > "
2014-12-26 16:55:46 +01:00
" %u:00 "
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN , TT_START_HOUR ) ;
TT_DrawCellAlignTimeTable ( ) ;
TT_TimeTableDrawDaysCells ( ) ;
TT_DrawCellAlignTimeTable ( ) ;
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td rowspan= \" 2 \" class= \" TT_TXT LEFT_MIDDLE \" "
" style= \" width:%u%%; height:40px; \" > "
2014-12-26 16:55:46 +01:00
" %u:00 "
" </td> "
2014-12-01 23:55:08 +01:00
" </tr> " ,
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN , TT_START_HOUR ) ;
/***** Get list of groups types and groups in this course *****/
2016-01-17 15:10:54 +01:00
if ( Gbl . Action . Act = = ActEdiCrsTT | |
Gbl . Action . Act = = ActChgCrsTT )
2014-12-01 23:55:08 +01:00
Grp_GetListGrpTypesAndGrpsInThisCrs ( Grp_ONLY_GROUP_TYPES_WITH_GROUPS ) ;
/***** Write the table row by row *****/
for ( Hour = 0 ;
Hour < TT_HOURS_PER_DAY * 2 ;
Hour + + )
{
fprintf ( Gbl . F . Out , " <tr> " ) ;
/* Hour */
if ( Hour % 2 )
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td rowspan= \" 2 \" class= \" TT_TXT RIGHT_MIDDLE \" "
" style= \" width:%u%%; height:40px; \" > "
2014-12-26 16:55:46 +01:00
" %2u:00 "
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN , TT_START_HOUR + ( Hour + 1 ) / 2 ) ;
/* Empty column used to adjust height */
TT_DrawCellAlignTimeTable ( ) ;
/* Row for this hour */
2015-11-30 21:23:14 +01:00
for ( DayColumn = 0 ;
DayColumn < TT_DAYS ;
DayColumn + + )
2014-12-01 23:55:08 +01:00
{
2015-11-30 21:23:14 +01:00
/* Day == 0 ==> monday,
. . .
Day = = 6 = = > sunday */
Day = ( DayColumn + Gbl . Prefs . FirstDayOfWeek ) % 7 ;
2014-12-01 23:55:08 +01:00
/* Check how many colums are needed.
For each item ( class ) in this hour from left to right , we must check the maximum of columns */
for ( H = 0 ;
H < TT_HOURS_PER_DAY * 2 ;
H + + )
TimeTableHoursChecked [ H ] = false ;
ColumnsToDraw = TT_TimeTableCalculateColsToDraw ( Day , Hour ) ;
if ( ! Editing & & ColumnsToDraw = = 0 )
ColumnsToDraw = 1 ;
ColumnsToDrawIncludingExtraColumn = ColumnsToDraw ;
if ( Editing & & ColumnsToDraw < TT_MAX_COLUMNS_PER_CELL )
ColumnsToDrawIncludingExtraColumn + + ;
/* Draw cells */
for ( Column = 0 , ContinuousFreeMinicolumns = 0 ;
Column < ColumnsToDrawIncludingExtraColumn ;
Column + + )
if ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType = = TT_FREE_HOUR )
ContinuousFreeMinicolumns + = TT_NUM_MINICOLUMNS_PER_DAY / ColumnsToDrawIncludingExtraColumn ;
else
{
if ( ContinuousFreeMinicolumns )
{
2016-03-18 14:07:21 +01:00
TT_TimeTableDrawCell ( Day , Hour , Column - 1 , ContinuousFreeMinicolumns ,
2015-12-01 00:38:22 +01:00
- 1L , TT_FREE_HOUR , TT_NO_CLASS , 0 , NULL , - 1 , NULL ) ;
2014-12-01 23:55:08 +01:00
ContinuousFreeMinicolumns = 0 ;
}
2016-03-18 14:07:21 +01:00
TT_TimeTableDrawCell ( Day , Hour , Column , TT_NUM_MINICOLUMNS_PER_DAY / ColumnsToDrawIncludingExtraColumn ,
2014-12-01 23:55:08 +01:00
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . CrsCod ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . ClassType ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Group ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . GrpCod ,
TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Place ) ;
}
if ( ContinuousFreeMinicolumns )
2016-03-18 14:07:21 +01:00
TT_TimeTableDrawCell ( Day , Hour , Column - 1 , ContinuousFreeMinicolumns ,
2015-12-01 00:38:22 +01:00
- 1L , TT_FREE_HOUR , TT_NO_CLASS , 0 , NULL , - 1L , NULL ) ;
2014-12-01 23:55:08 +01:00
}
/* Empty column used to adjust height */
TT_DrawCellAlignTimeTable ( ) ;
/* Hour */
if ( Hour % 2 )
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td rowspan= \" 2 \" class= \" TT_TXT LEFT_MIDDLE \" "
" style= \" width:%u%%; height:40px; \" > "
2014-12-26 16:55:46 +01:00
" %2u:00 "
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN , TT_START_HOUR + ( Hour + 1 ) / 2 ) ;
fprintf ( Gbl . F . Out , " </tr> " ) ;
}
/***** Free list of groups types and groups in this course *****/
2016-01-17 15:10:54 +01:00
if ( Gbl . Action . Act = = ActEdiCrsTT | |
Gbl . Action . Act = = ActChgCrsTT )
2014-12-01 23:55:08 +01:00
Grp_FreeListGrpTypesAndGrps ( ) ;
/***** Row with day names *****/
fprintf ( Gbl . F . Out , " <tr> " ) ;
TT_DrawCellAlignTimeTable ( ) ;
TT_TimeTableDrawDaysCells ( ) ;
TT_DrawCellAlignTimeTable ( ) ;
fprintf ( Gbl . F . Out , " </tr> " ) ;
/***** Bottom row used for column adjustement *****/
TT_TimeTableDrawAdjustRow ( ) ;
/***** End of the table *****/
fprintf ( Gbl . F . Out , " </table> " ) ;
}
/*****************************************************************************/
/********** Draw a row used for column adjustement in a time table ***********/
/*****************************************************************************/
static void TT_TimeTableDrawAdjustRow ( void )
{
unsigned Day ;
unsigned Minicolumn ;
fprintf ( Gbl . F . Out , " <tr> "
2015-11-30 20:47:37 +01:00
" <td class= \" TT_TXT LEFT_MIDDLE \" style= \" width:%u%%; \" > "
2015-12-01 00:38:22 +01:00
" "
2014-12-26 16:55:46 +01:00
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN ) ;
TT_DrawCellAlignTimeTable ( ) ;
for ( Day = 0 ;
Day < TT_DAYS ;
Day + + )
for ( Minicolumn = 0 ;
Minicolumn < TT_NUM_MINICOLUMNS_PER_DAY ;
Minicolumn + + )
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td class= \" TT_TXT LEFT_MIDDLE \" "
2015-09-02 23:51:44 +02:00
" style= \" width:%u%%; \" > "
2015-12-01 00:38:22 +01:00
" "
2014-12-26 16:55:46 +01:00
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_A_MINICOLUMN ) ;
TT_DrawCellAlignTimeTable ( ) ;
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td class= \" TT_TXT LEFT_MIDDLE \" "
2015-09-02 23:51:44 +02:00
" style= \" width:%u%%; \" > "
2015-12-01 00:38:22 +01:00
" "
2014-12-26 16:55:46 +01:00
" </td> "
2014-12-01 23:55:08 +01:00
" </tr> " ,
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN ) ;
}
/*****************************************************************************/
/****************** Draw cells with day names in a time table ****************/
/*****************************************************************************/
static void TT_TimeTableDrawDaysCells ( void )
{
extern const char * Txt_DAYS_CAPS [ 7 ] ;
2015-11-30 21:23:14 +01:00
unsigned DayColumn ;
2014-12-01 23:55:08 +01:00
unsigned Day ;
2015-11-30 21:23:14 +01:00
for ( DayColumn = 0 ;
DayColumn < TT_DAYS ;
DayColumn + + )
{
Day = ( DayColumn + Gbl . Prefs . FirstDayOfWeek ) % 7 ;
fprintf ( Gbl . F . Out , " <td colspan= \" %u \" class= \" %s CENTER_MIDDLE \" "
2015-09-02 23:51:44 +02:00
" style= \" width:%u%%; \" > "
2014-12-26 16:55:46 +01:00
" %s "
" </td> " ,
2015-11-30 21:23:14 +01:00
TT_NUM_MINICOLUMNS_PER_DAY ,
Day = = 6 ? " TT_SUNDAY " : // Sunday drawn in red
" TT_DAY " , // Monday to Saturday
TT_PERCENT_WIDTH_OF_A_DAY ,
2014-12-26 16:55:46 +01:00
Txt_DAYS_CAPS [ Day ] ) ;
2015-11-30 21:23:14 +01:00
}
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**** Calculate recursively number of columns to draw for a day and hour *****/
/*****************************************************************************/
static unsigned TT_TimeTableCalculateColsToDraw ( unsigned Day , unsigned Hour )
{
2015-11-30 21:23:14 +01:00
unsigned ColumnsToDraw ;
unsigned Column ;
unsigned H ;
unsigned FirstHour ;
unsigned Cols ;
2014-12-01 23:55:08 +01:00
ColumnsToDraw = TimeTable [ Day ] [ Hour ] . NumColumns ;
if ( ! TimeTableHoursChecked [ Hour ] )
{
TimeTableHoursChecked [ Hour ] = true ;
for ( Column = 0 ;
Column < TT_MAX_COLUMNS_PER_CELL ;
Column + + )
{
switch ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . HourType )
{
case TT_FREE_HOUR :
break ;
case TT_FIRST_HOUR :
/* Check from first hour (this one) to last hour searching maximum number of columns */
for ( H = Hour + 1 ;
H < Hour + TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ;
H + + )
if ( ! TimeTableHoursChecked [ H ] )
{
Cols = TT_TimeTableCalculateColsToDraw ( Day , H ) ;
if ( Cols > ColumnsToDraw )
ColumnsToDraw = Cols ;
}
break ;
case TT_NEXT_HOUR :
/* Find first hour for this item (class) */
for ( FirstHour = Hour ;
TimeTable [ Day ] [ FirstHour ] . Columns [ Column ] . HourType = = TT_NEXT_HOUR ;
FirstHour - - ) ;
/* Check from first hour to last hour searching maximum number of columns */
for ( H = FirstHour ;
H < FirstHour + TimeTable [ Day ] [ FirstHour ] . Columns [ Column ] . Duration ;
H + + )
if ( ! TimeTableHoursChecked [ H ] )
{
Cols = TT_TimeTableCalculateColsToDraw ( Day , H ) ;
if ( Cols > ColumnsToDraw )
ColumnsToDraw = Cols ;
}
break ;
}
}
}
return ColumnsToDraw ;
}
/*****************************************************************************/
/******************** Write empty cell for alignment *************************/
/*****************************************************************************/
static void TT_DrawCellAlignTimeTable ( void )
{
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <td class= \" TT_TXT LEFT_MIDDLE \" style= \" width:%u%%; \" > "
2015-12-01 00:38:22 +01:00
" "
2014-12-26 16:55:46 +01:00
" </td> " ,
2014-12-01 23:55:08 +01:00
TT_PERCENT_WIDTH_OF_A_SEPARATION_COLUMN ) ;
}
/*****************************************************************************/
/*************************** Write a timetable cell **************************/
/*****************************************************************************/
2016-03-18 14:07:21 +01:00
static void TT_TimeTableDrawCell ( unsigned Day , unsigned Hour , unsigned Column , unsigned ColSpan ,
2014-12-01 23:55:08 +01:00
long CrsCod , TT_HourType_t HourType , TT_ClassType_t ClassType , unsigned Duration , char * Group , long GrpCod , char * Place )
{
2016-10-02 20:03:21 +02:00
extern const char * Txt_unknown_removed_course ;
2015-01-02 12:57:26 +01:00
extern const char * Txt_TIMETABLE_CLASS_TYPES [ TT_NUM_CLASS_TYPES ] ;
2014-12-01 23:55:08 +01:00
extern const char * Txt_Group ;
extern const char * Txt_All_groups ;
extern const char * Txt_Classroom ;
extern const char * Txt_Place ;
static const char * TimeTableClasses [ TT_NUM_CLASS_TYPES ] =
{
" FREE " , // Free hour
" THEO " , // Theoretical class
" PRAC " , // Practical class
" TUTO " // Tutorials
} ;
enum
{
TT_CRS_SHOW ,
TT_CRS_EDIT ,
TT_TUT_SHOW ,
TT_TUT_EDIT ,
} TimeTableView = TT_CRS_SHOW ;
struct GroupData GrpDat ;
unsigned NumGrpTyp ;
unsigned NumGrp ;
unsigned H ;
unsigned Dur ;
unsigned MaxDuration ;
unsigned RowSpan = 0 ;
TT_ClassType_t CT ;
struct Course Crs ;
/***** Compute row span and background color depending on hour type *****/
switch ( HourType )
{
2015-11-30 20:47:37 +01:00
case TT_FREE_HOUR : // Free cell written
RowSpan = 1 ;
2014-12-01 23:55:08 +01:00
break ;
2015-11-30 20:47:37 +01:00
case TT_FIRST_HOUR : // Normal cell written
2014-12-01 23:55:08 +01:00
RowSpan = Duration ;
break ;
2015-11-30 20:47:37 +01:00
case TT_NEXT_HOUR : // Nothing written
2014-12-01 23:55:08 +01:00
break ;
}
/***** If there's nothing to do... *****/
if ( RowSpan = = 0 )
return ;
/***** Set type of view depending on current action *****/
2016-01-17 15:10:54 +01:00
switch ( Gbl . Action . Act )
2014-12-01 23:55:08 +01:00
{
2015-12-01 00:38:22 +01:00
case ActSeeCrsTT : case ActPrnCrsTT : case ActChgCrsTT1stDay :
case ActSeeMyTT : case ActPrnMyTT : case ActChgMyTT1stDay :
2014-12-01 23:55:08 +01:00
TimeTableView = TT_CRS_SHOW ;
break ;
2015-12-01 00:38:22 +01:00
case ActEdiCrsTT : case ActChgCrsTT :
2014-12-01 23:55:08 +01:00
TimeTableView = TT_CRS_EDIT ;
break ;
case ActSeeRecOneTch : case ActSeeRecSevTch :
TimeTableView = TT_TUT_SHOW ;
break ;
case ActEdiTut : case ActChgTut :
TimeTableView = TT_TUT_EDIT ;
break ;
}
/***** If group code > 0, a group is selected ==> get group type and name *****/
if ( HourType = = TT_FIRST_HOUR & &
( TimeTableView = = TT_CRS_SHOW | |
TimeTableView = = TT_CRS_EDIT ) & &
GrpCod > 0 )
{
/* Get group type and name */
GrpDat . GrpCod = GrpCod ;
Grp_GetDataOfGroupByCod ( & GrpDat ) ;
}
/***** Cell start *****/
2014-12-26 16:55:46 +01:00
fprintf ( Gbl . F . Out , " <td rowspan= \" %u \" colspan= \" %u \" class= \" %s " ,
2014-12-01 23:55:08 +01:00
RowSpan , ColSpan , TimeTableClasses [ ClassType ] ) ;
if ( ClassType = = TT_NO_CLASS )
fprintf ( Gbl . F . Out , " %u " , Hour % 4 ) ;
2015-09-02 23:51:44 +02:00
fprintf ( Gbl . F . Out , " CENTER_MIDDLE \" > " ) ;
2014-12-01 23:55:08 +01:00
/***** Form to modify this cell *****/
if ( TimeTableView = = TT_CRS_EDIT )
2015-12-01 00:38:22 +01:00
Act_FormStart ( ActChgCrsTT ) ;
2014-12-01 23:55:08 +01:00
else if ( TimeTableView = = TT_TUT_EDIT )
Act_FormStart ( ActChgTut ) ;
/***** Draw cell depending on type of view *****/
switch ( TimeTableView )
{
case TT_CRS_SHOW :
case TT_TUT_SHOW :
2015-11-30 20:47:37 +01:00
if ( HourType ! = TT_FREE_HOUR ) // If cell is not empty...
2014-12-01 23:55:08 +01:00
{
2015-11-30 20:47:37 +01:00
fprintf ( Gbl . F . Out , " <span class= \" TT_TXT \" > " ) ;
2016-03-18 14:07:21 +01:00
if ( Gbl . TimeTable . Type = = TT_MY_TIMETABLE )
2014-12-01 23:55:08 +01:00
{
Crs . CrsCod = CrsCod ;
Crs_GetDataOfCourseByCod ( & Crs ) ;
if ( ClassType = = TT_THEORY_CLASS | |
ClassType = = TT_PRACT_CLASS )
fprintf ( Gbl . F . Out , " %s<br /> " ,
2016-10-28 10:03:37 +02:00
Crs . ShrtName [ 0 ] ? Crs . ShrtName :
Txt_unknown_removed_course ) ;
2014-12-01 23:55:08 +01:00
}
fprintf ( Gbl . F . Out , " %s (%dh%s) " ,
2015-01-02 12:57:26 +01:00
Txt_TIMETABLE_CLASS_TYPES [ ClassType ] ,
2014-12-01 23:55:08 +01:00
Duration / 2 ,
Duration % 2 ? " 30' " :
" " ) ;
if ( TimeTableView = = TT_CRS_SHOW )
{
if ( GrpCod = = - 1 )
{
if ( Group [ 0 ] )
fprintf ( Gbl . F . Out , " <br />%s " , Group ) ;
}
else
{
Str_LimitLengthHTMLStr ( GrpDat . GrpTypName , 12 ) ;
Str_LimitLengthHTMLStr ( GrpDat . GrpName , 12 ) ;
fprintf ( Gbl . F . Out , " <br />%s %s " ,
GrpDat . GrpTypName , GrpDat . GrpName ) ;
}
if ( Place [ 0 ] )
fprintf ( Gbl . F . Out , " <br />%s " , Place ) ;
}
else // TimeTableView == TT_TUT_SHOW
if ( Place [ 0 ] )
fprintf ( Gbl . F . Out , " <br />%s " , Place ) ;
fprintf ( Gbl . F . Out , " </span> " ) ;
}
break ;
case TT_CRS_EDIT :
case TT_TUT_EDIT :
Par_PutHiddenParamUnsigned ( " ModTTDay " , Day ) ;
Par_PutHiddenParamUnsigned ( " ModTTHour " , Hour ) ;
Par_PutHiddenParamUnsigned ( " ModTTCol " , Column ) ;
fprintf ( Gbl . F . Out , " <span class= \" DAT_SMALL \" > " ) ;
/***** Class type *****/
2015-09-28 18:28:29 +02:00
fprintf ( Gbl . F . Out , " <select name= \" ModTTCellType \" style= \" width:68px; \" "
2015-10-22 14:49:48 +02:00
" onchange= \" document.getElementById('%s').submit(); \" > " ,
2016-01-14 10:31:09 +01:00
Gbl . Form . Id ) ;
2014-12-01 23:55:08 +01:00
for ( CT = ( TT_ClassType_t ) 0 ;
CT < ( TT_ClassType_t ) TT_NUM_CLASS_TYPES ;
CT + + )
if ( ( CT = = TT_NO_CLASS ) | |
( ( TimeTableView = = TT_CRS_EDIT ) & & ( CT = = TT_THEORY_CLASS | | CT = = TT_PRACT_CLASS ) ) | |
( ( TimeTableView = = TT_TUT_EDIT ) & & ( CT = = TT_TUTOR_CLASS ) ) )
{
fprintf ( Gbl . F . Out , " <option " ) ;
if ( CT = = ClassType )
fprintf ( Gbl . F . Out , " selected= \" selected \" " ) ;
fprintf ( Gbl . F . Out , " value= \" %s \" >%s</option> " ,
TimeTableStrsClassTypeDB [ CT ] ,
2015-01-02 12:57:26 +01:00
Txt_TIMETABLE_CLASS_TYPES [ CT ] ) ;
2014-12-01 23:55:08 +01:00
}
fprintf ( Gbl . F . Out , " </select> " ) ;
if ( HourType = = TT_FREE_HOUR )
{
fprintf ( Gbl . F . Out , " <input type= \" hidden \" name= \" ModTTDur \" value= \" " ) ;
for ( H = Hour + 1 ;
H < TT_HOURS_PER_DAY * 2 ;
H + + )
if ( TimeTable [ Day ] [ H ] . NumColumns = = TT_MAX_COLUMNS_PER_CELL )
break ;
MaxDuration = H - Hour ;
if ( MaxDuration > 1 )
fprintf ( Gbl . F . Out , " 1:00 " ) ;
else
fprintf ( Gbl . F . Out , " 0:30 " ) ;
fprintf ( Gbl . F . Out , " h \" /> " ) ;
Par_PutHiddenParamString ( " ModHorGrp " , " " ) ;
Par_PutHiddenParamString ( " ModHorLugar " , " " ) ;
}
else
{
/***** Class duration *****/
2015-09-28 18:28:29 +02:00
fprintf ( Gbl . F . Out , " <select name= \" ModTTDur \" style= \" width:57px; \" "
2015-10-22 14:49:48 +02:00
" onchange= \" document.getElementById('%s').submit(); \" > " ,
2016-01-14 10:31:09 +01:00
Gbl . Form . Id ) ;
2014-12-01 23:55:08 +01:00
for ( H = Hour + TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ;
H < TT_HOURS_PER_DAY * 2 ;
H + + )
if ( TimeTable [ Day ] [ H ] . NumColumns = = TT_MAX_COLUMNS_PER_CELL )
break ;
MaxDuration = H - Hour ;
if ( TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration > MaxDuration )
MaxDuration = TimeTable [ Day ] [ Hour ] . Columns [ Column ] . Duration ;
for ( Dur = 0 ;
Dur < = MaxDuration ;
Dur + + )
{
fprintf ( Gbl . F . Out , " <option " ) ;
if ( Dur = = Duration )
fprintf ( Gbl . F . Out , " selected= \" selected \" " ) ;
fprintf ( Gbl . F . Out , " >%d:%02d h</option> " ,
Dur / 2 ,
Dur % 2 ? 30 :
0 ) ;
}
fprintf ( Gbl . F . Out , " </select> " ) ;
if ( TimeTableView = = TT_CRS_EDIT )
{
/***** Group *****/
fprintf ( Gbl . F . Out , " <br />%s "
2015-09-06 19:51:06 +02:00
" <select name= \" ModTTGrpCod \" "
2015-09-28 18:28:29 +02:00
" style= \" width:110px; \" "
2015-10-22 14:49:48 +02:00
" onchange= \" document.getElementById('%s').submit(); \" > " ,
2016-01-14 10:31:09 +01:00
Txt_Group , Gbl . Form . Id ) ;
2014-12-01 23:55:08 +01:00
fprintf ( Gbl . F . Out , " <option value= \" -1 \" " ) ;
if ( GrpCod < = 0 )
fprintf ( Gbl . F . Out , " selected= \" selected \" " ) ;
fprintf ( Gbl . F . Out , " >%s</option> " , Txt_All_groups ) ;
for ( NumGrpTyp = 0 ;
NumGrpTyp < Gbl . CurrentCrs . Grps . GrpTypes . Num ;
NumGrpTyp + + )
for ( NumGrp = 0 ;
NumGrp < Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . NumGrps ;
NumGrp + + )
{
fprintf ( Gbl . F . Out , " <option value= \" %ld \" " ,
Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . LstGrps [ NumGrp ] . GrpCod ) ;
if ( GrpCod = = Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . LstGrps [ NumGrp ] . GrpCod )
fprintf ( Gbl . F . Out , " selected= \" selected \" " ) ;
Str_LimitLengthHTMLStr ( Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . GrpTypName , 8 ) ;
Str_LimitLengthHTMLStr ( Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . LstGrps [ NumGrp ] . GrpName , 8 ) ;
fprintf ( Gbl . F . Out , " >%s %s</option> " ,
Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . GrpTypName ,
Gbl . CurrentCrs . Grps . GrpTypes . LstGrpTypes [ NumGrpTyp ] . LstGrps [ NumGrp ] . GrpName ) ;
}
fprintf ( Gbl . F . Out , " </select> " ) ;
/***** Class room *****/
fprintf ( Gbl . F . Out , " <br />%s "
2015-10-22 14:49:48 +02:00
" <input type= \" text \" name= \" ModHorLugar \" "
" size= \" 1 \" maxlength= \" %u \" value= \" %s \" "
" onchange= \" document.getElementById('%s').submit(); \" /> " ,
2016-01-14 10:31:09 +01:00
Txt_Classroom , TT_MAX_LENGTH_PLACE , Place , Gbl . Form . Id ) ;
2014-12-01 23:55:08 +01:00
}
else // TimeTableView == TT_TUT_EDIT
{
Par_PutHiddenParamString ( " ModHorGrp " , " " ) ;
/***** Place *****/
fprintf ( Gbl . F . Out , " <br />%s "
2015-10-22 14:49:48 +02:00
" <input type= \" text \" name= \" ModHorLugar \" "
" size= \" 12 \" maxlength= \" %u \" value= \" %s \" "
" onchange= \" document.getElementById('%s').submit(); \" /> " ,
2016-01-14 10:31:09 +01:00
Txt_Place , TT_MAX_LENGTH_PLACE , Place , Gbl . Form . Id ) ;
2014-12-01 23:55:08 +01:00
}
}
fprintf ( Gbl . F . Out , " </span> " ) ;
break ;
}
/***** End of form *****/
if ( TimeTableView = = TT_CRS_EDIT | |
TimeTableView = = TT_TUT_EDIT )
2015-03-13 00:16:02 +01:00
Act_FormEnd ( ) ;
2014-12-01 23:55:08 +01:00
/***** End of cell *****/
fprintf ( Gbl . F . Out , " </td> " ) ;
}