swad-core/swad_timetable.c

1728 lines
68 KiB
C
Raw Normal View History

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.
2017-01-13 01:51:23 +01:00
Copyright (C) 1999-2017 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;
/*****************************************************************************/
2017-04-25 14:48:47 +02:00
/************************ Internal constants and types ***********************/
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
2017-04-24 21:12:53 +02:00
#define TT_DAYS_PER_WEEK 7 // Seven days per week
#define TT_MINUTES_PER_HOUR 60 // Number of minutes in 1 hour
#define TT_SECONDS_PER_MINUTE 60 // Number of seconds in 1 minute
2017-04-25 21:20:19 +02:00
#define TT_SECONDS_PER_HOUR (TT_SECONDS_PER_MINUTE * TT_MINUTES_PER_HOUR) // Number of seconds in 1 hour
2017-04-25 14:48:47 +02:00
#define TT_START_HOUR 6 // Day starts at this hour
#define TT_END_HOUR 24 // Day ends at this hour
#define TT_MIN_MINUTES_PER_INTERVAL 5
#define TT_MAX_MINUTES_PER_INTERVAL 30
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
2017-04-24 21:12:53 +02:00
2014-12-01 23:55:08 +01:00
#define TT_PERCENT_WIDTH_OF_A_MINICOLUMN 2 // Width (%) of each minicolumn
2017-01-29 21:41:08 +01:00
#define TT_PERCENT_WIDTH_OF_A_DAY (TT_PERCENT_WIDTH_OF_A_MINICOLUMN * TT_NUM_MINICOLUMNS_PER_DAY) // Width (%) of each day
2017-04-24 21:12:53 +02:00
#define TT_PERCENT_WIDTH_OF_ALL_DAYS (TT_PERCENT_WIDTH_OF_A_DAY * TT_DAYS_PER_WEEK) // Width (%) of all days
#define TT_PERCENT_WIDTH_OF_A_SEPARATION_COLUMN 1 // Width (%) of left and right columns (frame)
2017-01-28 15:58:46 +01:00
#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
2014-12-01 23:55:08 +01:00
#define TT_MAX_BYTES_STR_CLASS_TYPE 256
2017-03-08 03:48:23 +01:00
#define TT_MAX_BYTES_STR_DURATION 32 // "hh:mm h"
2014-12-01 23:55:08 +01:00
2017-04-25 14:48:47 +02:00
struct TT_Column
{
long CrsCod; // Course code (-1 if no course selected)
long GrpCod; // Group code (-1 if no group selected)
TT_IntervalType_t IntervalType;
TT_ClassType_t ClassType;
2017-04-25 21:20:19 +02:00
unsigned DurationIntervals;
2017-04-25 14:48:47 +02:00
char Place[TT_MAX_BYTES_PLACE + 1];
char Group[Grp_MAX_BYTES_GROUP_NAME + 1];
};
struct TT_Cell
{
unsigned NumColumns;
struct TT_Column Columns[TT_MAX_COLUMNS_PER_CELL];
};
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/************************* Internal global variables *************************/
/*****************************************************************************/
2017-04-25 14:48:47 +02:00
char *TT_ClassTypeDB[TT_NUM_CLASS_TYPES] =
2017-04-24 13:00:59 +02:00
{
"free",
"lecture",
"practical",
"tutoring",
};
2017-04-24 13:39:55 +02:00
2017-04-25 14:48:47 +02:00
struct TT_Cell *TT_TimeTable[TT_DAYS_PER_WEEK];
2017-04-24 13:39:55 +02:00
2017-04-25 14:48:47 +02:00
/* Possible resolutions of the timetable in minutes */
#define TT_NUM_RESOLUTIONS 3
2017-04-25 21:20:19 +02:00
unsigned TT_MinutesPerInterval[TT_NUM_RESOLUTIONS] =
2017-04-24 13:39:55 +02:00
{
2017-04-25 14:48:47 +02:00
5, // 5 minutes
15, // 15 minutes // Use 10 or 15 minutes (15 looks better), never both together
30, // 30 minutes
2017-04-25 11:57:36 +02:00
};
2017-04-24 13:39:55 +02:00
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/***************************** Internal prototypes **************************/
/*****************************************************************************/
2017-04-25 14:48:47 +02:00
static void TT_TimeTableConfigureIntervalsAndAllocateTimeTable (void);
2017-04-25 21:20:19 +02:00
static void TT_FreeTimeTable (void);
2017-04-25 11:57:36 +02:00
2014-12-01 23:55:08 +01:00
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);
2017-04-25 11:57:36 +02:00
static void TT_FillTimeTableFromDB (long UsrCod);
2017-04-25 21:20:19 +02:00
static void TT_CalculateRangeCell (unsigned StartTimeSeconds,
unsigned EndTimeSeconds,
struct TT_Range *Range);
static unsigned TT_CalculateMinutesPerInterval (unsigned Seconds);
2017-04-25 14:48:47 +02:00
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);
2017-04-24 21:12:53 +02:00
static void TT_TimeTableDrawHourCell (unsigned Hour,unsigned Min,const char *Align);
2017-04-25 11:57:36 +02:00
static unsigned TT_CalculateColsToDrawInCell (bool TopCall,
unsigned Weekday,unsigned Interval);
2014-12-01 23:55:08 +01:00
static void TT_DrawCellAlignTimeTable (void);
2017-04-24 21:12:53 +02:00
static void TT_TimeTableDrawCell (unsigned Weekday,unsigned Interval,unsigned Column,unsigned ColSpan,
long CrsCod,TT_IntervalType_t IntervalType,TT_ClassType_t ClassType,
unsigned DurationNumIntervals,char *Group,long GrpCod,char *Place);
2014-12-01 23:55:08 +01:00
2017-04-25 11:57:36 +02:00
/*****************************************************************************/
/******************** Create internal timetable in memory ********************/
/*****************************************************************************/
2017-04-25 21:20:19 +02:00
static void TT_TimeTableConfigureIntervalsAndAllocateTimeTable (void)
2017-04-25 11:57:36 +02:00
{
2017-04-25 21:20:19 +02:00
unsigned Weekday;
2017-04-25 14:48:47 +02:00
2017-04-25 21:20:19 +02:00
if (Gbl.TimeTable.Config.Range.Hours.End >
Gbl.TimeTable.Config.Range.Hours.Start)
2017-04-25 14:48:47 +02:00
{
2017-04-25 21:20:19 +02:00
/***** Configuration of timetable depending on hours and resolution *****/
Gbl.TimeTable.Config.HoursPerDay = Gbl.TimeTable.Config.Range.Hours.End -
Gbl.TimeTable.Config.Range.Hours.Start; // From start hour to end hour
Gbl.TimeTable.Config.SecondsPerInterval = Gbl.TimeTable.Config.Range.MinutesPerInterval *
TT_SECONDS_PER_MINUTE;
Gbl.TimeTable.Config.IntervalsPerHour = TT_MINUTES_PER_HOUR /
Gbl.TimeTable.Config.Range.MinutesPerInterval;
Gbl.TimeTable.Config.IntervalsPerDay = Gbl.TimeTable.Config.IntervalsPerHour *
Gbl.TimeTable.Config.HoursPerDay;
Gbl.TimeTable.Config.IntervalsBeforeStartHour = Gbl.TimeTable.Config.IntervalsPerHour *
Gbl.TimeTable.Config.Range.Hours.Start;
/***** Allocate memory for timetable *****/
for (Weekday = 0;
Weekday < TT_DAYS_PER_WEEK;
Weekday++)
if ((TT_TimeTable[Weekday] = (struct TT_Cell *)
malloc (Gbl.TimeTable.Config.IntervalsPerDay *
sizeof (struct TT_Cell))) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for timetable.");
2017-04-25 14:48:47 +02:00
}
2017-04-25 21:20:19 +02:00
else
2017-04-25 14:48:47 +02:00
{
2017-04-25 21:20:19 +02:00
/***** Table is empty *****/
Gbl.TimeTable.Config.HoursPerDay = 0;
Gbl.TimeTable.Config.SecondsPerInterval = 0;
Gbl.TimeTable.Config.IntervalsPerHour = 0;
Gbl.TimeTable.Config.IntervalsPerDay = 0;
Gbl.TimeTable.Config.IntervalsBeforeStartHour = 0;
/***** Clear timetable in order to not try to free it *****/
for (Weekday = 0;
Weekday < TT_DAYS_PER_WEEK;
Weekday++)
TT_TimeTable[Weekday] = NULL;
2017-04-25 14:48:47 +02:00
}
2017-04-25 11:57:36 +02:00
}
/*****************************************************************************/
/******************** Destroy internal timetable in memory *******************/
/*****************************************************************************/
2017-04-25 21:20:19 +02:00
static void TT_FreeTimeTable (void)
2017-04-25 11:57:36 +02:00
{
unsigned Weekday;
/***** Free memory for timetable *****/
for (Weekday = 0;
Weekday < TT_DAYS_PER_WEEK;
Weekday++)
2017-04-25 21:20:19 +02:00
if (TT_TimeTable[Weekday])
{
free ((void *) TT_TimeTable[Weekday]);
TT_TimeTable[Weekday] = NULL;
}
2017-04-25 11:57:36 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*********** 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;
2017-03-03 21:06:34 +01:00
fprintf (Gbl.F.Out,"<div class=\"CLASSPHOTO_TITLE 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)
{
2017-04-24 18:53:25 +02:00
char StrClassType[TT_MAX_BYTES_STR_CLASS_TYPE + 1];
2017-01-28 15:58:46 +01:00
char StrDuration[TT_MAX_BYTES_STR_DURATION + 1];
2017-01-29 21:41:08 +01:00
unsigned Hours;
unsigned Minutes;
2014-12-01 23:55:08 +01:00
2017-01-29 21:41:08 +01:00
/***** Get day (0: monday, 1: tuesday,..., 6: sunday *****/
2017-04-24 21:12:53 +02:00
Gbl.TimeTable.Weekday = (unsigned)
2017-04-25 21:20:19 +02:00
Par_GetParToUnsignedLong ("TTDay",
2017-04-24 21:12:53 +02:00
0,
TT_DAYS_PER_WEEK - 1,
0);
2014-12-01 23:55:08 +01:00
/***** Get hour *****/
2017-04-24 21:12:53 +02:00
Gbl.TimeTable.Interval = (unsigned)
2017-04-25 21:20:19 +02:00
Par_GetParToUnsignedLong ("TTInt",
2017-04-25 11:57:36 +02:00
0,
Gbl.TimeTable.Config.IntervalsPerDay - 1,
0);
2014-12-01 23:55:08 +01:00
/***** Get number of column *****/
2017-01-29 21:41:08 +01:00
Gbl.TimeTable.Column = (unsigned)
2017-04-25 21:20:19 +02:00
Par_GetParToUnsignedLong ("TTCol",
2017-01-29 21:41:08 +01:00
0,
TT_MAX_COLUMNS_PER_CELL - 1,
0);
2014-12-01 23:55:08 +01:00
/***** Get class type *****/
2017-04-25 21:20:19 +02:00
Par_GetParToText ("TTTyp",StrClassType,TT_MAX_BYTES_STR_CLASS_TYPE);
2017-04-24 13:39:55 +02:00
for (Gbl.TimeTable.ClassType = (TT_ClassType_t) 0;
Gbl.TimeTable.ClassType < (TT_ClassType_t) TT_NUM_CLASS_TYPES;
Gbl.TimeTable.ClassType++)
2017-04-25 14:48:47 +02:00
if (!strcmp (StrClassType,TT_ClassTypeDB[Gbl.TimeTable.ClassType]))
2014-12-01 23:55:08 +01:00
break;
2017-04-24 13:39:55 +02:00
if (Gbl.TimeTable.ClassType == (TT_ClassType_t) TT_NUM_CLASS_TYPES)
2014-12-01 23:55:08 +01:00
Lay_ShowErrorAndExit ("Type of timetable cell is missing.");
/***** Get class duration *****/
2017-04-25 21:20:19 +02:00
Par_GetParToText ("TTDur",StrDuration,TT_MAX_BYTES_STR_DURATION);
2014-12-01 23:55:08 +01:00
if (sscanf (StrDuration,"%u:%u",&Hours,&Minutes) != 2)
Lay_ShowErrorAndExit ("Duration is missing.");
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.DurationIntervals = Hours * Gbl.TimeTable.Config.IntervalsPerHour +
Minutes / Gbl.TimeTable.Config.Range.MinutesPerInterval;
2014-12-01 23:55:08 +01:00
/***** Get group code *****/
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.GrpCod = Par_GetParToLong ("TTGrp");
2014-12-01 23:55:08 +01:00
/***** Get place *****/
2017-04-25 21:20:19 +02:00
Par_GetParToText ("TTPlc",Gbl.TimeTable.Place,TT_MAX_BYTES_PLACE);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/**************************** 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
2017-04-24 13:00:59 +02:00
NULL, // TT_TUTORING_TIMETABLE
2016-11-26 20:58:12 +01:00
};
2016-11-26 22:02:42 +01:00
Act_Action_t ActChgTT1stDay[TT_NUM_TIMETABLE_TYPES] =
{
ActChgCrsTT1stDay,// TT_COURSE_TIMETABLE
ActChgMyTT1stDay, // TT_MY_TIMETABLE
2017-04-24 13:00:59 +02:00
ActUnk, // TT_TUTORING_TIMETABLE
2016-11-26 22:02:42 +01:00
};
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-12-04 20:12:56 +01:00
2016-03-18 14:07:21 +01:00
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)));
2016-12-04 20:12:56 +01:00
Gbl.TimeTable.ContextualIcons.PutIconPrint = !PrintView;
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],
2016-12-04 23:31:48 +01:00
(Gbl.TimeTable.ContextualIcons.PutIconEditCrsTT ||
2016-03-18 14:07:21 +01:00
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-12-04 12:42:45 +01:00
if ( Gbl.TimeTable.Type == TT_MY_TIMETABLE ||
(Gbl.TimeTable.Type == TT_COURSE_TIMETABLE &&
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-12-04 12:42:45 +01:00
Grp_PutParamWhichGrps,
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)
2017-04-17 19:03:21 +02:00
Lay_PutContextualLink (ActEdiCrsTT,NULL,Grp_PutParamWhichGrps,
2016-03-18 14:07:21 +01:00
"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)
2017-04-17 19:03:21 +02:00
Lay_PutContextualLink (ActEdiTut,NULL,NULL,
2016-07-01 16:32:42 +02:00
"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,
2017-04-17 19:03:21 +02:00
NULL,Grp_PutParamWhichGrps,
2016-07-01 16:32:42 +02:00
"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
2017-04-24 13:00:59 +02:00
ActUnk, // TT_TUTORING_TIMETABLE
2016-11-26 22:07:52 +01:00
};
2016-12-04 23:09:28 +01:00
Grp_ShowFormToSelWhichGrps (ActSeeTT[Gbl.TimeTable.Type],NULL);
2016-11-26 22:07:52 +01:00
}
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 *****/
2017-04-24 13:00:59 +02:00
Gbl.TimeTable.Type = TT_TUTORING_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 *****/
2017-04-17 19:03:21 +02:00
Lay_PutContextualLink (ActSeeCrsTT,NULL,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 *****/
2017-04-17 19:03:21 +02:00
Lay_PutContextualLink (ActSeeMyTT,NULL,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
{
2017-04-25 21:20:19 +02:00
extern const char *Txt_The_timetable_is_empty;
2017-04-25 21:42:29 +02:00
/***** Set type of view depending on current action *****/
Gbl.TimeTable.View = TT_CRS_VIEW;
2017-04-25 21:20:19 +02:00
switch (Gbl.Action.Act)
{
case ActSeeCrsTT: case ActPrnCrsTT: case ActChgCrsTT1stDay:
case ActSeeMyTT: case ActPrnMyTT: case ActChgMyTT1stDay:
2017-04-25 21:42:29 +02:00
Gbl.TimeTable.View = TT_CRS_VIEW;
break;
2017-04-25 21:20:19 +02:00
case ActSeeRecOneTch: case ActSeeRecSevTch:
2017-04-25 21:42:29 +02:00
Gbl.TimeTable.View = TT_TUT_VIEW;
break;
2017-04-25 21:20:19 +02:00
case ActEdiCrsTT: case ActChgCrsTT:
2017-04-25 21:42:29 +02:00
Gbl.TimeTable.View = TT_CRS_EDIT;
break;
2017-04-25 21:20:19 +02:00
case ActEdiTut: case ActChgTut:
2017-04-25 21:42:29 +02:00
Gbl.TimeTable.View = TT_TUT_EDIT;
break;
2017-04-25 21:20:19 +02:00
}
/***** If editing ==> configure and allocate timetable *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_EDIT ||
Gbl.TimeTable.View == TT_TUT_EDIT)
2017-04-25 21:20:19 +02:00
{
Gbl.TimeTable.Config.Range.Hours.Start = TT_START_HOUR; // Day starts at this hour
Gbl.TimeTable.Config.Range.Hours.End = TT_END_HOUR; // Day ends at this hour
Gbl.TimeTable.Config.Range.MinutesPerInterval = TT_MinutesPerInterval[0]; // The smallest interval
TT_TimeTableConfigureIntervalsAndAllocateTimeTable ();
}
/* If viewing (not editing) ==>
configure and allocate memory when table is read from database */
2017-04-25 11:57:36 +02:00
/***** Fill internal timetable with the timetable from database *****/
TT_FillTimeTableFromDB (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;
2017-04-24 13:00:59 +02:00
case TT_TUTORING_TIMETABLE:
2014-12-01 23:55:08 +01:00
TT_WriteTutTimeTableIntoDB (UsrCod);
break;
default:
break;
}
/* Get a new table from database */
2017-04-25 11:57:36 +02:00
TT_FillTimeTableFromDB (UsrCod);
2014-12-01 23:55:08 +01:00
}
/***** Draw timetable *****/
2017-04-25 21:20:19 +02:00
if (Gbl.TimeTable.Config.HoursPerDay)
TT_DrawTimeTable ();
else
Lay_ShowAlert (Lay_INFO,Txt_The_timetable_is_empty);
2017-04-25 11:57:36 +02:00
/***** Free internal timetable in memory *****/
2017-04-25 21:20:19 +02:00
TT_FreeTimeTable ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/******************* Write course timetable into database ********************/
/*****************************************************************************/
static void TT_WriteCrsTimeTableIntoDB (long CrsCod)
{
2017-03-13 14:57:35 +01:00
char Query[512 +
TT_MAX_BYTES_PLACE +
Grp_MAX_BYTES_GROUP_NAME];
2017-04-24 13:50:03 +02:00
unsigned Weekday;
2017-04-24 21:12:53 +02:00
unsigned Interval;
2017-04-24 13:39:55 +02:00
unsigned Hour;
unsigned Min;
2017-03-13 14:57:35 +01:00
unsigned Column;
2014-12-01 23:55:08 +01:00
/***** Remove former timetable *****/
2017-03-24 01:09:27 +01:00
sprintf (Query,"DELETE FROM timetable_crs WHERE CrsCod=%ld",
2017-03-13 14:57:35 +01:00
CrsCod);
2014-12-01 23:55:08 +01:00
DB_QueryDELETE (Query,"can not remove former timetable");
/***** Go across the timetable inserting classes into database *****/
2017-04-24 13:50:03 +02:00
for (Weekday = 0;
2017-04-24 21:12:53 +02:00
Weekday < TT_DAYS_PER_WEEK;
2017-04-24 13:50:03 +02:00
Weekday++)
2017-04-25 21:20:19 +02:00
for (Interval = 0, Hour = Gbl.TimeTable.Config.Range.Hours.Start, Min = 0;
2017-04-25 11:57:36 +02:00
Interval < Gbl.TimeTable.Config.IntervalsPerDay;
2017-04-24 21:12:53 +02:00
Interval++,
2017-04-25 21:20:19 +02:00
Hour += (Min + Gbl.TimeTable.Config.Range.MinutesPerInterval) / TT_SECONDS_PER_MINUTE,
Min = (Min + Gbl.TimeTable.Config.Range.MinutesPerInterval) % TT_SECONDS_PER_MINUTE)
2014-12-01 23:55:08 +01:00
for (Column = 0;
Column < TT_MAX_COLUMNS_PER_CELL;
Column++)
2017-04-24 21:12:53 +02:00
if (TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType == TT_FIRST_INTERVAL &&
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals)
2014-12-01 23:55:08 +01:00
{
2017-03-13 13:17:53 +01:00
sprintf (Query,"INSERT INTO timetable_crs"
2017-04-24 13:39:55 +02:00
" (CrsCod,GrpCod,Weekday,StartTime,Duration,"
"ClassType,Place,GroupName)"
2017-03-13 13:17:53 +01:00
" VALUES"
2017-04-24 13:39:55 +02:00
" (%ld,%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),"
"'%s','%s','%s')",
2014-12-01 23:55:08 +01:00
CrsCod,
2017-04-24 21:12:53 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].GrpCod,
2017-04-24 13:50:03 +02:00
Weekday,
2017-04-24 13:39:55 +02:00
Hour,Min,
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals *
2017-04-25 11:57:36 +02:00
Gbl.TimeTable.Config.SecondsPerInterval,
2017-04-25 14:48:47 +02:00
TT_ClassTypeDB[TT_TimeTable[Weekday][Interval].Columns[Column].ClassType],
2017-04-24 21:12:53 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].Place,
TT_TimeTable[Weekday][Interval].Columns[Column].Group);
2014-12-01 23:55:08 +01:00
DB_QueryINSERT (Query,"can not create course timetable");
}
}
/*****************************************************************************/
/********************* Write tutor timetable into database *******************/
/*****************************************************************************/
static void TT_WriteTutTimeTableIntoDB (long UsrCod)
{
2017-03-13 14:57:35 +01:00
char Query[512 +
TT_MAX_BYTES_PLACE];
2017-04-24 13:50:03 +02:00
unsigned Weekday;
2017-04-24 21:12:53 +02:00
unsigned Interval;
2017-04-24 13:50:03 +02:00
unsigned Hour;
unsigned Min;
2017-04-24 13:00:59 +02:00
unsigned Column;
2014-12-01 23:55:08 +01:00
/***** Remove former timetable *****/
2017-03-24 01:09:27 +01:00
sprintf (Query,"DELETE FROM timetable_tut WHERE UsrCod=%ld",
2017-03-13 14:57:35 +01:00
UsrCod);
2014-12-01 23:55:08 +01:00
DB_QueryDELETE (Query,"can not remove former timetable");
/***** Loop over timetable *****/
2017-04-24 13:50:03 +02:00
for (Weekday = 0;
2017-04-24 21:12:53 +02:00
Weekday < TT_DAYS_PER_WEEK;
2017-04-24 13:50:03 +02:00
Weekday++)
2017-04-25 21:20:19 +02:00
for (Interval = 0, Hour = Gbl.TimeTable.Config.Range.Hours.Start, Min = 0;
2017-04-25 11:57:36 +02:00
Interval < Gbl.TimeTable.Config.IntervalsPerDay;
2017-04-24 21:12:53 +02:00
Interval++,
2017-04-25 21:20:19 +02:00
Hour += (Min + Gbl.TimeTable.Config.Range.MinutesPerInterval) / TT_SECONDS_PER_MINUTE,
Min = (Min + Gbl.TimeTable.Config.Range.MinutesPerInterval) % TT_SECONDS_PER_MINUTE)
2017-04-24 18:53:25 +02:00
for (Column = 0;
2014-12-01 23:55:08 +01:00
Column < TT_MAX_COLUMNS_PER_CELL;
Column++)
2017-04-24 21:12:53 +02:00
if (TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType == TT_FIRST_INTERVAL &&
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals)
2014-12-01 23:55:08 +01:00
{
2017-03-13 13:17:53 +01:00
sprintf (Query,"INSERT INTO timetable_tut"
2017-04-24 13:50:03 +02:00
" (UsrCod,Weekday,StartTime,Duration,Place)"
2017-03-13 13:17:53 +01:00
" VALUES"
2017-04-24 13:50:03 +02:00
" (%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),'%s')",
UsrCod,
Weekday,
Hour,Min,
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals *
2017-04-25 11:57:36 +02:00
Gbl.TimeTable.Config.SecondsPerInterval,
2017-04-24 21:12:53 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].Place);
2014-12-01 23:55:08 +01:00
DB_QueryINSERT (Query,"can not create office timetable");
}
}
/*****************************************************************************/
/********** Create an internal table with timetable from database ************/
/*****************************************************************************/
2017-04-25 11:57:36 +02:00
static void TT_FillTimeTableFromDB (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;
2017-04-24 13:00:59 +02:00
unsigned long NumRow;
unsigned long NumRows;
2017-04-24 18:53:25 +02:00
unsigned Weekday;
2017-04-24 21:12:53 +02:00
unsigned Interval;
2017-04-25 21:20:19 +02:00
unsigned i; // To iterate through intervals
2017-04-24 21:12:53 +02:00
unsigned DurationNumIntervals;
2017-04-24 13:00:59 +02:00
unsigned Column;
2017-04-25 14:48:47 +02:00
unsigned StartTimeSeconds;
unsigned DurationSeconds;
unsigned EndTimeSeconds;
2017-04-25 21:20:19 +02:00
struct TT_Range RangeCell;
2017-04-24 13:00:59 +02:00
unsigned FirstFreeColumn;
2014-12-01 23:55:08 +01:00
long GrpCod;
2017-04-24 13:39:55 +02:00
TT_ClassType_t ClassType = TT_FREE; // Initialized to avoid warning
2014-12-01 23:55:08 +01:00
bool TimeTableIsIncomplete = false;
bool TimeTableHasSpaceForThisClass;
bool Found;
/***** 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:
2017-04-24 18:53:25 +02:00
sprintf (Query,"SELECT "
"timetable_crs.Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
"timetable_crs.Place,"
"timetable_crs.ClassType,"
"timetable_crs.GroupName,"
"timetable_crs.GrpCod,"
"timetable_crs.CrsCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs,crs_usr"
2017-03-24 01:09:27 +01:00
" WHERE crs_usr.UsrCod=%ld"
" AND timetable_crs.GrpCod=-1"
" AND timetable_crs.CrsCod=crs_usr.CrsCod"
2014-12-01 23:55:08 +01:00
" UNION DISTINCT "
2017-04-24 18:53:25 +02:00
"SELECT "
"timetable_crs.Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
"timetable_crs.Place,"
"timetable_crs.ClassType,"
"timetable_crs.GroupName,"
"timetable_crs.GrpCod,"
"timetable_crs.CrsCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs,crs_grp_usr"
2017-03-24 01:09:27 +01:00
" WHERE crs_grp_usr.UsrCod=%ld"
" AND timetable_crs.GrpCod=crs_grp_usr.GrpCod"
2014-12-01 23:55:08 +01:00
" UNION "
2017-04-24 18:53:25 +02:00
"SELECT "
"Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(Duration) AS D,"
"Place,"
"'tutoring' AS ClassType,"
"'' AS GroupName,"
"-1 AS GrpCod,"
"-1 AS CrsCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_tut"
2017-03-24 01:09:27 +01:00
" WHERE UsrCod=%ld"
2017-04-25 02:07:32 +02:00
" ORDER BY Weekday,S,ClassType,"
2017-04-24 18:53:25 +02:00
"GroupName,GrpCod,Place,D DESC,CrsCod",
2014-12-01 23:55:08 +01:00
UsrCod,UsrCod,UsrCod);
break;
case Grp_ALL_GROUPS:
2017-04-24 18:53:25 +02:00
sprintf (Query,"SELECT "
"timetable_crs.Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
"timetable_crs.Place,"
"timetable_crs.ClassType,"
"timetable_crs.GroupName,"
"timetable_crs.GrpCod,"
"timetable_crs.CrsCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs,crs_usr"
2017-03-24 01:09:27 +01:00
" WHERE crs_usr.UsrCod=%ld"
" AND timetable_crs.CrsCod=crs_usr.CrsCod"
2014-12-01 23:55:08 +01:00
" UNION "
2017-04-24 18:53:25 +02:00
"SELECT "
"Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(Duration) AS D,"
"Place,"
"'tutoring' AS ClassType,"
"'' AS GroupName,"
"-1 AS GrpCod,"
"-1 AS CrsCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_tut"
2017-03-24 01:09:27 +01:00
" WHERE UsrCod=%ld"
2017-04-25 02:07:32 +02:00
" ORDER BY Weekday,S,ClassType,"
2017-04-24 18:53:25 +02:00
"GroupName,GrpCod,Place,D DESC,CrsCod",
2014-12-01 23:55:08 +01:00
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
2017-04-24 18:53:25 +02:00
sprintf (Query,"SELECT "
"Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(Duration) AS D,"
"Place,"
"ClassType,"
"GroupName,"
"GrpCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs"
2017-03-24 01:09:27 +01:00
" WHERE CrsCod=%ld"
2017-04-25 02:07:32 +02:00
" ORDER BY Weekday,S,ClassType,"
2017-04-24 18:53:25 +02:00
"GroupName,GrpCod,Place,D DESC",
2014-12-01 23:55:08 +01:00
Gbl.CurrentCrs.Crs.CrsCod);
else
2017-04-24 18:53:25 +02:00
sprintf (Query,"SELECT "
"timetable_crs.Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
"timetable_crs.Place,"
"timetable_crs.ClassType,"
"timetable_crs.GroupName,"
"timetable_crs.GrpCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs,crs_usr"
2017-03-24 01:09:27 +01:00
" WHERE timetable_crs.CrsCod=%ld"
" AND timetable_crs.GrpCod=-1 AND crs_usr.UsrCod=%ld"
" AND timetable_crs.CrsCod=crs_usr.CrsCod"
2014-12-01 23:55:08 +01:00
" UNION DISTINCT "
2017-04-24 18:53:25 +02:00
"SELECT timetable_crs.Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
"timetable_crs.Place,"
"timetable_crs.ClassType,"
"timetable_crs.GroupName,"
"timetable_crs.GrpCod"
2014-12-01 23:55:08 +01:00
" FROM timetable_crs,crs_grp_usr"
2017-03-24 01:09:27 +01:00
" WHERE timetable_crs.CrsCod=%ld"
" AND crs_grp_usr.UsrCod=%ld"
" AND timetable_crs.GrpCod=crs_grp_usr.GrpCod"
2017-04-25 02:07:32 +02:00
" ORDER BY Weekday,S,ClassType,"
2017-04-24 18:53:25 +02:00
"GroupName,GrpCod,Place,D DESC",
2014-12-01 23:55:08 +01:00
Gbl.CurrentCrs.Crs.CrsCod,UsrCod,
Gbl.CurrentCrs.Crs.CrsCod,UsrCod);
break;
2017-04-24 13:00:59 +02:00
case TT_TUTORING_TIMETABLE:
2017-04-24 18:53:25 +02:00
sprintf (Query,"SELECT "
"Weekday,"
2017-04-25 02:07:32 +02:00
"TIME_TO_SEC(StartTime) AS S,"
2017-04-24 18:53:25 +02:00
"TIME_TO_SEC(Duration) AS D,"
"Place"
2014-12-01 23:55:08 +01:00
" FROM timetable_tut"
2017-03-24 01:09:27 +01:00
" WHERE UsrCod=%ld"
2017-04-25 02:07:32 +02:00
" ORDER BY Weekday,S,Place,D DESC",
2014-12-01 23:55:08 +01:00
UsrCod);
break;
}
NumRows = DB_QuerySELECT (Query,&mysql_res,"can not get timetable");
2017-04-25 21:20:19 +02:00
/***** If viewing (not editing) ==>
calculate range of hours and resolution *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_VIEW ||
Gbl.TimeTable.View == TT_TUT_VIEW)
2017-04-25 14:48:47 +02:00
{
2017-04-25 21:20:19 +02:00
/* Initialize hours and resolution for timetable */
Gbl.TimeTable.Config.Range.Hours.Start = TT_END_HOUR; // Initialized to maximum hour
Gbl.TimeTable.Config.Range.Hours.End = TT_START_HOUR; // Initialized to minimum hour
Gbl.TimeTable.Config.Range.MinutesPerInterval = TT_MinutesPerInterval[TT_NUM_RESOLUTIONS - 1]; // The longest interval
2017-04-25 14:48:47 +02:00
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
row = mysql_fetch_row (mysql_res);
/* StartTime formatted as seconds (row[1]) */
if (sscanf (row[1],"%u",&StartTimeSeconds) != 1)
Lay_ShowErrorAndExit ("Wrong start time in timetable.");
/* Duration formatted as seconds (row[2]) */
if (sscanf (row[2],"%u",&DurationSeconds) != 1)
Lay_ShowErrorAndExit ("Wrong duration in timetable.");
EndTimeSeconds = StartTimeSeconds + DurationSeconds;
2017-04-25 21:20:19 +02:00
/* Compute hours and resolution */
TT_CalculateRangeCell (StartTimeSeconds,EndTimeSeconds,&RangeCell);
if (RangeCell.Hours.Start < Gbl.TimeTable.Config.Range.Hours.Start)
Gbl.TimeTable.Config.Range.Hours.Start = RangeCell.Hours.Start;
if (RangeCell.Hours.End > Gbl.TimeTable.Config.Range.Hours.End)
Gbl.TimeTable.Config.Range.Hours.End = RangeCell.Hours.End;
if (RangeCell.MinutesPerInterval < Gbl.TimeTable.Config.Range.MinutesPerInterval)
Gbl.TimeTable.Config.Range.MinutesPerInterval = RangeCell.MinutesPerInterval;
2017-04-25 14:48:47 +02:00
}
mysql_data_seek (mysql_res,0);
2017-04-25 21:20:19 +02:00
/***** Configure and allocate timetable *****/
2017-04-25 14:48:47 +02:00
TT_TimeTableConfigureIntervalsAndAllocateTimeTable ();
}
2017-04-25 21:20:19 +02:00
/***** Build the table by filling it from database *****/
if (Gbl.TimeTable.Config.HoursPerDay)
2014-12-01 23:55:08 +01:00
{
2017-04-25 21:20:19 +02:00
/***** Initialize timetable to all free *****/
for (Weekday = 0;
Weekday < TT_DAYS_PER_WEEK;
Weekday++)
for (Interval = 0;
Interval < Gbl.TimeTable.Config.IntervalsPerDay;
Interval++)
{
TT_TimeTable[Weekday][Interval].NumColumns = 0;
for (Column = 0;
Column < TT_MAX_COLUMNS_PER_CELL;
Column++)
{
TT_TimeTable[Weekday][Interval].Columns[Column].CrsCod = -1L;
TT_TimeTable[Weekday][Interval].Columns[Column].GrpCod = -1L;
TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType = TT_FREE_INTERVAL;
TT_TimeTable[Weekday][Interval].Columns[Column].ClassType = TT_FREE;
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals = 0;
TT_TimeTable[Weekday][Interval].Columns[Column].Group[0] = '\0';
TT_TimeTable[Weekday][Interval].Columns[Column].Place[0] = '\0';
}
}
2014-12-01 23:55:08 +01:00
2017-04-25 21:20:19 +02:00
/***** Fill data from database *****/
for (NumRow = 0;
NumRow < NumRows;
NumRow++)
{
row = mysql_fetch_row (mysql_res);
2017-04-25 02:07:32 +02:00
2017-04-25 21:20:19 +02:00
if (Gbl.TimeTable.Type == TT_MY_TIMETABLE ||
Gbl.TimeTable.Type == TT_COURSE_TIMETABLE)
/* Group code */
if (sscanf (row[6],"%ld",&GrpCod) != 1)
GrpCod = -1;
2014-12-01 23:55:08 +01:00
2017-04-25 21:20:19 +02:00
/* Day of week (row[0]) */
if (sscanf (row[0],"%u",&Weekday) != 1)
Lay_ShowErrorAndExit ("Wrong day of week in timetable.");
if (Weekday >= TT_DAYS_PER_WEEK)
Lay_ShowErrorAndExit ("Wrong day of week in timetable.");
2014-12-01 23:55:08 +01:00
2017-04-25 21:20:19 +02:00
/* StartTime formatted as seconds (row[1])
--> StartTime in number of intervals */
if (sscanf (row[1],"%u",&StartTimeSeconds) != 1)
Lay_ShowErrorAndExit ("Wrong start time in timetable.");
Interval = StartTimeSeconds /
Gbl.TimeTable.Config.SecondsPerInterval;
if (Interval < Gbl.TimeTable.Config.IntervalsBeforeStartHour)
Lay_ShowErrorAndExit ("Wrong start time in timetable.");
Interval -= Gbl.TimeTable.Config.IntervalsBeforeStartHour;
/* Duration formatted as seconds (row[2])
--> Duration in number of intervals */
if (sscanf (row[2],"%u",&DurationSeconds) != 1)
Lay_ShowErrorAndExit ("Wrong duration in timetable.");
DurationNumIntervals = DurationSeconds /
Gbl.TimeTable.Config.SecondsPerInterval;
/* Type of class (row[4]) */
switch (Gbl.TimeTable.Type)
{
case TT_COURSE_TIMETABLE:
case TT_MY_TIMETABLE:
for (ClassType = TT_LECTURE, Found = false;
ClassType <= TT_TUTORING;
ClassType++)
if (!strcmp (row[4],TT_ClassTypeDB[ClassType]))
{
Found = true;
break;
}
if (!Found)
Lay_ShowErrorAndExit ("Wrong type of class in timetable.");
break;
case TT_TUTORING_TIMETABLE:
ClassType = TT_TUTORING;
break;
}
/* Cell has been read without errors */
if (TT_TimeTable[Weekday][Interval].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 (TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType == TT_FREE_INTERVAL)
{
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 (i = Interval + 1;
i < Interval + DurationNumIntervals &&
i < Gbl.TimeTable.Config.IntervalsPerDay;
i++)
if (TT_TimeTable[Weekday][i].Columns[FirstFreeColumn].IntervalType != TT_FREE_INTERVAL)
{
TimeTableIsIncomplete = true;
TimeTableHasSpaceForThisClass = false;
break;
}
if (TimeTableHasSpaceForThisClass)
{
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].ClassType = ClassType;
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].DurationIntervals = DurationNumIntervals;
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].IntervalType = TT_FIRST_INTERVAL;
for (i = Interval + 1;
i < Interval + DurationNumIntervals &&
i < Gbl.TimeTable.Config.IntervalsPerDay;
i++)
{
TT_TimeTable[Weekday][i].Columns[FirstFreeColumn].IntervalType = TT_NEXT_INTERVAL;
TT_TimeTable[Weekday][i].NumColumns++;
}
/* Course (row[7]), group (row[5]) and place (row[3])*/
switch (Gbl.TimeTable.Type)
{
case TT_MY_TIMETABLE:
case TT_COURSE_TIMETABLE:
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].CrsCod =
(Gbl.TimeTable.Type == TT_MY_TIMETABLE ? Str_ConvertStrCodToLongCod (row[7]) :
Gbl.CurrentCrs.Crs.CrsCod);
Str_Copy (TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].Group,
row[5],
Grp_MAX_BYTES_GROUP_NAME);
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].GrpCod = GrpCod;
// no break;
case TT_TUTORING_TIMETABLE:
Str_Copy (TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].Place,
row[3],
TT_MAX_BYTES_PLACE);
break;
}
/* Increment number of items in this cell */
TT_TimeTable[Weekday][Interval].NumColumns++;
}
}
else
TimeTableIsIncomplete = true;
}
else
TimeTableIsIncomplete = true;
}
2014-12-01 23:55:08 +01:00
}
/***** 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
}
2017-04-25 14:48:47 +02:00
/*****************************************************************************/
/****************** Get resolution given a time in seconds *******************/
/*****************************************************************************/
2017-04-25 21:20:19 +02:00
static void TT_CalculateRangeCell (unsigned StartTimeSeconds,
unsigned EndTimeSeconds,
struct TT_Range *Range)
{
unsigned TimeMinutes;
unsigned MinutesPerIntervalForEndTime;
/***** Compute minimum hour *****/
// Example: if Seconds == 42300 (time == 11:45:00) =>
// TimeMinutes = 42300/60 = 705 =>
// Hour = 705/60 = 11
TimeMinutes = StartTimeSeconds / TT_SECONDS_PER_MINUTE;
Range->Hours.Start = TimeMinutes / TT_MINUTES_PER_HOUR;
/***** Compute maximum hour *****/
// Example: if Seconds == 42300 (time == 11:45:00) =>
// TimeMinutes = 42300/60 = 705 =>
// Hour = 705/60 = 11
// 705 % 60 = 45 ==> Hour = Hour+1 = 12
TimeMinutes = EndTimeSeconds / TT_SECONDS_PER_MINUTE;
Range->Hours.End = TimeMinutes / TT_MINUTES_PER_HOUR;
if (TimeMinutes % TT_MINUTES_PER_HOUR)
Range->Hours.End++;
/***** Compute resolution (longest interval necessary for this cell) *****/
Range->MinutesPerInterval = TT_CalculateMinutesPerInterval (StartTimeSeconds);
if (Range->MinutesPerInterval > TT_MinutesPerInterval[0]) // If not already the shortest
{
MinutesPerIntervalForEndTime = TT_CalculateMinutesPerInterval (EndTimeSeconds);
if (MinutesPerIntervalForEndTime < Range->MinutesPerInterval)
Range->MinutesPerInterval = MinutesPerIntervalForEndTime;
}
}
2017-04-25 14:48:47 +02:00
// Example: if Seconds == 42300 (time == 11:45:00) => Minutes = 45 => Resolution = 15
2017-04-25 21:20:19 +02:00
static unsigned TT_CalculateMinutesPerInterval (unsigned Seconds)
2017-04-25 14:48:47 +02:00
{
unsigned Minutes;
2017-04-25 21:20:19 +02:00
unsigned MinutesPerInterval;
unsigned Resolution;
2017-04-25 14:48:47 +02:00
2017-04-25 21:20:19 +02:00
/***** Compute minutes part (45) of a time (11:45:00) from seconds (42300) *****/
2017-04-25 14:48:47 +02:00
Minutes = (Seconds / TT_SECONDS_PER_MINUTE) % TT_MINUTES_PER_HOUR;
2017-04-25 21:20:19 +02:00
/***** Compute minutes per interval *****/
MinutesPerInterval = TT_MinutesPerInterval[0]; // Default: the shortest interval
for (Resolution = TT_NUM_RESOLUTIONS - 1; // From the longest interval...
Resolution > 0;
Resolution--) // ...to shorter intervals
if (Minutes % TT_MinutesPerInterval[Resolution] == 0)
2017-04-25 14:48:47 +02:00
{
2017-04-25 21:20:19 +02:00
MinutesPerInterval = TT_MinutesPerInterval[Resolution];
2017-04-25 14:48:47 +02:00
break;
}
2017-04-25 21:20:19 +02:00
return MinutesPerInterval;
2017-04-25 14:48:47 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/*********************** Modify a class in timetable *************************/
/*****************************************************************************/
static void TT_ModifTimeTable (void)
{
2017-04-24 21:12:53 +02:00
if (TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].IntervalType == TT_FIRST_INTERVAL)
2014-12-01 23:55:08 +01:00
{
/***** Free this cell *****/
2017-04-25 21:20:19 +02:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].GrpCod = -1L;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].IntervalType = TT_FREE_INTERVAL;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].ClassType = TT_FREE;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].DurationIntervals = 0;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Group[0] = '\0';
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Place[0] = '\0';
2017-04-24 21:12:53 +02:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].NumColumns--;
2014-12-01 23:55:08 +01:00
}
2017-04-24 21:12:53 +02:00
if (Gbl.TimeTable.ClassType != TT_FREE &&
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.DurationIntervals > 0 &&
2017-04-24 21:12:53 +02:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].NumColumns < TT_MAX_COLUMNS_PER_CELL)
2014-12-01 23:55:08 +01:00
{
/***** Change this cell *****/
2017-04-24 21:12:53 +02:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].NumColumns++;
2017-04-25 21:20:19 +02:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].GrpCod = Gbl.TimeTable.GrpCod;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].IntervalType = TT_FIRST_INTERVAL;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].ClassType = Gbl.TimeTable.ClassType;
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].DurationIntervals = Gbl.TimeTable.DurationIntervals;
2017-04-24 21:12:53 +02:00
Str_Copy (TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Group,
2017-01-17 03:10:43 +01:00
Gbl.TimeTable.Group,
2017-03-08 03:48:23 +01:00
Grp_MAX_BYTES_GROUP_NAME);
2017-04-24 21:12:53 +02:00
Str_Copy (TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Place,
2017-01-17 03:10:43 +01:00
Gbl.TimeTable.Place,
TT_MAX_BYTES_PLACE);
2014-12-01 23:55:08 +01:00
}
}
/*****************************************************************************/
/********************* 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
{
2015-11-30 21:23:14 +01:00
unsigned DayColumn; // Column from left (0) to right (6)
2017-04-24 21:12:53 +02:00
unsigned Weekday; // Day of week
unsigned Interval;
2017-04-24 01:56:57 +02:00
unsigned Min;
2015-11-30 21:23:14 +01:00
unsigned Column;
unsigned ColumnsToDraw;
unsigned ColumnsToDrawIncludingExtraColumn;
unsigned ContinuousFreeMinicolumns;
2014-12-01 23:55:08 +01:00
/***** 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>"
2017-04-24 10:13:53 +02:00
"<td rowspan=\"2\" class=\"TT_HOUR_BIG RIGHT_MIDDLE\""
" style=\"width:%u%%;\">"
2017-04-25 14:48:47 +02:00
"%02u:00"
2014-12-26 16:55:46 +01:00
"</td>",
2017-04-25 11:57:36 +02:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN,
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.Config.Range.Hours.Start);
2014-12-01 23:55:08 +01:00
TT_DrawCellAlignTimeTable ();
TT_TimeTableDrawDaysCells ();
TT_DrawCellAlignTimeTable ();
2017-04-24 10:13:53 +02:00
fprintf (Gbl.F.Out,"<td rowspan=\"2\" class=\"TT_HOUR_BIG LEFT_MIDDLE\""
" style=\"width:%u%%;\">"
2017-04-25 14:48:47 +02:00
"%02u:00"
2014-12-26 16:55:46 +01:00
"</td>"
2014-12-01 23:55:08 +01:00
"</tr>",
2017-04-24 01:56:57 +02:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN,
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.Config.Range.Hours.Start);
2014-12-01 23:55:08 +01:00
/***** 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 *****/
2017-04-25 21:20:19 +02:00
for (Interval = 0, Min = Gbl.TimeTable.Config.Range.MinutesPerInterval;
2017-04-25 11:57:36 +02:00
Interval < Gbl.TimeTable.Config.IntervalsPerDay;
Interval++,
2017-04-25 21:20:19 +02:00
Min = (Min + Gbl.TimeTable.Config.Range.MinutesPerInterval) %
2017-04-25 11:57:36 +02:00
TT_SECONDS_PER_MINUTE)
2014-12-01 23:55:08 +01:00
{
fprintf (Gbl.F.Out,"<tr>");
2017-04-24 21:12:53 +02:00
/* Left hour:minutes cell */
if (Interval % 2)
2017-04-25 21:20:19 +02:00
TT_TimeTableDrawHourCell (Gbl.TimeTable.Config.Range.Hours.Start +
2017-04-25 11:57:36 +02:00
(Interval + 2) / Gbl.TimeTable.Config.IntervalsPerHour,
2017-04-24 21:12:53 +02:00
Min,
"RIGHT_MIDDLE");
2014-12-01 23:55:08 +01:00
/* Empty column used to adjust height */
TT_DrawCellAlignTimeTable ();
/* Row for this hour */
2015-11-30 21:23:14 +01:00
for (DayColumn = 0;
2017-04-24 21:12:53 +02:00
DayColumn < TT_DAYS_PER_WEEK;
2015-11-30 21:23:14 +01:00
DayColumn++)
2014-12-01 23:55:08 +01:00
{
2017-04-24 21:12:53 +02:00
/* Weekday == 0 ==> monday,
2015-11-30 21:23:14 +01:00
...
2017-04-24 21:12:53 +02:00
Weekday == 6 ==> sunday */
Weekday = (DayColumn + Gbl.Prefs.FirstDayOfWeek) % 7;
2015-11-30 21:23:14 +01:00
2014-12-01 23:55:08 +01:00
/* Check how many colums are needed.
2017-04-25 02:07:32 +02:00
For each item (class) in this hour from left to right,
we must check the maximum of columns */
2017-04-25 11:57:36 +02:00
ColumnsToDraw = TT_CalculateColsToDrawInCell (true, // Top call, non recursive
Weekday,Interval);
2017-04-25 21:42:29 +02:00
if (ColumnsToDraw == 0 &&
(Gbl.TimeTable.View == TT_CRS_VIEW ||
Gbl.TimeTable.View == TT_TUT_VIEW))
2014-12-01 23:55:08 +01:00
ColumnsToDraw = 1;
2017-04-25 14:48:47 +02:00
// If editing and there's place for more columns,
// a potential new column is added at the end of each day
2014-12-01 23:55:08 +01:00
ColumnsToDrawIncludingExtraColumn = ColumnsToDraw;
2017-04-25 21:42:29 +02:00
if (ColumnsToDraw < TT_MAX_COLUMNS_PER_CELL &&
(Gbl.TimeTable.View == TT_CRS_EDIT ||
Gbl.TimeTable.View == TT_TUT_EDIT))
2014-12-01 23:55:08 +01:00
ColumnsToDrawIncludingExtraColumn++;
2017-04-24 01:56:57 +02:00
/* Draw cells */
2014-12-01 23:55:08 +01:00
for (Column = 0, ContinuousFreeMinicolumns = 0;
Column < ColumnsToDrawIncludingExtraColumn;
Column++)
2017-04-24 21:12:53 +02:00
if (TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType == TT_FREE_INTERVAL)
ContinuousFreeMinicolumns += TT_NUM_MINICOLUMNS_PER_DAY /
ColumnsToDrawIncludingExtraColumn;
2014-12-01 23:55:08 +01:00
else
{
if (ContinuousFreeMinicolumns)
{
2017-04-24 21:12:53 +02:00
TT_TimeTableDrawCell (Weekday,Interval,Column - 1,ContinuousFreeMinicolumns,
-1L,TT_FREE_INTERVAL,TT_FREE,0,NULL,-1,NULL);
2014-12-01 23:55:08 +01:00
ContinuousFreeMinicolumns = 0;
}
2017-04-24 21:12:53 +02:00
TT_TimeTableDrawCell (Weekday,Interval,Column,
TT_NUM_MINICOLUMNS_PER_DAY /
ColumnsToDrawIncludingExtraColumn,
TT_TimeTable[Weekday][Interval].Columns[Column].CrsCod,
TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType,
TT_TimeTable[Weekday][Interval].Columns[Column].ClassType,
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals,
2017-04-24 21:12:53 +02:00
TT_TimeTable[Weekday][Interval].Columns[Column].Group,
TT_TimeTable[Weekday][Interval].Columns[Column].GrpCod,
TT_TimeTable[Weekday][Interval].Columns[Column].Place);
2014-12-01 23:55:08 +01:00
}
if (ContinuousFreeMinicolumns)
2017-04-24 21:12:53 +02:00
TT_TimeTableDrawCell (Weekday,Interval,Column - 1,ContinuousFreeMinicolumns,
-1L,TT_FREE_INTERVAL,TT_FREE,0,NULL,-1L,NULL);
2014-12-01 23:55:08 +01:00
}
/* Empty column used to adjust height */
TT_DrawCellAlignTimeTable ();
2017-04-24 21:12:53 +02:00
/* Right hour:minutes cell */
if (Interval % 2)
2017-04-25 21:20:19 +02:00
TT_TimeTableDrawHourCell (Gbl.TimeTable.Config.Range.Hours.Start +
2017-04-25 11:57:36 +02:00
(Interval + 2) / Gbl.TimeTable.Config.IntervalsPerHour,
2017-04-24 21:12:53 +02:00
Min,
"LEFT_MIDDLE");
2014-12-01 23:55:08 +01:00
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)
{
2017-04-24 21:12:53 +02:00
unsigned Weekday;
2014-12-01 23:55:08 +01:00
unsigned Minicolumn;
fprintf (Gbl.F.Out,"<tr>"
2017-04-25 21:20:19 +02:00
"<td class=\"TT_HOURCOL\"></td>");
2017-04-24 10:13:53 +02:00
TT_DrawCellAlignTimeTable ();
2017-04-24 21:12:53 +02:00
for (Weekday = 0;
Weekday < TT_DAYS_PER_WEEK;
Weekday++)
2014-12-01 23:55:08 +01:00
for (Minicolumn = 0;
Minicolumn < TT_NUM_MINICOLUMNS_PER_DAY;
Minicolumn++)
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<td class=\"TT_MINICOL\"></td>");
2017-04-24 10:13:53 +02:00
TT_DrawCellAlignTimeTable ();
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<td class=\"TT_HOURCOL\"></td>"
"</tr>");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/****************** 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;
2017-04-24 21:12:53 +02:00
unsigned Weekday;
2014-12-01 23:55:08 +01:00
2015-11-30 21:23:14 +01:00
for (DayColumn = 0;
2017-04-24 21:12:53 +02:00
DayColumn < TT_DAYS_PER_WEEK;
2015-11-30 21:23:14 +01:00
DayColumn++)
{
2017-04-24 21:12:53 +02:00
Weekday = (DayColumn + Gbl.Prefs.FirstDayOfWeek) % 7;
2017-04-24 01:56:57 +02:00
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,
2017-04-24 21:12:53 +02:00
Weekday == 6 ? "TT_SUNDAY" : // Sunday drawn in red
"TT_DAY", // Monday to Saturday
2015-11-30 21:23:14 +01:00
TT_PERCENT_WIDTH_OF_A_DAY,
2017-04-24 21:12:53 +02:00
Txt_DAYS_CAPS[Weekday]);
2015-11-30 21:23:14 +01:00
}
2014-12-01 23:55:08 +01:00
}
2017-04-24 10:13:53 +02:00
/*****************************************************************************/
/****************** Draw cells with day names in a time table ****************/
/*****************************************************************************/
2017-04-24 21:12:53 +02:00
static void TT_TimeTableDrawHourCell (unsigned Hour,unsigned Min,const char *Align)
2017-04-24 10:13:53 +02:00
{
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<td rowspan=\"2\" class=\"TT_HOUR %s %s\">"
2017-04-25 14:48:47 +02:00
"%02u:%02u"
"</td>",
2017-04-24 10:13:53 +02:00
Min ? "TT_HOUR_SMALL" :
"TT_HOUR_BIG",
Align,
2017-04-25 14:48:47 +02:00
Hour,Min);
2017-04-24 10:13:53 +02:00
}
2014-12-01 23:55:08 +01:00
/*****************************************************************************/
/**** Calculate recursively number of columns to draw for a day and hour *****/
/*****************************************************************************/
2017-04-25 11:57:36 +02:00
static unsigned TT_CalculateColsToDrawInCell (bool TopCall,
unsigned Weekday,unsigned Interval)
2014-12-01 23:55:08 +01:00
{
2015-11-30 21:23:14 +01:00
unsigned ColumnsToDraw;
unsigned Column;
2017-04-25 21:20:19 +02:00
unsigned i;
2015-11-30 21:23:14 +01:00
unsigned FirstHour;
unsigned Cols;
2017-04-25 11:57:36 +02:00
static bool *TT_IntervalsChecked;
if (TopCall) // Top call, non recursive call
{
/****** Allocate space to store list of intervals already checked
and initialize to false by using calloc *****/
if ((TT_IntervalsChecked = (bool *) calloc (Gbl.TimeTable.Config.IntervalsPerDay,
sizeof (bool))) == NULL)
Lay_ShowErrorAndExit ("Error allocating memory for timetable.");
}
2014-12-01 23:55:08 +01:00
2017-04-24 21:12:53 +02:00
ColumnsToDraw = TT_TimeTable[Weekday][Interval].NumColumns;
2014-12-01 23:55:08 +01:00
2017-04-25 11:57:36 +02:00
if (!TT_IntervalsChecked[Interval])
2014-12-01 23:55:08 +01:00
{
2017-04-25 11:57:36 +02:00
TT_IntervalsChecked[Interval] = true;
2014-12-01 23:55:08 +01:00
for (Column = 0;
Column < TT_MAX_COLUMNS_PER_CELL;
Column++)
{
2017-04-24 21:12:53 +02:00
switch (TT_TimeTable[Weekday][Interval].Columns[Column].IntervalType)
2014-12-01 23:55:08 +01:00
{
2017-04-24 21:12:53 +02:00
case TT_FREE_INTERVAL:
2014-12-01 23:55:08 +01:00
break;
2017-04-24 21:12:53 +02:00
case TT_FIRST_INTERVAL:
2014-12-01 23:55:08 +01:00
/* Check from first hour (this one) to last hour searching maximum number of columns */
2017-04-25 21:20:19 +02:00
for (i = Interval + 1;
i < Interval + TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals;
i++)
if (!TT_IntervalsChecked[i])
2014-12-01 23:55:08 +01:00
{
2017-04-25 11:57:36 +02:00
Cols = TT_CalculateColsToDrawInCell (false, // Recursive call
2017-04-25 21:20:19 +02:00
Weekday,i);
2014-12-01 23:55:08 +01:00
if (Cols > ColumnsToDraw)
ColumnsToDraw = Cols;
}
break;
2017-04-24 21:12:53 +02:00
case TT_NEXT_INTERVAL:
2014-12-01 23:55:08 +01:00
/* Find first hour for this item (class) */
2017-04-24 21:12:53 +02:00
for (FirstHour = Interval;
TT_TimeTable[Weekday][FirstHour].Columns[Column].IntervalType == TT_NEXT_INTERVAL;
2014-12-01 23:55:08 +01:00
FirstHour--);
2017-04-25 11:57:36 +02:00
/* Check from first hour to last hour searching maximum number of columns */
2017-04-25 21:20:19 +02:00
for (i = FirstHour;
i < FirstHour + TT_TimeTable[Weekday][FirstHour].Columns[Column].DurationIntervals;
i++)
if (!TT_IntervalsChecked[i])
2014-12-01 23:55:08 +01:00
{
2017-04-25 11:57:36 +02:00
Cols = TT_CalculateColsToDrawInCell (false, // Recursive call
2017-04-25 21:20:19 +02:00
Weekday,i);
2014-12-01 23:55:08 +01:00
if (Cols > ColumnsToDraw)
ColumnsToDraw = Cols;
}
break;
}
}
}
2017-04-25 11:57:36 +02:00
if (TopCall) // Top call, non recursive call
/****** Free space used by list of intervals already checked *****/
free ((void *) TT_IntervalsChecked);
2014-12-01 23:55:08 +01:00
return ColumnsToDraw;
}
/*****************************************************************************/
/******************** Write empty cell for alignment *************************/
/*****************************************************************************/
static void TT_DrawCellAlignTimeTable (void)
{
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<td class=\"TT_ALIGN\"></td>");
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/*************************** Write a timetable cell **************************/
/*****************************************************************************/
2017-04-24 21:12:53 +02:00
static void TT_TimeTableDrawCell (unsigned Weekday,unsigned Interval,unsigned Column,unsigned ColSpan,
long CrsCod,TT_IntervalType_t IntervalType,TT_ClassType_t ClassType,
unsigned DurationNumIntervals,char *Group,long GrpCod,char *Place)
2014-12-01 23:55:08 +01:00
{
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] =
{
2017-04-25 21:42:29 +02:00
"TT_FREE", // TT_FREE (free hour)
"TT_LECT", // TT_LECTURE (lecture class)
"TT_PRAC", // TT_PRACTICAL (practical class)
"TT_TUTO", // TT_TUTORING (tutoring/office hour)
2014-12-01 23:55:08 +01:00
};
struct GroupData GrpDat;
unsigned NumGrpTyp;
unsigned NumGrp;
2017-04-25 21:20:19 +02:00
unsigned i;
2014-12-01 23:55:08 +01:00
unsigned Dur;
unsigned MaxDuration;
unsigned RowSpan = 0;
2017-04-24 13:39:55 +02:00
TT_ClassType_t CT;
2014-12-01 23:55:08 +01:00
struct Course Crs;
/***** Compute row span and background color depending on hour type *****/
2017-04-24 21:12:53 +02:00
switch (IntervalType)
2014-12-01 23:55:08 +01:00
{
2017-04-24 21:12:53 +02:00
case TT_FREE_INTERVAL: // Free cell written
2015-11-30 20:47:37 +01:00
RowSpan = 1;
2014-12-01 23:55:08 +01:00
break;
2017-04-24 21:12:53 +02:00
case TT_FIRST_INTERVAL: // Normal cell written
RowSpan = DurationNumIntervals;
2014-12-01 23:55:08 +01:00
break;
2017-04-24 21:12:53 +02:00
case TT_NEXT_INTERVAL: // Nothing written
2014-12-01 23:55:08 +01:00
break;
}
/***** If there's nothing to do... *****/
if (RowSpan == 0)
return;
/***** If group code > 0, a group is selected ==> get group type and name *****/
2017-04-24 21:12:53 +02:00
if (IntervalType == TT_FIRST_INTERVAL &&
2017-04-25 21:42:29 +02:00
(Gbl.TimeTable.View == TT_CRS_VIEW ||
Gbl.TimeTable.View == TT_CRS_EDIT) &&
2014-12-01 23:55:08 +01:00
GrpCod > 0)
{
/* Get group type and name */
GrpDat.GrpCod = GrpCod;
Grp_GetDataOfGroupByCod (&GrpDat);
}
/***** Cell start *****/
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<td");
if (RowSpan > 1)
fprintf (Gbl.F.Out," rowspan=\"%u\"",RowSpan);
if (ColSpan > 1)
fprintf (Gbl.F.Out," colspan=\"%u\"",ColSpan);
fprintf (Gbl.F.Out," class=\"%s",TimeTableClasses[ClassType]);
2017-04-24 13:39:55 +02:00
if (ClassType == TT_FREE)
2017-04-24 21:12:53 +02:00
fprintf (Gbl.F.Out,"%u",Interval % 4);
2017-04-25 21:20:19 +02:00
else
fprintf (Gbl.F.Out," CENTER_MIDDLE DAT_SMALL");
fprintf (Gbl.F.Out,"\">");
2014-12-01 23:55:08 +01:00
/***** Form to modify this cell *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_EDIT)
2015-12-01 00:38:22 +01:00
Act_FormStart (ActChgCrsTT);
2017-04-25 21:42:29 +02:00
else if (Gbl.TimeTable.View == TT_TUT_EDIT)
2014-12-01 23:55:08 +01:00
Act_FormStart (ActChgTut);
/***** Draw cell depending on type of view *****/
2017-04-25 21:42:29 +02:00
switch (Gbl.TimeTable.View)
2014-12-01 23:55:08 +01:00
{
2017-04-25 21:42:29 +02:00
case TT_CRS_VIEW: // View course timetable
case TT_TUT_VIEW: // View tutoring timetable
2017-04-24 21:12:53 +02:00
if (IntervalType != TT_FREE_INTERVAL) // If cell is not empty...
2014-12-01 23:55:08 +01:00
{
2017-04-25 02:07:32 +02:00
/***** Start cell *****/
2017-03-05 19:15:57 +01:00
fprintf (Gbl.F.Out,"<div class=\"TT_CELL TT_TXT\">");
2017-04-25 02:07:32 +02:00
/***** Course name *****/
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);
2017-04-24 13:39:55 +02:00
if (ClassType == TT_LECTURE ||
ClassType == TT_PRACTICAL)
2014-12-01 23:55:08 +01:00
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
}
2017-04-25 02:07:32 +02:00
/***** Type of class and duration *****/
2017-04-25 14:48:47 +02:00
fprintf (Gbl.F.Out,"%s (%u:%02u)",
2017-04-24 13:39:55 +02:00
Txt_TIMETABLE_CLASS_TYPES[ClassType],
2017-04-25 11:57:36 +02:00
(DurationNumIntervals / Gbl.TimeTable.Config.IntervalsPerHour), // Hours
(DurationNumIntervals % Gbl.TimeTable.Config.IntervalsPerHour) *
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.Config.Range.MinutesPerInterval); // Minutes
2017-04-25 02:07:32 +02:00
/***** Group *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_VIEW)
2014-12-01 23:55:08 +01:00
{
2017-04-25 02:07:32 +02:00
if (GrpCod <= 0)
2014-12-01 23:55:08 +01:00
{
if (Group[0])
fprintf (Gbl.F.Out,"<br />%s",Group);
}
else
fprintf (Gbl.F.Out,"<br />%s %s",
GrpDat.GrpTypName,GrpDat.GrpName);
}
2017-04-25 02:07:32 +02:00
/***** Place *****/
if (Place[0])
fprintf (Gbl.F.Out,"<br />%s",Place);
/***** End cell *****/
2017-03-05 19:15:57 +01:00
fprintf (Gbl.F.Out,"</div>");
2014-12-01 23:55:08 +01:00
}
break;
case TT_CRS_EDIT:
case TT_TUT_EDIT:
2017-04-25 21:20:19 +02:00
Par_PutHiddenParamUnsigned ("TTDay",Weekday);
Par_PutHiddenParamUnsigned ("TTInt",Interval);
Par_PutHiddenParamUnsigned ("TTCol",Column);
2014-12-01 23:55:08 +01:00
/***** Class type *****/
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<select name=\"TTTyp\" 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);
2017-04-24 13:39:55 +02:00
for (CT = (TT_ClassType_t) 0;
CT < (TT_ClassType_t) TT_NUM_CLASS_TYPES;
2014-12-01 23:55:08 +01:00
CT++)
2017-04-24 13:00:59 +02:00
if ((CT == TT_FREE) ||
2017-04-25 21:42:29 +02:00
((Gbl.TimeTable.View == TT_CRS_EDIT) && (CT == TT_LECTURE || CT == TT_PRACTICAL)) ||
((Gbl.TimeTable.View == TT_TUT_EDIT) && (CT == TT_TUTORING)))
2014-12-01 23:55:08 +01:00
{
fprintf (Gbl.F.Out,"<option");
2017-04-24 13:39:55 +02:00
if (CT == ClassType)
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out," selected=\"selected\"");
fprintf (Gbl.F.Out," value=\"%s\">%s</option>",
2017-04-25 14:48:47 +02:00
TT_ClassTypeDB[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>");
2017-04-25 02:07:32 +02:00
2017-04-24 21:12:53 +02:00
if (IntervalType == TT_FREE_INTERVAL)
2014-12-01 23:55:08 +01:00
{
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<input type=\"hidden\" name=\"TTDur\" value=\"");
for (i = Interval + 1;
i < Gbl.TimeTable.Config.IntervalsPerDay;
i++)
if (TT_TimeTable[Weekday][i].NumColumns == TT_MAX_COLUMNS_PER_CELL)
2014-12-01 23:55:08 +01:00
break;
2017-04-25 21:20:19 +02:00
MaxDuration = i - Interval;
2017-04-25 11:57:36 +02:00
Dur = (MaxDuration >= Gbl.TimeTable.Config.IntervalsPerHour) ? Gbl.TimeTable.Config.IntervalsPerHour : // MaxDuration >= 1h ==> Dur = 1h
2017-04-25 21:20:19 +02:00
MaxDuration; // MaxDuration < 1h ==> Dur = MaxDuration
2017-04-25 14:48:47 +02:00
fprintf (Gbl.F.Out,"%u:%02u\" />",
2017-04-25 11:57:36 +02:00
(Dur / Gbl.TimeTable.Config.IntervalsPerHour), // Hours
(Dur % Gbl.TimeTable.Config.IntervalsPerHour) *
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.Config.Range.MinutesPerInterval); // Minutes
2014-12-01 23:55:08 +01:00
}
else
{
/***** Class duration *****/
2017-04-25 21:20:19 +02:00
fprintf (Gbl.F.Out,"<select name=\"TTDur\" 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);
2017-04-25 21:20:19 +02:00
for (i = Interval + TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals;
i < Gbl.TimeTable.Config.IntervalsPerDay;
i++)
if (TT_TimeTable[Weekday][i].NumColumns == TT_MAX_COLUMNS_PER_CELL)
2014-12-01 23:55:08 +01:00
break;
2017-04-25 21:20:19 +02:00
MaxDuration = i - Interval;
if (TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals > MaxDuration)
MaxDuration = TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals;
2014-12-01 23:55:08 +01:00
for (Dur = 0;
Dur <= MaxDuration;
Dur++)
{
fprintf (Gbl.F.Out,"<option");
2017-04-24 21:12:53 +02:00
if (Dur == DurationNumIntervals)
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out," selected=\"selected\"");
2017-04-25 14:48:47 +02:00
fprintf (Gbl.F.Out,">%u:%02u</option>",
2017-04-25 11:57:36 +02:00
(Dur / Gbl.TimeTable.Config.IntervalsPerHour), // Hours
(Dur % Gbl.TimeTable.Config.IntervalsPerHour) *
2017-04-25 21:20:19 +02:00
Gbl.TimeTable.Config.Range.MinutesPerInterval); // Minutes
2014-12-01 23:55:08 +01:00
}
fprintf (Gbl.F.Out,"</select>");
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_EDIT)
2014-12-01 23:55:08 +01:00
{
/***** Group *****/
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"<br />"
"<label>"
"%s"
2017-04-25 21:20:19 +02:00
"<select name=\"TTGrp\""
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\"");
fprintf (Gbl.F.Out,">%s %s</option>",
Gbl.CurrentCrs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].GrpTypName,
Gbl.CurrentCrs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp].LstGrps[NumGrp].GrpName);
}
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"</select>"
"</label>");
2014-12-01 23:55:08 +01:00
/***** Class room *****/
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"<br />"
"<label>"
"%s"
2017-04-25 21:20:19 +02:00
"<input type=\"text\" name=\"TTPlc\""
2015-10-22 14:49:48 +02:00
" size=\"1\" maxlength=\"%u\" value=\"%s\""
2016-12-26 16:35:01 +01:00
" onchange=\"document.getElementById('%s').submit();\" />"
"</label>",
2017-03-08 03:48:23 +01:00
Txt_Classroom,TT_MAX_CHARS_PLACE,Place,Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
}
else // TimeTableView == TT_TUT_EDIT
{
/***** Place *****/
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"<br />"
2016-12-27 16:45:37 +01:00
"<label class=\"DAT_SMALL\">"
2016-12-26 16:35:01 +01:00
"%s"
2017-04-25 21:20:19 +02:00
"<input type=\"text\" name=\"TTPlc\""
2015-10-22 14:49:48 +02:00
" size=\"12\" maxlength=\"%u\" value=\"%s\""
2016-12-26 16:35:01 +01:00
" onchange=\"document.getElementById('%s').submit();\" />"
"</label>",
2017-03-08 03:48:23 +01:00
Txt_Place,TT_MAX_CHARS_PLACE,Place,Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
}
}
break;
}
/***** End of form *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_EDIT ||
Gbl.TimeTable.View == 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>");
}