swad-core/swad_timetable.c

1755 lines
66 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.
2019-01-07 21:52:19 +01:00
Copyright (C) 1999-2019 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 *********************************/
/*****************************************************************************/
2019-01-07 13:19:57 +01:00
#define _GNU_SOURCE // For asprintf
2014-12-01 23:55:08 +01:00
#include <linux/stddef.h> // For NULL
2019-01-07 13:19:57 +01:00
#include <stdio.h> // For asprintf
2017-04-27 10:15:07 +02:00
#include <stdlib.h> // For malloc, calloc, free
2014-12-01 23:55:08 +01:00
#include <string.h> // For string functions
2017-06-10 21:38:10 +02:00
#include "swad_box.h"
2015-12-01 00:38:22 +01:00
#include "swad_calendar.h"
2014-12-01 23:55:08 +01:00
#include "swad_database.h"
2018-11-09 20:47:39 +01:00
#include "swad_form.h"
2014-12-01 23:55:08 +01:00
#include "swad_global.h"
2018-12-08 16:43:13 +01:00
#include "swad_language.h"
2014-12-01 23:55:08 +01:00
#include "swad_parameter.h"
2019-03-26 11:53:21 +01:00
#include "swad_setting.h"
2019-10-03 22:55:00 +02:00
#include "swad_table.h"
2014-12-01 23:55:08 +01:00
#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
2017-06-12 14:16:33 +02:00
#define TT_PERCENT_WIDTH_OF_A_SEPARATION_COLUMN 1 // Width (%) of left and right columns
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;
2019-01-07 17:00:04 +01:00
char Info[TT_MAX_BYTES_INFO + 1];
// char Place[TT_MAX_BYTES_PLACE + 1];
2017-04-25 14:48:47 +02:00
};
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,
2019-01-07 17:00:04 +01:00
unsigned DurationNumIntervals,long GrpCod,const char *Info);
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;
2019-10-15 15:23:38 +02:00
fprintf (Gbl.F.Out,"<div class=\"CLASSPHOTO_TITLE CM\">");
2019-04-04 10:45:15 +02:00
switch (Gbl.Crs.Grps.WhichGrps)
2014-12-01 23:55:08 +01:00
{
2019-09-29 17:33:39 +02:00
case Grp_MY_GROUPS:
2014-12-01 23:55:08 +01:00
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
2019-01-07 17:00:04 +01:00
/***** Get info *****/
Par_GetParToText ("TTInf",Gbl.TimeTable.Info,TT_MAX_BYTES_INFO);
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 &&
2017-06-04 18:18:54 +02:00
Gbl.Usrs.Me.Role.Logged >= Rol_TCH);
2016-03-18 14:07:21 +01:00
Gbl.TimeTable.ContextualIcons.PutIconEditOfficeHours = (Gbl.TimeTable.Type == TT_MY_TIMETABLE &&
!PrintView &&
2017-06-04 18:18:54 +02:00
(Gbl.Usrs.Me.Role.Available & (1 << Rol_TCH)));
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
2017-06-12 14:16:33 +02:00
/***** Start box *****/
2017-06-10 21:38:10 +02:00
Box_StartBox ("100%",Txt_TIMETABLE_TYPES[Gbl.TimeTable.Type],
2017-06-11 22:26:40 +02:00
(Gbl.TimeTable.ContextualIcons.PutIconEditCrsTT ||
Gbl.TimeTable.ContextualIcons.PutIconEditOfficeHours ||
Gbl.TimeTable.ContextualIcons.PutIconPrint) ? TT_PutContextualIcons :
NULL,
2017-06-12 15:03:29 +02:00
Help[Gbl.TimeTable.Type],Box_NOT_CLOSABLE);
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,
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Ins.InsCod,Gbl.Hierarchy.Deg.DegCod,Gbl.Hierarchy.Crs.CrsCod);
2014-12-08 17:35:48 +01:00
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
{
2019-03-26 11:53:21 +01:00
/***** Setting selector *****/
Set_StartSettingsHead ();
2019-02-25 15:14:28 +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 &&
2019-04-04 10:45:15 +02:00
Gbl.Crs.Grps.NumGrps))
2016-11-26 22:07:52 +01:00
TT_PutFormToSelectWhichGroupsToShow ();
2015-12-01 00:38:22 +01:00
2019-02-25 15:14:28 +01:00
/* Show form to change first day of week */
2016-11-26 22:02:42 +01:00
Cal_ShowFormToSelFirstDayOfWeek (ActChgTT1stDay[Gbl.TimeTable.Type],
2019-01-12 03:00:59 +01:00
Grp_PutParamWhichGrps);
2019-02-25 15:14:28 +01:00
2019-03-26 11:53:21 +01:00
Set_EndSettingsHead ();
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
2017-06-12 14:16:33 +02:00
/***** End box *****/
2017-06-10 21:38:10 +02:00
Box_EndBox ();
2016-03-18 14:07:21 +01:00
}
/*****************************************************************************/
/***************** Put contextual icons above the time table *****************/
/*****************************************************************************/
static void TT_PutContextualIcons (void)
{
if (Gbl.TimeTable.ContextualIcons.PutIconEditCrsTT)
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToEdit (ActEdiCrsTT,Grp_PutParamWhichGrps);
2016-03-18 14:07:21 +01:00
if (Gbl.TimeTable.ContextualIcons.PutIconEditOfficeHours)
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToEdit (ActEdiTut,NULL);
2016-03-18 14:07:21 +01:00
if (Gbl.TimeTable.ContextualIcons.PutIconPrint)
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToPrint (Gbl.TimeTable.Type == TT_COURSE_TIMETABLE ? ActPrnCrsTT :
2017-04-30 19:44:18 +02:00
ActPrnMyTT,
Grp_PutParamWhichGrps);
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;
2017-06-11 22:26:40 +02:00
Box_StartBox ("100%",Txt_TIMETABLE_TYPES[Gbl.TimeTable.Type],TT_PutIconToViewCrsTT,
2017-06-12 15:03:29 +02:00
Hlp_COURSE_Timetable,Box_NOT_CLOSABLE);
2016-03-18 14:07:21 +01:00
TT_ShowTimeTable (Gbl.Usrs.Me.UsrDat.UsrCod);
2017-06-10 21:38:10 +02:00
Box_EndBox ();
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;
2017-06-11 22:26:40 +02:00
Box_StartBox ("100%",Txt_TIMETABLE_TYPES[Gbl.TimeTable.Type],TT_PutIconToViewMyTT,
2017-06-12 15:03:29 +02:00
Hlp_PROFILE_Timetable,Box_NOT_CLOSABLE);
2016-03-18 14:07:21 +01:00
TT_ShowTimeTable (Gbl.Usrs.Me.UsrDat.UsrCod);
2017-06-10 21:38:10 +02:00
Box_EndBox ();
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)
{
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToView (ActSeeCrsTT,NULL);
2016-03-18 14:17:19 +01:00
}
/*****************************************************************************/
/************************ Put icon to view my timetable **********************/
/*****************************************************************************/
static void TT_PutIconToViewMyTT (void)
{
2017-06-11 19:13:28 +02:00
Ico_PutContextualIconToView (ActSeeMyTT,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;
2019-03-11 13:33:34 +01: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:
2019-04-04 10:45:15 +02:00
TT_WriteCrsTimeTableIntoDB (Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
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
2019-02-16 19:29:27 +01:00
Ale_ShowAlert (Ale_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-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 *****/
2018-11-02 22:27:26 +01:00
DB_QueryDELETE ("can not remove former timetable",
"DELETE FROM timetable_crs WHERE CrsCod=%ld",
CrsCod);
2014-12-01 23:55:08 +01:00
/***** 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)
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create course timetable",
"INSERT INTO timetable_crs"
" (CrsCod,GrpCod,Weekday,StartTime,Duration,"
2019-01-07 17:00:04 +01:00
"ClassType,Info)"
2018-11-02 19:37:11 +01:00
" VALUES"
" (%ld,%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),"
2019-01-07 17:00:04 +01:00
"'%s','%s')",
2018-11-02 19:37:11 +01:00
CrsCod,
TT_TimeTable[Weekday][Interval].Columns[Column].GrpCod,
Weekday,
Hour,Min,
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals *
Gbl.TimeTable.Config.SecondsPerInterval,
TT_ClassTypeDB[TT_TimeTable[Weekday][Interval].Columns[Column].ClassType],
2019-01-07 17:00:04 +01:00
TT_TimeTable[Weekday][Interval].Columns[Column].Info);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********************* Write tutor timetable into database *******************/
/*****************************************************************************/
static void TT_WriteTutTimeTableIntoDB (long UsrCod)
{
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 *****/
2018-11-02 22:27:26 +01:00
DB_QueryDELETE ("can not remove former timetable",
"DELETE FROM timetable_tut WHERE UsrCod=%ld",
UsrCod);
2014-12-01 23:55:08 +01:00
/***** 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)
2018-11-02 19:37:11 +01:00
DB_QueryINSERT ("can not create office timetable",
"INSERT INTO timetable_tut"
2019-01-07 17:00:04 +01:00
" (UsrCod,Weekday,StartTime,Duration,Info)"
2018-11-02 19:37:11 +01:00
" VALUES"
" (%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),'%s')",
UsrCod,
Weekday,
Hour,Min,
TT_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals *
Gbl.TimeTable.Config.SecondsPerInterval,
2019-01-07 17:00:04 +01:00
TT_TimeTable[Weekday][Interval].Columns[Column].Info);
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********** 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;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
2018-11-02 01:23:05 +01:00
unsigned long NumRows = 0; // Initialized to avoid warning
2017-04-24 13:00:59 +02:00
unsigned long NumRow;
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;
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:
2019-04-04 10:45:15 +02:00
switch (Gbl.Crs.Grps.WhichGrps)
2014-12-01 23:55:08 +01:00
{
2019-09-29 17:33:39 +02:00
case Grp_MY_GROUPS:
2018-11-02 01:23:05 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get timetable",
"SELECT timetable_crs.Weekday,"
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
2019-01-07 17:00:04 +01:00
"timetable_crs.Info,"
2018-11-02 01:23:05 +01:00
"timetable_crs.ClassType,"
"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.Weekday,"
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
2019-01-07 17:00:04 +01:00
"timetable_crs.Info,"
2018-11-02 01:23:05 +01:00
"timetable_crs.ClassType,"
"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 Weekday,"
"TIME_TO_SEC(StartTime) AS S,"
"TIME_TO_SEC(Duration) AS D,"
2019-01-07 17:00:04 +01:00
"Info,"
2018-11-02 01:23:05 +01:00
"'tutoring' AS ClassType,"
"-1 AS GrpCod,"
"-1 AS CrsCod"
" FROM timetable_tut"
" WHERE UsrCod=%ld"
" ORDER BY Weekday,S,ClassType,"
2019-01-07 17:00:04 +01:00
"GrpCod,Info,D DESC,CrsCod",
2018-11-02 01:23:05 +01:00
UsrCod,UsrCod,UsrCod);
2014-12-01 23:55:08 +01:00
break;
case Grp_ALL_GROUPS:
2018-11-02 01:23:05 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get timetable",
"SELECT timetable_crs.Weekday,"
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
2019-01-07 17:00:04 +01:00
"timetable_crs.Info,"
2018-11-02 01:23:05 +01:00
"timetable_crs.ClassType,"
"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 Weekday,"
"TIME_TO_SEC(StartTime) AS S,"
"TIME_TO_SEC(Duration) AS D,"
2019-01-07 17:00:04 +01:00
"Info,"
2018-11-02 01:23:05 +01:00
"'tutoring' AS ClassType,"
"-1 AS GrpCod,"
"-1 AS CrsCod"
" FROM timetable_tut"
" WHERE UsrCod=%ld"
" ORDER BY Weekday,S,ClassType,"
2019-01-07 17:00:04 +01:00
"GrpCod,Info,D DESC,CrsCod",
2018-11-02 01:23:05 +01:00
UsrCod,UsrCod);
2014-12-01 23:55:08 +01:00
break;
}
break;
case TT_COURSE_TIMETABLE:
2019-04-04 10:45:15 +02:00
if (Gbl.Crs.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
2018-11-02 01:23:05 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get timetable",
"SELECT Weekday,"
"TIME_TO_SEC(StartTime) AS S,"
"TIME_TO_SEC(Duration) AS D,"
2019-01-07 17:00:04 +01:00
"Info,"
2018-11-02 01:23:05 +01:00
"ClassType,"
"GrpCod"
" FROM timetable_crs"
" WHERE CrsCod=%ld"
" ORDER BY Weekday,S,ClassType,"
2019-01-07 17:00:04 +01:00
"GrpCod,Info,D DESC",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod);
2014-12-01 23:55:08 +01:00
else
2018-11-02 01:23:05 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get timetable",
"SELECT timetable_crs.Weekday,"
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
2019-01-07 17:00:04 +01:00
"timetable_crs.Info,"
2018-11-02 01:23:05 +01:00
"timetable_crs.ClassType,"
"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.Weekday,"
"TIME_TO_SEC(timetable_crs.StartTime) AS S,"
"TIME_TO_SEC(timetable_crs.Duration) AS D,"
2019-01-07 17:00:04 +01:00
"timetable_crs.Info,"
2018-11-02 01:23:05 +01:00
"timetable_crs.ClassType,"
"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 Weekday,S,ClassType,"
2019-01-07 17:00:04 +01:00
"GrpCod,Info,D DESC",
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod,UsrCod,
Gbl.Hierarchy.Crs.CrsCod,UsrCod);
2014-12-01 23:55:08 +01:00
break;
2017-04-24 13:00:59 +02:00
case TT_TUTORING_TIMETABLE:
2018-11-02 01:23:05 +01:00
NumRows = DB_QuerySELECT (&mysql_res,"can not get timetable",
"SELECT Weekday,"
"TIME_TO_SEC(StartTime) AS S,"
"TIME_TO_SEC(Duration) AS D,"
2019-01-07 17:00:04 +01:00
"Info"
2018-11-02 01:23:05 +01:00
" FROM timetable_tut"
" WHERE UsrCod=%ld"
2019-01-07 17:00:04 +01:00
" ORDER BY Weekday,S,Info,D DESC",
2018-11-02 01:23:05 +01:00
UsrCod);
2014-12-01 23:55:08 +01:00
break;
}
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;
2019-01-07 17:00:04 +01:00
TT_TimeTable[Weekday][Interval].Columns[Column].Info[0] = '\0';
2017-04-25 21:20:19 +02:00
}
}
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
/* 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++;
}
2019-01-07 17:00:04 +01:00
/* Course (row[6]) and info (row[3])*/
2017-04-25 21:20:19 +02:00
switch (Gbl.TimeTable.Type)
{
case TT_MY_TIMETABLE:
case TT_COURSE_TIMETABLE:
2019-01-07 17:00:04 +01:00
/* Group code (row[5]) */
if (Gbl.TimeTable.Type == TT_MY_TIMETABLE ||
Gbl.TimeTable.Type == TT_COURSE_TIMETABLE)
if (sscanf (row[5],"%ld",&TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].GrpCod) != 1)
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].GrpCod = -1;
/* Course code (row[6]) */
2017-04-25 21:20:19 +02:00
TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].CrsCod =
2019-01-07 17:00:04 +01:00
(Gbl.TimeTable.Type == TT_MY_TIMETABLE ? Str_ConvertStrCodToLongCod (row[6]) :
2019-04-04 10:45:15 +02:00
Gbl.Hierarchy.Crs.CrsCod);
2018-10-04 21:57:25 +02:00
/* falls through */
/* no break */
2017-04-25 21:20:19 +02:00
case TT_TUTORING_TIMETABLE:
2019-01-07 17:00:04 +01:00
Str_Copy (TT_TimeTable[Weekday][Interval].Columns[FirstFreeColumn].Info,
2017-04-25 21:20:19 +02:00
row[3],
2019-01-07 17:00:04 +01:00
TT_MAX_BYTES_INFO);
2017-04-25 21:20:19 +02:00
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)
2019-02-16 19:29:27 +01:00
Ale_ShowAlert (Ale_INFO,Txt_Incomplete_timetable_for_lack_of_space);
2014-12-01 23:55:08 +01:00
}
2017-04-25 14:48:47 +02:00
/*****************************************************************************/
2017-04-27 10:15:07 +02:00
/** Calculate range of a cell (start hour, end hour, minutes per interval) ***/
2017-04-25 14:48:47 +02:00
/*****************************************************************************/
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-27 10:15:07 +02:00
/*****************************************************************************/
/*********************** Calculate minutes per interval **********************/
/*****************************************************************************/
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;
2019-01-07 17:00:04 +01:00
TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Info[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;
2019-01-07 17:00:04 +01:00
Str_Copy (TT_TimeTable[Gbl.TimeTable.Weekday][Gbl.TimeTable.Interval].Columns[Gbl.TimeTable.Column].Info,
Gbl.TimeTable.Info,
TT_MAX_BYTES_INFO);
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
2017-06-12 14:16:33 +02:00
/***** Start table *****/
2019-10-14 15:02:00 +02:00
Tbl_TABLE_Begin ("TT");
2014-12-01 23:55:08 +01:00
/***** Top row used for column adjustement *****/
TT_TimeTableDrawAdjustRow ();
/***** Row with day names *****/
2019-10-10 23:14:13 +02:00
Tbl_TR_Begin (NULL);
2019-10-07 21:15:14 +02:00
2019-10-15 15:23:38 +02:00
Tbl_TD_Begin ("rowspan=\"2\" class=\"TT_HOUR_BIG RM\" style=\"width:%u%%;\"",
2019-10-10 23:14:13 +02:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN);
2019-10-09 23:49:29 +02:00
fprintf (Gbl.F.Out,"%02u:00",Gbl.TimeTable.Config.Range.Hours.Start);
2019-10-10 23:14:13 +02:00
Tbl_TD_End ();
2019-10-07 21:15:14 +02:00
2014-12-01 23:55:08 +01:00
TT_DrawCellAlignTimeTable ();
TT_TimeTableDrawDaysCells ();
TT_DrawCellAlignTimeTable ();
2019-10-07 21:15:14 +02:00
2019-10-15 15:23:38 +02:00
Tbl_TD_Begin ("rowspan=\"2\" class=\"TT_HOUR_BIG LM\" style=\"width:%u%%;\"",
2019-10-10 23:14:13 +02:00
TT_PERCENT_WIDTH_OF_AN_HOUR_COLUMN);
2019-10-09 23:49:29 +02:00
fprintf (Gbl.F.Out,"%02u:00",Gbl.TimeTable.Config.Range.Hours.Start);
2019-10-10 23:14:13 +02:00
Tbl_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-10 23:14:13 +02:00
Tbl_TR_End ();
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
{
2019-10-10 23:14:13 +02:00
Tbl_TR_Begin (NULL);
2014-12-01 23:55:08 +01:00
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,
2019-10-15 15:23:38 +02:00
"RM");
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,
2019-01-07 17:00:04 +01:00
-1L,TT_FREE_INTERVAL,TT_FREE,0,-1L,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].GrpCod,
2019-01-07 17:00:04 +01:00
TT_TimeTable[Weekday][Interval].Columns[Column].Info);
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,
2019-01-07 17:00:04 +01:00
-1L,TT_FREE_INTERVAL,TT_FREE,0,-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,
2019-10-15 15:23:38 +02:00
"LM");
2014-12-01 23:55:08 +01:00
2019-10-10 23:14:13 +02:00
Tbl_TR_End ();
2014-12-01 23:55:08 +01:00
}
/***** 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 *****/
2019-10-10 23:14:13 +02:00
Tbl_TR_Begin (NULL);
2014-12-01 23:55:08 +01:00
TT_DrawCellAlignTimeTable ();
TT_TimeTableDrawDaysCells ();
TT_DrawCellAlignTimeTable ();
2019-10-10 23:14:13 +02:00
Tbl_TR_End ();
2014-12-01 23:55:08 +01:00
/***** Bottom row used for column adjustement *****/
TT_TimeTableDrawAdjustRow ();
2017-06-12 14:16:33 +02:00
/***** End table *****/
2019-10-10 23:14:13 +02:00
Tbl_TABLE_End ();
2014-12-01 23:55:08 +01:00
}
/*****************************************************************************/
/********** 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;
2019-10-10 23:14:13 +02:00
Tbl_TR_Begin (NULL);
2019-10-07 21:15:14 +02:00
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("class=\"TT_HOURCOL\"");
Tbl_TD_End ();
2019-10-07 21:15:14 +02:00
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++)
2019-10-07 21:15:14 +02:00
{
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("class=\"TT_MINICOL\"");
Tbl_TD_End ();
2019-10-07 21:15:14 +02:00
}
2017-04-24 10:13:53 +02:00
TT_DrawCellAlignTimeTable ();
2019-10-07 21:15:14 +02:00
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("class=\"TT_HOURCOL\"");
Tbl_TD_End ();
2019-10-07 21:15:14 +02:00
2019-10-10 23:14:13 +02:00
Tbl_TR_End ();
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;
2019-10-16 00:06:02 +02:00
Tbl_TD_Begin ("colspan=\"%u\" class=\"%s CM\" style=\"width:%u%%;\"",
2019-10-10 23:14:13 +02:00
TT_NUM_MINICOLUMNS_PER_DAY,
Weekday == 6 ? "TT_SUNDAY" : // Sunday drawn in red
"TT_DAY", // Monday to Saturday
TT_PERCENT_WIDTH_OF_A_DAY);
2019-10-09 23:49:29 +02:00
fprintf (Gbl.F.Out,"%s",Txt_DAYS_CAPS[Weekday]);
2019-10-10 23:14:13 +02:00
Tbl_TD_End ();
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
{
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("rowspan=\"2\" class=\"TT_HOUR %s %s\"",
Min ? "TT_HOUR_SMALL" :
"TT_HOUR_BIG",
Align);
2019-10-09 23:49:29 +02:00
fprintf (Gbl.F.Out,"%02u:%02u",Hour,Min);
2019-10-10 23:14:13 +02:00
Tbl_TD_End ();
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:
2017-04-27 10:15:07 +02: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
2017-04-27 10:15:07 +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)
{
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("class=\"TT_ALIGN\"");
Tbl_TD_End ();
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,
2019-01-07 17:00:04 +01:00
unsigned DurationNumIntervals,long GrpCod,const char *Info)
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;
2019-01-07 17:00:04 +01:00
extern const char *Txt_Info;
2014-12-01 23:55:08 +01:00
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
};
2019-01-07 13:19:57 +01:00
char *CellStr; // Unique string for this cell used in labels
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;
2019-10-10 15:03:47 +02:00
char *RowSpanStr;
char *ColSpanStr;
char *ClassStr;
2017-04-24 13:39:55 +02:00
TT_ClassType_t CT;
2014-12-01 23:55:08 +01:00
struct Course Crs;
2019-01-07 13:19:57 +01:00
struct GroupType *GrpTyp;
struct Group *Grp;
2014-12-01 23:55:08 +01:00
/***** 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;
2019-01-07 17:00:04 +01:00
/***** If group code > 0, a group is selected ==> get group data *****/
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)
{
2019-01-07 17:00:04 +01:00
/* Get group data */
2014-12-01 23:55:08 +01:00
GrpDat.GrpCod = GrpCod;
Grp_GetDataOfGroupByCod (&GrpDat);
}
/***** Cell start *****/
2019-10-10 15:03:47 +02:00
/* Create rowspan, colspan and class strings */
2017-04-25 21:20:19 +02:00
if (RowSpan > 1)
2019-10-10 15:03:47 +02:00
{
2019-10-10 21:21:24 +02:00
if (asprintf (&RowSpanStr,"rowspan=\"%u\" ",RowSpan) < 0)
2019-10-10 15:03:47 +02:00
Lay_NotEnoughMemoryExit ();
}
else
{
2019-10-10 21:21:24 +02:00
if (asprintf (&RowSpanStr,"%s","") < 0)
2019-10-10 15:03:47 +02:00
Lay_NotEnoughMemoryExit ();
}
2017-04-25 21:20:19 +02:00
if (ColSpan > 1)
2019-10-10 15:03:47 +02:00
{
2019-10-10 21:21:24 +02:00
if (asprintf (&ColSpanStr,"colspan=\"%u\" ",ColSpan) < 0)
2019-10-10 15:03:47 +02:00
Lay_NotEnoughMemoryExit ();
}
else
{
2019-10-10 21:21:24 +02:00
if (asprintf (&ColSpanStr,"%s","") < 0)
2019-10-10 15:03:47 +02:00
Lay_NotEnoughMemoryExit ();
}
2017-04-24 13:39:55 +02:00
if (ClassType == TT_FREE)
2019-10-10 15:03:47 +02:00
{
if (asprintf (&ClassStr,"%s%u",TimeTableClasses[ClassType],Interval % 4) < 0)
Lay_NotEnoughMemoryExit ();
}
2017-04-25 21:20:19 +02:00
else
2019-10-10 15:03:47 +02:00
{
2019-10-15 15:23:38 +02:00
if (asprintf (&ClassStr,"%s CM DAT_SMALL",TimeTableClasses[ClassType]) < 0)
2019-10-10 15:03:47 +02:00
Lay_NotEnoughMemoryExit ();
}
/* Start cell */
2019-10-10 23:14:13 +02:00
Tbl_TD_Begin ("%s%sclass=\"%s\"",RowSpanStr,ColSpanStr,ClassStr);
2019-10-10 15:03:47 +02:00
/* Free allocated memory for rowspan, colspan and class strings */
free ((void *) RowSpanStr);
free ((void *) ColSpanStr);
free ((void *) ClassStr);
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)
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActChgCrsTT);
2017-04-25 21:42:29 +02:00
else if (Gbl.TimeTable.View == TT_TUT_EDIT)
2018-11-09 20:47:39 +01:00
Frm_StartForm (ActChgTut);
2014-12-01 23:55:08 +01:00
/***** 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 *****/
2019-01-07 17:00:04 +01:00
if (Gbl.TimeTable.View == TT_CRS_VIEW &&
2019-01-07 17:29:10 +01:00
GrpCod > 0)
2014-12-01 23:55:08 +01:00
{
2019-01-07 17:00:04 +01:00
fprintf (Gbl.F.Out,"<br />%s"
2019-01-07 17:29:10 +01:00
"<br />%s",
2019-01-07 17:00:04 +01:00
GrpDat.GrpTypName,GrpDat.GrpName);
if (GrpDat.Classroom.ClaCod > 0)
fprintf (Gbl.F.Out,"<br />(%s)",
GrpDat.Classroom.ShrtName);
2014-12-01 23:55:08 +01:00
}
2017-04-25 02:07:32 +02:00
2019-01-07 17:00:04 +01:00
/***** Info *****/
2019-01-07 17:29:10 +01:00
if (Info)
if (Info[0])
fprintf (Gbl.F.Out,"<br />%s",Info);
2017-04-25 02:07:32 +02:00
/***** 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:
2019-01-07 13:19:57 +01:00
/***** Create unique string for this cell used in labels *****/
if (asprintf (&CellStr,"%02u%02u%02u",
Weekday,Interval,Column) < 0)
Lay_NotEnoughMemoryExit ();
/***** Put hidden parameters *****/
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 *****/
2019-10-16 00:06:02 +02:00
fprintf (Gbl.F.Out,"<select name=\"TTTyp\" class=\"TT_TYP\""
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 *****/
2019-10-16 00:06:02 +02:00
fprintf (Gbl.F.Out,"<select name=\"TTDur\" class=\"TT_DUR\""
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 />"
2019-01-07 13:19:57 +01:00
"<label for=\"TTGrp%s\">"
2016-12-26 16:35:01 +01:00
"%s"
2019-01-07 13:19:57 +01:00
"</label>"
"<select id=\"TTGrp%s\" name=\"TTGrp\""
2019-10-16 00:06:02 +02:00
" class=\"TT_GRP\""
2015-10-22 14:49:48 +02:00
" onchange=\"document.getElementById('%s').submit();\">",
2019-01-07 13:19:57 +01:00
CellStr,
Txt_Group,
CellStr,
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;
2019-04-04 10:45:15 +02:00
NumGrpTyp < Gbl.Crs.Grps.GrpTypes.Num;
2014-12-01 23:55:08 +01:00
NumGrpTyp++)
2019-01-07 13:19:57 +01:00
{
2019-04-04 10:45:15 +02:00
GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp];
2019-01-07 13:19:57 +01:00
2014-12-01 23:55:08 +01:00
for (NumGrp = 0;
2019-01-07 13:19:57 +01:00
NumGrp < GrpTyp->NumGrps;
2014-12-01 23:55:08 +01:00
NumGrp++)
{
2019-01-07 13:19:57 +01:00
Grp = &GrpTyp->LstGrps[NumGrp];
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out,"<option value=\"%ld\"",
2019-01-07 13:19:57 +01:00
Grp->GrpCod);
if (GrpCod == Grp->GrpCod)
2014-12-01 23:55:08 +01:00
fprintf (Gbl.F.Out," selected=\"selected\"");
2019-01-07 13:19:57 +01:00
fprintf (Gbl.F.Out,">%s %s",
GrpTyp->GrpTypName,Grp->GrpName);
if (Grp->Classroom.ClaCod > 0)
fprintf (Gbl.F.Out," (%s)",
Grp->Classroom.ShrtName);
fprintf (Gbl.F.Out,"</option>");
2014-12-01 23:55:08 +01:00
}
2019-01-07 13:19:57 +01:00
}
fprintf (Gbl.F.Out,"</select>");
2014-12-01 23:55:08 +01:00
2019-01-07 17:00:04 +01:00
/***** Info *****/
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"<br />"
2019-01-07 17:00:04 +01:00
"<label for=\"TTInf%s\">"
2016-12-26 16:35:01 +01:00
"%s"
2019-01-07 13:19:57 +01:00
"</label>"
2019-01-07 17:00:04 +01:00
"<input id=\"TTInf%s\" name=\"TTInf\""
2019-01-07 13:19:57 +01:00
" type=\"text\" size=\"1\" maxlength=\"%u\""
2019-10-16 00:06:02 +02:00
" value=\"%s\" class=\"TT_INF\""
2019-01-07 13:19:57 +01:00
" onchange=\"document.getElementById('%s').submit();\" />",
CellStr,
2019-01-07 17:00:04 +01:00
Txt_Info,
2019-01-07 13:19:57 +01:00
CellStr,
2019-01-07 17:29:10 +01:00
TT_MAX_CHARS_INFO,
Info ? Info :
"",
2019-01-07 13:19:57 +01:00
Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
}
else // TimeTableView == TT_TUT_EDIT
{
2019-01-07 17:00:04 +01:00
/***** Info *****/
2016-12-26 16:35:01 +01:00
fprintf (Gbl.F.Out,"<br />"
2019-01-07 17:00:04 +01:00
"<label for=\"TTInf%s\" class=\"DAT_SMALL\">"
2016-12-26 16:35:01 +01:00
"%s"
2019-01-07 13:19:57 +01:00
"</label>"
2019-01-07 17:00:04 +01:00
"<input id=\"TTInf%s\" name=\"TTInf\""
2019-01-07 13:19:57 +01:00
" type=\"text\" size=\"12\" maxlength=\"%u\""
2019-10-16 00:06:02 +02:00
" value=\"%s\" class=\"TT_INF\""
2019-01-07 13:19:57 +01:00
" onchange=\"document.getElementById('%s').submit();\" />",
CellStr,
2019-01-07 17:00:04 +01:00
Txt_Info,
2019-01-07 13:19:57 +01:00
CellStr,
2019-01-07 17:00:04 +01:00
TT_MAX_CHARS_INFO,Info,
2019-01-07 13:19:57 +01:00
Gbl.Form.Id);
2014-12-01 23:55:08 +01:00
}
}
2019-01-07 13:19:57 +01:00
/***** Free allocated unique string for this cell used in labels *****/
free ((void *) CellStr);
2014-12-01 23:55:08 +01:00
break;
}
2017-06-12 14:16:33 +02:00
/***** End form *****/
2017-04-25 21:42:29 +02:00
if (Gbl.TimeTable.View == TT_CRS_EDIT ||
Gbl.TimeTable.View == TT_TUT_EDIT)
2018-11-09 20:47:39 +01:00
Frm_EndForm ();
2014-12-01 23:55:08 +01:00
2017-06-12 14:16:33 +02:00
/***** End cell *****/
2019-10-10 23:14:13 +02:00
Tbl_TD_End ();
2014-12-01 23:55:08 +01:00
}