diff --git a/Makefile b/Makefile index 92df7321..d88366a3 100644 --- a/Makefile +++ b/Makefile @@ -90,7 +90,7 @@ OBJS = swad_account.o swad_account_database.o swad_action.o swad_admin.o \ swad_timeline_favourite.o swad_timeline_form.o swad_timeline_note.o \ swad_timeline_notification.o swad_timeline_post.o \ swad_timeline_publication.o swad_timeline_share.o swad_timeline_user.o \ - swad_timeline_who.o swad_timetable.o \ + swad_timeline_who.o swad_timetable.o swad_timetable_database.o \ swad_user.o \ swad_xml.o \ swad_zip.o diff --git a/swad_changelog.h b/swad_changelog.h index d19d3d1d..b98cb27b 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -602,14 +602,15 @@ TODO: FIX BUG, URGENT! En las fechas como par TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo. */ -#define Log_PLATFORM_VERSION "SWAD 21.47.5 (2021-10-30)" +#define Log_PLATFORM_VERSION "SWAD 21.48 (2021-11-03)" #define CSS_FILE "swad20.45.css" #define JS_FILE "swad20.69.1.js" /* TODO: Rename CENTRE to CENTER in help wiki. TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams - Version 21.47.5: Oct 29, 2021 Queries moved to module swad_questions_database. (321308 lines) + Version 21.48: Nov 03, 2021 New module swad_timetable_database for database queries related to timetables. (321438 lines) + Version 21.47.5: Oct 30, 2021 Queries moved to module swad_questions_database. (321308 lines) Version 21.47.4: Oct 30, 2021 Review of comments. (321253 lines) Version 21.47.3: Oct 29, 2021 Queries moved to module swad_questions_database. (321299 lines) Version 21.47.2: Oct 29, 2021 Queries moved to module swad_questions_database. (321259 lines) diff --git a/swad_group.c b/swad_group.c index 8976f56f..5888b46d 100644 --- a/swad_group.c +++ b/swad_group.c @@ -53,6 +53,7 @@ #include "swad_survey.h" #include "swad_survey_database.h" #include "swad_timetable.h" +#include "swad_timetable_database.h" /*****************************************************************************/ /*************************** Private constants *******************************/ diff --git a/swad_timetable.c b/swad_timetable.c index 9799992d..333b2697 100644 --- a/swad_timetable.c +++ b/swad_timetable.c @@ -42,6 +42,7 @@ #include "swad_parameter.h" #include "swad_setting.h" #include "swad_timetable.h" +#include "swad_timetable_database.h" /*****************************************************************************/ /*************************** External constants ******************************/ @@ -81,16 +82,6 @@ extern struct Globals Gbl; #define Tmt_MAX_BYTES_STR_CLASS_TYPE 256 #define Tmt_MAX_BYTES_STR_DURATION 32 // "hh:mm h" -struct Tmt_Column - { - long CrsCod; // Course code (-1 if no course selected) - long GrpCod; // Group code (-1 if no group selected) - Tmt_IntervalType_t IntervalType; - Tmt_ClassType_t ClassType; - unsigned DurationIntervals; - char Info[Tmt_MAX_BYTES_INFO + 1]; - }; - struct Tmt_Cell { unsigned NumColumns; @@ -101,14 +92,6 @@ struct Tmt_Cell /************************** Private global variables *************************/ /*****************************************************************************/ -static const char *Tmt_ClassTypeDB[Tmt_NUM_CLASS_TYPES] = - { - [Tmt_FREE ] = "free", - [Tmt_LECTURE ] = "lecture", - [Tmt_PRACTICAL] = "practical", - [Tmt_TUTORING ] = "tutoring", - }; - struct Tmt_Cell *Tmt_TimeTable[Tmt_DAYS_PER_WEEK]; /* Possible resolutions of the timetable in minutes */ @@ -137,7 +120,7 @@ static void Tmt_PutIconToViewMyTT (__attribute__((unused)) void *Args); static void Tmt_WriteCrsTimeTableIntoDB (const struct Tmt_Timetable *Timetable, long CrsCod); -static void Tmt_WriteTutTimeTableIntoDB (const struct Tmt_Timetable *Timetable, +static void Tmt_WriteUsrTimeTableIntoDB (const struct Tmt_Timetable *Timetable, long UsrCod); static void Tmt_FillTimeTableFromDB (struct Tmt_Timetable *Timetable, long UsrCod); @@ -237,15 +220,17 @@ static void Tmt_ShowTimeTableGrpsSelected (void) extern const char *Txt_All_groups; HTM_DIV_Begin ("class=\"CLASSPHOTO_TITLE CM\""); - switch (Gbl.Crs.Grps.WhichGrps) - { - case Grp_MY_GROUPS: - HTM_TxtF (Txt_Groups_OF_A_USER,Gbl.Usrs.Me.UsrDat.FullName); - break; - case Grp_ALL_GROUPS: - HTM_Txt (Txt_All_groups); - break; - } + + switch (Gbl.Crs.Grps.WhichGrps) + { + case Grp_MY_GROUPS: + HTM_TxtF (Txt_Groups_OF_A_USER,Gbl.Usrs.Me.UsrDat.FullName); + break; + case Grp_ALL_GROUPS: + HTM_Txt (Txt_All_groups); + break; + } + HTM_DIV_End (); } @@ -255,6 +240,7 @@ static void Tmt_ShowTimeTableGrpsSelected (void) static void Tmt_GetParamsTimeTable (struct Tmt_Timetable *Timetable) { + extern const char *Tmt_DB_ClassType[Tmt_NUM_CLASS_TYPES]; char StrClassType[Tmt_MAX_BYTES_STR_CLASS_TYPE + 1]; char StrDuration[Tmt_MAX_BYTES_STR_DURATION + 1]; unsigned Hours; @@ -286,7 +272,7 @@ static void Tmt_GetParamsTimeTable (struct Tmt_Timetable *Timetable) for (Timetable->ClassType = (Tmt_ClassType_t) 0; Timetable->ClassType <= (Tmt_ClassType_t) (Tmt_NUM_CLASS_TYPES - 1); Timetable->ClassType++) - if (!strcmp (StrClassType,Tmt_ClassTypeDB[Timetable->ClassType])) + if (!strcmp (StrClassType,Tmt_DB_ClassType[Timetable->ClassType])) break; if (Timetable->ClassType > (Tmt_ClassType_t) (Tmt_NUM_CLASS_TYPES - 1)) Err_ShowErrorAndExit ("Type of timetable cell is missing."); @@ -427,7 +413,7 @@ static void Tmt_PutContextualIcons (void *Timetable) if (((struct Tmt_Timetable *) Timetable)->ContextualIcons.PutIconPrint) Ico_PutContextualIconToPrint (((struct Tmt_Timetable *) Timetable)->Type == Tmt_COURSE_TIMETABLE ? ActPrnCrsTT : - ActPrnMyTT, + ActPrnMyTT, Grp_PutParamWhichGroups,&WhichGroups); } } @@ -464,7 +450,7 @@ void Tmt_EditCrsTimeTable (void) Box_BoxBegin ("100%",Txt_TIMETABLE_TYPES[Timetable.Type], Tmt_PutIconToViewCrsTT,NULL, Hlp_COURSE_Timetable,Box_NOT_CLOSABLE); - Tmt_ShowTimeTable (&Timetable,Gbl.Usrs.Me.UsrDat.UsrCod); + Tmt_ShowTimeTable (&Timetable,Gbl.Usrs.Me.UsrDat.UsrCod); Box_BoxEnd (); } @@ -483,7 +469,7 @@ void Tmt_EditMyTutTimeTable (void) Box_BoxBegin ("100%",Txt_TIMETABLE_TYPES[Timetable.Type], Tmt_PutIconToViewMyTT,NULL, Hlp_PROFILE_Timetable,Box_NOT_CLOSABLE); - Tmt_ShowTimeTable (&Timetable,Gbl.Usrs.Me.UsrDat.UsrCod); + Tmt_ShowTimeTable (&Timetable,Gbl.Usrs.Me.UsrDat.UsrCod); Box_BoxEnd (); } @@ -539,7 +525,7 @@ void Tmt_ShowTimeTable (struct Tmt_Timetable *Timetable,long UsrCod) Timetable->View == Tmt_TUT_EDIT) { Timetable->Config.Range.Hours.Start = Tmt_START_HOUR; // Day starts at this hour - Timetable->Config.Range.Hours.End = Tmt_END_HOUR; // Day ends at this hour + Timetable->Config.Range.Hours.End = Tmt_END_HOUR; // Day ends at this hour Timetable->Config.Range.MinutesPerInterval = Tmt_MinutesPerInterval[0]; // The smallest interval Tmt_TimeTableConfigureIntervalsAndAllocateTimeTable (Timetable); } @@ -566,7 +552,7 @@ void Tmt_ShowTimeTable (struct Tmt_Timetable *Timetable,long UsrCod) Tmt_WriteCrsTimeTableIntoDB (Timetable,Gbl.Hierarchy.Crs.CrsCod); break; case Tmt_TUTORING_TIMETABLE: - Tmt_WriteTutTimeTableIntoDB (Timetable,UsrCod); + Tmt_WriteUsrTimeTableIntoDB (Timetable,UsrCod); break; default: break; @@ -600,10 +586,7 @@ static void Tmt_WriteCrsTimeTableIntoDB (const struct Tmt_Timetable *Timetable, unsigned Column; /***** Remove former timetable *****/ - DB_QueryDELETE ("can not remove former timetable", - "DELETE FROM tmt_courses" - " WHERE CrsCod=%ld", - CrsCod); + Tmt_DB_RemoveCrsTimeTable (CrsCod); /***** Go across the timetable inserting classes into database *****/ for (Weekday = 0; @@ -619,29 +602,17 @@ static void Tmt_WriteCrsTimeTableIntoDB (const struct Tmt_Timetable *Timetable, Column++) if (Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType == Tmt_FIRST_INTERVAL && Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals) - DB_QueryINSERT ("can not create course timetable", - "INSERT INTO tmt_courses" - " (CrsCod,GrpCod,Weekday,StartTime,Duration," - "ClassType,Info)" - " VALUES" - " (%ld,%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u)," - "'%s','%s')", - CrsCod, - Tmt_TimeTable[Weekday][Interval].Columns[Column].GrpCod, - Weekday, - Hour, - Min, - Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals * - Timetable->Config.SecondsPerInterval, - Tmt_ClassTypeDB[Tmt_TimeTable[Weekday][Interval].Columns[Column].ClassType], - Tmt_TimeTable[Weekday][Interval].Columns[Column].Info); + Tmt_DB_InsertHourInCrsTimeTable (CrsCod, + &Tmt_TimeTable[Weekday][Interval].Columns[Column], + Weekday,Hour,Min, + Timetable->Config.SecondsPerInterval); } /*****************************************************************************/ /********************* Write tutor timetable into database *******************/ /*****************************************************************************/ -static void Tmt_WriteTutTimeTableIntoDB (const struct Tmt_Timetable *Timetable, +static void Tmt_WriteUsrTimeTableIntoDB (const struct Tmt_Timetable *Timetable, long UsrCod) { unsigned Weekday; @@ -651,10 +622,7 @@ static void Tmt_WriteTutTimeTableIntoDB (const struct Tmt_Timetable *Timetable, unsigned Column; /***** Remove former timetable *****/ - DB_QueryDELETE ("can not remove former timetable", - "DELETE FROM tmt_tutoring" - " WHERE UsrCod=%ld", - UsrCod); + Tmt_DB_RemoveUsrTimeTable (UsrCod); /***** Loop over timetable *****/ for (Weekday = 0; @@ -670,18 +638,10 @@ static void Tmt_WriteTutTimeTableIntoDB (const struct Tmt_Timetable *Timetable, Column++) if (Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType == Tmt_FIRST_INTERVAL && Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals) - DB_QueryINSERT ("can not create office timetable", - "INSERT INTO tmt_tutoring" - " (UsrCod,Weekday,StartTime,Duration,Info)" - " VALUES" - " (%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),'%s')", - UsrCod, - Weekday, - Hour, - Min, - Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals * - Timetable->Config.SecondsPerInterval, - Tmt_TimeTable[Weekday][Interval].Columns[Column].Info); + Tmt_DB_InsertHourInUsrTimeTable (UsrCod, + &Tmt_TimeTable[Weekday][Interval].Columns[Column], + Weekday,Hour,Min, + Timetable->Config.SecondsPerInterval); } /*****************************************************************************/ @@ -691,6 +651,7 @@ static void Tmt_WriteTutTimeTableIntoDB (const struct Tmt_Timetable *Timetable, static void Tmt_FillTimeTableFromDB (struct Tmt_Timetable *Timetable, long UsrCod) { + extern const char *Tmt_DB_ClassType[Tmt_NUM_CLASS_TYPES]; extern const char *Txt_Incomplete_timetable_for_lack_of_space; MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -712,168 +673,7 @@ static void Tmt_FillTimeTableFromDB (struct Tmt_Timetable *Timetable, bool Found; /***** Get timetable from database *****/ - switch (Timetable->Type) - { - case Tmt_MY_TIMETABLE: - switch (Gbl.Crs.Grps.WhichGrps) - { - case Grp_MY_GROUPS: - NumRows = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get timetable", - "SELECT tmt_courses.Weekday," // row[0] - "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] - "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] - "tmt_courses.Info," // row[3] - "tmt_courses.ClassType," // row[4] - "tmt_courses.GrpCod," // row[5] - "tmt_courses.CrsCod" // row[6] - " FROM tmt_courses," - "crs_users" - " WHERE crs_users.UsrCod=%ld" - " AND tmt_courses.GrpCod=-1" - " AND tmt_courses.CrsCod=crs_users.CrsCod" - " UNION DISTINCT " - "SELECT tmt_courses.Weekday," // row[0] - "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] - "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] - "tmt_courses.Info," // row[3] - "tmt_courses.ClassType," // row[4] - "tmt_courses.GrpCod," // row[5] - "tmt_courses.CrsCod" // row[6] - " FROM grp_users," - "tmt_courses" - " WHERE grp_users.UsrCod=%ld" - " AND grp_users.GrpCod=tmt_courses.GrpCod" - " UNION " - "SELECT Weekday," // row[0] - "TIME_TO_SEC(StartTime) AS S," // row[1] - "TIME_TO_SEC(Duration) AS D," // row[2] - "Info," // row[3] - "'tutoring' AS ClassType," // row[4] - "-1 AS GrpCod," // row[5] - "-1 AS CrsCod" // row[6] - " FROM tmt_tutoring" - " WHERE UsrCod=%ld" - " ORDER BY Weekday," - "S," - "ClassType," - "GrpCod," - "Info," - "D DESC," - "CrsCod", - UsrCod, - UsrCod, - UsrCod); - break; - case Grp_ALL_GROUPS: - NumRows = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get timetable", - "SELECT tmt_courses.Weekday," // row[0] - "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] - "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] - "tmt_courses.Info," // row[3] - "tmt_courses.ClassType," // row[4] - "tmt_courses.GrpCod," // row[5] - "tmt_courses.CrsCod" // row[6] - " FROM tmt_courses," - "crs_users" - " WHERE crs_users.UsrCod=%ld" - " AND tmt_courses.CrsCod=crs_users.CrsCod" - " UNION " - "SELECT Weekday," // row[0] - "TIME_TO_SEC(StartTime) AS S," // row[1] - "TIME_TO_SEC(Duration) AS D," // row[2] - "Info," // row[3] - "'tutoring' AS ClassType," // row[4] - "-1 AS GrpCod," // row[5] - "-1 AS CrsCod" // row[6] - " FROM tmt_tutoring" - " WHERE UsrCod=%ld" - " ORDER BY Weekday," - "S," - "ClassType," - "GrpCod," - "Info," - "D DESC," - "CrsCod", - UsrCod, - UsrCod); - break; - } - break; - case Tmt_COURSE_TIMETABLE: - if (Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS || - Gbl.Action.Act == ActEdiCrsTT || - Gbl.Action.Act == ActChgCrsTT) // If we are editing, all groups are shown - NumRows = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get timetable", - "SELECT Weekday," // row[0] - "TIME_TO_SEC(StartTime) AS S," // row[1] - "TIME_TO_SEC(Duration) AS D," // row[2] - "Info," // row[3] - "ClassType," // row[4] - "GrpCod" // row[5] - " FROM tmt_courses" - " WHERE CrsCod=%ld" - " ORDER BY Weekday," - "S," - "ClassType," - "GrpCod," - "Info," - "D DESC", - Gbl.Hierarchy.Crs.CrsCod); - else - NumRows = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get timetable", - "SELECT tmt_courses.Weekday," // row[0] - "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] - "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] - "tmt_courses.Info," // row[3] - "tmt_courses.ClassType," // row[4] - "tmt_courses.GrpCod" // row[5] - " FROM tmt_courses," - "crs_users" - " WHERE tmt_courses.CrsCod=%ld" - " AND tmt_courses.GrpCod=-1" - " AND crs_users.UsrCod=%ld" - " AND tmt_courses.CrsCod=crs_users.CrsCod" - " UNION DISTINCT " - "SELECT tmt_courses.Weekday," // row[0] - "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] - "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] - "tmt_courses.Info," // row[3] - "tmt_courses.ClassType," // row[4] - "tmt_courses.GrpCod" // row[5] - " FROM tmt_courses," - "grp_users" - " WHERE tmt_courses.CrsCod=%ld" - " AND grp_users.UsrCod=%ld" - " AND tmt_courses.GrpCod=grp_users.GrpCod" - " ORDER BY Weekday," - "S," - "ClassType," - "GrpCod," - "Info," - "D DESC", - Gbl.Hierarchy.Crs.CrsCod,UsrCod, - Gbl.Hierarchy.Crs.CrsCod,UsrCod); - break; - case Tmt_TUTORING_TIMETABLE: - NumRows = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get timetable", - "SELECT Weekday," // row[0] - "TIME_TO_SEC(StartTime) AS S," // row[1] - "TIME_TO_SEC(Duration) AS D," // row[2] - "Info" // row[3] - " FROM tmt_tutoring" - " WHERE UsrCod=%ld" - " ORDER BY Weekday," - "S," - "Info," - "D DESC", - UsrCod); - break; - } + NumRows = Tmt_DB_GetTimeTable (&mysql_res,Timetable->Type,UsrCod); /***** If viewing (not editing) ==> calculate range of hours and resolution *****/ @@ -976,10 +776,10 @@ static void Tmt_FillTimeTableFromDB (struct Tmt_Timetable *Timetable, { case Tmt_COURSE_TIMETABLE: case Tmt_MY_TIMETABLE: - for (ClassType = Tmt_LECTURE, Found = false; + for (ClassType = Tmt_LECTURE, Found = false; ClassType <= Tmt_TUTORING; ClassType++) - if (!strcmp (row[4],Tmt_ClassTypeDB[ClassType])) + if (!strcmp (row[4],Tmt_DB_ClassType[ClassType])) { Found = true; break; @@ -1196,140 +996,140 @@ static void Tmt_DrawTimeTable (const struct Tmt_Timetable *Timetable) /***** Begin table *****/ HTM_TABLE_Begin ("TT"); - /***** Top row used for column adjustement *****/ - Tmt_TimeTableDrawAdjustRow (); + /***** Top row used for column adjustement *****/ + Tmt_TimeTableDrawAdjustRow (); - /***** Row with day names *****/ - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("rowspan=\"2\" class=\"Tmt_HOUR_BIG RM\" style=\"width:%u%%;\"", - Tmt_PERCENT_WIDTH_OF_AN_HOUR_COLUMN); - HTM_TxtF ("%02u:00",Timetable->Config.Range.Hours.Start); - HTM_TD_End (); - - Tmt_DrawCellAlignTimeTable (); - Tmt_TimeTableDrawDaysCells (); - Tmt_DrawCellAlignTimeTable (); - - HTM_TD_Begin ("rowspan=\"2\" class=\"Tmt_HOUR_BIG LM\" style=\"width:%u%%;\"", - Tmt_PERCENT_WIDTH_OF_AN_HOUR_COLUMN); - HTM_TxtF ("%02u:00",Timetable->Config.Range.Hours.Start); - HTM_TD_End (); - - HTM_TR_End (); - - /***** Get list of groups types and groups in this course *****/ - if (Gbl.Action.Act == ActEdiCrsTT || - Gbl.Action.Act == ActChgCrsTT) - Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS); - - /***** Write the table row by row *****/ - for (Interval = 0, Min = Timetable->Config.Range.MinutesPerInterval; - Interval < Timetable->Config.IntervalsPerDay; - Interval++, - Min = (Min + Timetable->Config.Range.MinutesPerInterval) % - Tmt_SECONDS_PER_MINUTE) - { + /***** Row with day names *****/ HTM_TR_Begin (NULL); - /* Left hour:minutes cell */ - if (Interval % 2) - Tmt_TimeTableDrawHourCell (Timetable->Config.Range.Hours.Start + - (Interval + 2) / Timetable->Config.IntervalsPerHour, - Min, - "RM"); + HTM_TD_Begin ("rowspan=\"2\" class=\"Tmt_HOUR_BIG RM\" style=\"width:%u%%;\"", + Tmt_PERCENT_WIDTH_OF_AN_HOUR_COLUMN); + HTM_TxtF ("%02u:00",Timetable->Config.Range.Hours.Start); + HTM_TD_End (); - /* Empty column used to adjust height */ - Tmt_DrawCellAlignTimeTable (); + Tmt_DrawCellAlignTimeTable (); + Tmt_TimeTableDrawDaysCells (); + Tmt_DrawCellAlignTimeTable (); - /* Row for this hour */ - for (DayColumn = 0; - DayColumn < Tmt_DAYS_PER_WEEK; - DayColumn++) - { - /* Weekday == 0 ==> monday, - ... - Weekday == 6 ==> sunday */ - Weekday = (DayColumn + Gbl.Prefs.FirstDayOfWeek) % 7; - - /* Check how many colums are needed. - For each item (class) in this hour from left to right, - we must check the maximum of columns */ - ColumnsToDraw = Tmt_CalculateColsToDrawInCell (Timetable, - true, // Top call, non recursive - Weekday,Interval); - if (ColumnsToDraw == 0 && - (Timetable->View == Tmt_CRS_VIEW || - Timetable->View == Tmt_TUT_VIEW)) - ColumnsToDraw = 1; - // If editing and there's place for more columns, - // a potential new column is added at the end of each day - ColumnsToDrawIncludingExtraColumn = ColumnsToDraw; - if (ColumnsToDraw < Tmt_MAX_COLUMNS_PER_CELL && - (Timetable->View == Tmt_CRS_EDIT || - Timetable->View == Tmt_TUT_EDIT)) - ColumnsToDrawIncludingExtraColumn++; - - /* Draw cells */ - for (Column = 0, ContinuousFreeMinicolumns = 0; - Column < ColumnsToDrawIncludingExtraColumn; - Column++) - if (Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType == Tmt_FREE_INTERVAL) - ContinuousFreeMinicolumns += Tmt_NUM_MINICOLUMNS_PER_DAY / - ColumnsToDrawIncludingExtraColumn; - else - { - if (ContinuousFreeMinicolumns) - { - Tmt_TimeTableDrawCell (Timetable, - Weekday,Interval,Column - 1,ContinuousFreeMinicolumns, - -1L,Tmt_FREE_INTERVAL,Tmt_FREE,0,-1L,NULL); - ContinuousFreeMinicolumns = 0; - } - Tmt_TimeTableDrawCell (Timetable, - Weekday,Interval,Column, - Tmt_NUM_MINICOLUMNS_PER_DAY / - ColumnsToDrawIncludingExtraColumn, - Tmt_TimeTable[Weekday][Interval].Columns[Column].CrsCod, - Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType, - Tmt_TimeTable[Weekday][Interval].Columns[Column].ClassType, - Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals, - Tmt_TimeTable[Weekday][Interval].Columns[Column].GrpCod, - Tmt_TimeTable[Weekday][Interval].Columns[Column].Info); - } - if (ContinuousFreeMinicolumns) - Tmt_TimeTableDrawCell (Timetable, - Weekday,Interval,Column - 1,ContinuousFreeMinicolumns, - -1L,Tmt_FREE_INTERVAL,Tmt_FREE,0,-1L,NULL); - } - - /* Empty column used to adjust height */ - Tmt_DrawCellAlignTimeTable (); - - /* Right hour:minutes cell */ - if (Interval % 2) - Tmt_TimeTableDrawHourCell (Timetable->Config.Range.Hours.Start + - (Interval + 2) / Timetable->Config.IntervalsPerHour, - Min, - "LM"); + HTM_TD_Begin ("rowspan=\"2\" class=\"Tmt_HOUR_BIG LM\" style=\"width:%u%%;\"", + Tmt_PERCENT_WIDTH_OF_AN_HOUR_COLUMN); + HTM_TxtF ("%02u:00",Timetable->Config.Range.Hours.Start); + HTM_TD_End (); HTM_TR_End (); - } - /***** Free list of groups types and groups in this course *****/ - if (Gbl.Action.Act == ActEdiCrsTT || - Gbl.Action.Act == ActChgCrsTT) - Grp_FreeListGrpTypesAndGrps (); + /***** Get list of groups types and groups in this course *****/ + if (Gbl.Action.Act == ActEdiCrsTT || + Gbl.Action.Act == ActChgCrsTT) + Grp_GetListGrpTypesAndGrpsInThisCrs (Grp_ONLY_GROUP_TYPES_WITH_GROUPS); - /***** Row with day names *****/ - HTM_TR_Begin (NULL); - Tmt_DrawCellAlignTimeTable (); - Tmt_TimeTableDrawDaysCells (); - Tmt_DrawCellAlignTimeTable (); - HTM_TR_End (); + /***** Write the table row by row *****/ + for (Interval = 0, Min = Timetable->Config.Range.MinutesPerInterval; + Interval < Timetable->Config.IntervalsPerDay; + Interval++, + Min = (Min + Timetable->Config.Range.MinutesPerInterval) % + Tmt_SECONDS_PER_MINUTE) + { + HTM_TR_Begin (NULL); - /***** Bottom row used for column adjustement *****/ - Tmt_TimeTableDrawAdjustRow (); + /* Left hour:minutes cell */ + if (Interval % 2) + Tmt_TimeTableDrawHourCell (Timetable->Config.Range.Hours.Start + + (Interval + 2) / Timetable->Config.IntervalsPerHour, + Min, + "RM"); + + /* Empty column used to adjust height */ + Tmt_DrawCellAlignTimeTable (); + + /* Row for this hour */ + for (DayColumn = 0; + DayColumn < Tmt_DAYS_PER_WEEK; + DayColumn++) + { + /* Weekday == 0 ==> monday, + ... + Weekday == 6 ==> sunday */ + Weekday = (DayColumn + Gbl.Prefs.FirstDayOfWeek) % 7; + + /* Check how many colums are needed. + For each item (class) in this hour from left to right, + we must check the maximum of columns */ + ColumnsToDraw = Tmt_CalculateColsToDrawInCell (Timetable, + true, // Top call, non recursive + Weekday,Interval); + if (ColumnsToDraw == 0 && + (Timetable->View == Tmt_CRS_VIEW || + Timetable->View == Tmt_TUT_VIEW)) + ColumnsToDraw = 1; + // If editing and there's place for more columns, + // a potential new column is added at the end of each day + ColumnsToDrawIncludingExtraColumn = ColumnsToDraw; + if (ColumnsToDraw < Tmt_MAX_COLUMNS_PER_CELL && + (Timetable->View == Tmt_CRS_EDIT || + Timetable->View == Tmt_TUT_EDIT)) + ColumnsToDrawIncludingExtraColumn++; + + /* Draw cells */ + for (Column = 0, ContinuousFreeMinicolumns = 0; + Column < ColumnsToDrawIncludingExtraColumn; + Column++) + if (Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType == Tmt_FREE_INTERVAL) + ContinuousFreeMinicolumns += Tmt_NUM_MINICOLUMNS_PER_DAY / + ColumnsToDrawIncludingExtraColumn; + else + { + if (ContinuousFreeMinicolumns) + { + Tmt_TimeTableDrawCell (Timetable, + Weekday,Interval,Column - 1,ContinuousFreeMinicolumns, + -1L,Tmt_FREE_INTERVAL,Tmt_FREE,0,-1L,NULL); + ContinuousFreeMinicolumns = 0; + } + Tmt_TimeTableDrawCell (Timetable, + Weekday,Interval,Column, + Tmt_NUM_MINICOLUMNS_PER_DAY / + ColumnsToDrawIncludingExtraColumn, + Tmt_TimeTable[Weekday][Interval].Columns[Column].CrsCod, + Tmt_TimeTable[Weekday][Interval].Columns[Column].IntervalType, + Tmt_TimeTable[Weekday][Interval].Columns[Column].ClassType, + Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals, + Tmt_TimeTable[Weekday][Interval].Columns[Column].GrpCod, + Tmt_TimeTable[Weekday][Interval].Columns[Column].Info); + } + if (ContinuousFreeMinicolumns) + Tmt_TimeTableDrawCell (Timetable, + Weekday,Interval,Column - 1,ContinuousFreeMinicolumns, + -1L,Tmt_FREE_INTERVAL,Tmt_FREE,0,-1L,NULL); + } + + /* Empty column used to adjust height */ + Tmt_DrawCellAlignTimeTable (); + + /* Right hour:minutes cell */ + if (Interval % 2) + Tmt_TimeTableDrawHourCell (Timetable->Config.Range.Hours.Start + + (Interval + 2) / Timetable->Config.IntervalsPerHour, + Min, + "LM"); + + HTM_TR_End (); + } + + /***** Free list of groups types and groups in this course *****/ + if (Gbl.Action.Act == ActEdiCrsTT || + Gbl.Action.Act == ActChgCrsTT) + Grp_FreeListGrpTypesAndGrps (); + + /***** Row with day names *****/ + HTM_TR_Begin (NULL); + Tmt_DrawCellAlignTimeTable (); + Tmt_TimeTableDrawDaysCells (); + Tmt_DrawCellAlignTimeTable (); + HTM_TR_End (); + + /***** Bottom row used for column adjustement *****/ + Tmt_TimeTableDrawAdjustRow (); /***** End table *****/ HTM_TABLE_End (); @@ -1346,24 +1146,24 @@ static void Tmt_TimeTableDrawAdjustRow (void) HTM_TR_Begin (NULL); - HTM_TD_Begin ("class=\"Tmt_HOURCOL\""); - HTM_TD_End (); + HTM_TD_Begin ("class=\"Tmt_HOURCOL\""); + HTM_TD_End (); - Tmt_DrawCellAlignTimeTable (); - for (Weekday = 0; - Weekday < Tmt_DAYS_PER_WEEK; - Weekday++) - for (Minicolumn = 0; - Minicolumn < Tmt_NUM_MINICOLUMNS_PER_DAY; - Minicolumn++) - { - HTM_TD_Begin ("class=\"Tmt_MINICOL\""); - HTM_TD_End (); - } - Tmt_DrawCellAlignTimeTable (); + Tmt_DrawCellAlignTimeTable (); + for (Weekday = 0; + Weekday < Tmt_DAYS_PER_WEEK; + Weekday++) + for (Minicolumn = 0; + Minicolumn < Tmt_NUM_MINICOLUMNS_PER_DAY; + Minicolumn++) + { + HTM_TD_Begin ("class=\"Tmt_MINICOL\""); + HTM_TD_End (); + } + Tmt_DrawCellAlignTimeTable (); - HTM_TD_Begin ("class=\"Tmt_HOURCOL\""); - HTM_TD_End (); + HTM_TD_Begin ("class=\"Tmt_HOURCOL\""); + HTM_TD_End (); HTM_TR_End (); } @@ -1388,7 +1188,7 @@ static void Tmt_TimeTableDrawDaysCells (void) Weekday == 6 ? "Tmt_SUNDAY" : // Sunday drawn in red "Tmt_DAY", // Monday to Saturday Tmt_PERCENT_WIDTH_OF_A_DAY); - HTM_Txt (Txt_DAYS_CAPS[Weekday]); + HTM_Txt (Txt_DAYS_CAPS[Weekday]); HTM_TD_End (); } } @@ -1403,7 +1203,7 @@ static void Tmt_TimeTableDrawHourCell (unsigned Hour,unsigned Min,const char *Al Min ? "Tmt_HOUR_SMALL" : "Tmt_HOUR_BIG", Align); - HTM_TxtF ("%02u:%02u",Hour,Min); + HTM_TxtF ("%02u:%02u",Hour,Min); HTM_TD_End (); } @@ -1505,6 +1305,7 @@ static void Tmt_TimeTableDrawCell (const struct Tmt_Timetable *Timetable, long CrsCod,Tmt_IntervalType_t IntervalType,Tmt_ClassType_t ClassType, unsigned DurationNumIntervals,long GrpCod,const char *Info) { + extern const char *Tmt_DB_ClassType[Tmt_NUM_CLASS_TYPES]; extern const char *Txt_unknown_removed_course; extern const char *Txt_TIMETABLE_CLASS_TYPES[Tmt_NUM_CLASS_TYPES]; extern const char *Txt_Group; @@ -1604,251 +1405,222 @@ static void Tmt_TimeTableDrawCell (const struct Tmt_Timetable *Timetable, free (ColSpanStr); free (ClassStr); - /***** Form to modify this cell *****/ - if (Timetable->View == Tmt_CRS_EDIT) - Frm_BeginForm (ActChgCrsTT); - else if (Timetable->View == Tmt_TUT_EDIT) - Frm_BeginForm (ActChgTut); + /***** Form to modify this cell *****/ + if (Timetable->View == Tmt_CRS_EDIT) + Frm_BeginForm (ActChgCrsTT); + else if (Timetable->View == Tmt_TUT_EDIT) + Frm_BeginForm (ActChgTut); - /***** Draw cell depending on type of view *****/ - switch (Timetable->View) - { - case Tmt_CRS_VIEW: // View course timetable - case Tmt_TUT_VIEW: // View tutoring timetable - if (IntervalType != Tmt_FREE_INTERVAL) // If cell is not empty... - { - /***** Begin cell *****/ - HTM_DIV_Begin ("class=\"Tmt_CELL Tmt_TXT\""); - - /***** Course name *****/ - if (Timetable->Type == Tmt_MY_TIMETABLE) - { - Crs.CrsCod = CrsCod; - Crs_GetDataOfCourseByCod (&Crs); - if (ClassType == Tmt_LECTURE || - ClassType == Tmt_PRACTICAL) - { - HTM_Txt (Crs.ShrtName[0] ? Crs.ShrtName : - Txt_unknown_removed_course); - HTM_BR (); - } - } - - /***** Type of class and duration *****/ - HTM_TxtF ("%s (%u:%02u)", - Txt_TIMETABLE_CLASS_TYPES[ClassType], - (DurationNumIntervals / Timetable->Config.IntervalsPerHour), // Hours - (DurationNumIntervals % Timetable->Config.IntervalsPerHour) * - Timetable->Config.Range.MinutesPerInterval); // Minutes - - /***** Group *****/ - if (Timetable->View == Tmt_CRS_VIEW && - GrpCod > 0) + /***** Draw cell depending on type of view *****/ + switch (Timetable->View) + { + case Tmt_CRS_VIEW: // View course timetable + case Tmt_TUT_VIEW: // View tutoring timetable + if (IntervalType != Tmt_FREE_INTERVAL) // If cell is not empty... { - HTM_BR (); - HTM_Txt (GrpDat.GrpTypName); - HTM_BR (); - HTM_Txt (GrpDat.GrpName); - if (GrpDat.Room.RooCod > 0) - { - HTM_BR (); - HTM_TxtF ("(%s)",GrpDat.Room.ShrtName); - } + /***** Begin cell *****/ + HTM_DIV_Begin ("class=\"Tmt_CELL Tmt_TXT\""); + + /***** Course name *****/ + if (Timetable->Type == Tmt_MY_TIMETABLE) + { + Crs.CrsCod = CrsCod; + Crs_GetDataOfCourseByCod (&Crs); + if (ClassType == Tmt_LECTURE || + ClassType == Tmt_PRACTICAL) + { + HTM_Txt (Crs.ShrtName[0] ? Crs.ShrtName : + Txt_unknown_removed_course); + HTM_BR (); + } + } + + /***** Type of class and duration *****/ + HTM_TxtF ("%s (%u:%02u)", + Txt_TIMETABLE_CLASS_TYPES[ClassType], + (DurationNumIntervals / Timetable->Config.IntervalsPerHour), // Hours + (DurationNumIntervals % Timetable->Config.IntervalsPerHour) * + Timetable->Config.Range.MinutesPerInterval); // Minutes + + /***** Group *****/ + if (Timetable->View == Tmt_CRS_VIEW && + GrpCod > 0) + { + HTM_BR (); + HTM_Txt (GrpDat.GrpTypName); + HTM_BR (); + HTM_Txt (GrpDat.GrpName); + if (GrpDat.Room.RooCod > 0) + { + HTM_BR (); + HTM_TxtF ("(%s)",GrpDat.Room.ShrtName); + } + } + + /***** Info *****/ + if (Info) + if (Info[0]) + { + HTM_BR (); + HTM_Txt (Info); + } + + /***** End cell *****/ + HTM_DIV_End (); } - - /***** Info *****/ - if (Info) - if (Info[0]) - { - HTM_BR (); - HTM_Txt (Info); - } - - /***** End cell *****/ - HTM_DIV_End (); - } - break; - case Tmt_CRS_EDIT: - case Tmt_TUT_EDIT: - /***** Create unique string for this cell used in labels *****/ - if (asprintf (&CellStr,"%02u%02u%02u", - Weekday,Interval,Column) < 0) - Err_NotEnoughMemoryExit (); - - /***** Put hidden parameters *****/ - Par_PutHiddenParamUnsigned (NULL,"TTDay",Weekday); - Par_PutHiddenParamUnsigned (NULL,"TTInt",Interval); - Par_PutHiddenParamUnsigned (NULL,"TTCol",Column); - - /***** Class type *****/ - HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE, - "name=\"TTTyp\" class=\"Tmt_TYP\""); - for (CT = (Tmt_ClassType_t) 0; - CT <= (Tmt_ClassType_t) (Tmt_NUM_CLASS_TYPES - 1); - CT++) - if ((CT == Tmt_FREE) || - ((Timetable->View == Tmt_CRS_EDIT) && (CT == Tmt_LECTURE || CT == Tmt_PRACTICAL)) || - ((Timetable->View == Tmt_TUT_EDIT) && (CT == Tmt_TUTORING))) - HTM_OPTION (HTM_Type_STRING,Tmt_ClassTypeDB[CT], - CT == ClassType,false, - "%s",Txt_TIMETABLE_CLASS_TYPES[CT]); - HTM_SELECT_End (); - - if (IntervalType == Tmt_FREE_INTERVAL) - { - for (i = Interval + 1; - i < Timetable->Config.IntervalsPerDay; - i++) - if (Tmt_TimeTable[Weekday][i].NumColumns == Tmt_MAX_COLUMNS_PER_CELL) - break; - MaxDuration = i - Interval; - Dur = (MaxDuration >= Timetable->Config.IntervalsPerHour) ? Timetable->Config.IntervalsPerHour : // MaxDuration >= 1h ==> Dur = 1h - MaxDuration; // MaxDuration < 1h ==> Dur = MaxDuration - if (asprintf (&TTDur,"%u:%02u", - (Dur / Timetable->Config.IntervalsPerHour), // Hours - (Dur % Timetable->Config.IntervalsPerHour) * - Timetable->Config.Range.MinutesPerInterval) < 0) // Minutes + break; + case Tmt_CRS_EDIT: + case Tmt_TUT_EDIT: + /***** Create unique string for this cell used in labels *****/ + if (asprintf (&CellStr,"%02u%02u%02u", + Weekday,Interval,Column) < 0) Err_NotEnoughMemoryExit (); - Par_PutHiddenParamString (NULL,"TTDur",TTDur); - free (TTDur); - } - else - { - /***** Class duration *****/ + + /***** Put hidden parameters *****/ + Par_PutHiddenParamUnsigned (NULL,"TTDay",Weekday); + Par_PutHiddenParamUnsigned (NULL,"TTInt",Interval); + Par_PutHiddenParamUnsigned (NULL,"TTCol",Column); + + /***** Class type *****/ HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE, - "name=\"TTDur\" class=\"Tmt_DUR\""); - for (i = Interval + Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals; - i < Timetable->Config.IntervalsPerDay; - i++) - if (Tmt_TimeTable[Weekday][i].NumColumns == Tmt_MAX_COLUMNS_PER_CELL) - break; - MaxDuration = i - Interval; - if (Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals > MaxDuration) - MaxDuration = Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals; - for (Dur = 0; - Dur <= MaxDuration; - Dur++) + "name=\"TTTyp\" class=\"Tmt_TYP\""); + for (CT = (Tmt_ClassType_t) 0; + CT <= (Tmt_ClassType_t) (Tmt_NUM_CLASS_TYPES - 1); + CT++) + if ((CT == Tmt_FREE) || + ((Timetable->View == Tmt_CRS_EDIT) && (CT == Tmt_LECTURE || CT == Tmt_PRACTICAL)) || + ((Timetable->View == Tmt_TUT_EDIT) && (CT == Tmt_TUTORING))) + HTM_OPTION (HTM_Type_STRING,Tmt_DB_ClassType[CT], + CT == ClassType,false, + "%s",Txt_TIMETABLE_CLASS_TYPES[CT]); + HTM_SELECT_End (); + + if (IntervalType == Tmt_FREE_INTERVAL) { + for (i = Interval + 1; + i < Timetable->Config.IntervalsPerDay; + i++) + if (Tmt_TimeTable[Weekday][i].NumColumns == Tmt_MAX_COLUMNS_PER_CELL) + break; + MaxDuration = i - Interval; + Dur = (MaxDuration >= Timetable->Config.IntervalsPerHour) ? Timetable->Config.IntervalsPerHour : // MaxDuration >= 1h ==> Dur = 1h + MaxDuration; // MaxDuration < 1h ==> Dur = MaxDuration if (asprintf (&TTDur,"%u:%02u", - (Dur / Timetable->Config.IntervalsPerHour), // Hours + (Dur / Timetable->Config.IntervalsPerHour), // Hours (Dur % Timetable->Config.IntervalsPerHour) * Timetable->Config.Range.MinutesPerInterval) < 0) // Minutes Err_NotEnoughMemoryExit (); - HTM_OPTION (HTM_Type_STRING,TTDur, - Dur == DurationNumIntervals,false, - "%s",TTDur); + Par_PutHiddenParamString (NULL,"TTDur",TTDur); free (TTDur); } - HTM_SELECT_End (); - - if (Timetable->View == Tmt_CRS_EDIT) + else { - /***** Group *****/ - HTM_BR (); - HTM_LABEL_Begin ("for=\"TTGrp%s\"",CellStr); - HTM_Txt (Txt_Group); - HTM_LABEL_End (); + /***** Class duration *****/ HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE, - "id=\"TTGrp%s\" name=\"TTGrp\"" - " class=\"Tmt_GRP\"", - CellStr); - HTM_OPTION (HTM_Type_STRING,"-1",GrpCod <= 0,false, - "%s",Txt_All_groups); - for (NumGrpTyp = 0; - NumGrpTyp < Gbl.Crs.Grps.GrpTypes.NumGrpTypes; - NumGrpTyp++) - { - GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp]; - - for (NumGrp = 0; - NumGrp < GrpTyp->NumGrps; - NumGrp++) - { - Grp = &GrpTyp->LstGrps[NumGrp]; - if (Grp->Room.RooCod > 0) - { - if (asprintf (&Room," (%s)",Grp->Room.ShrtName) < 0) - Err_NotEnoughMemoryExit (); - } - else - { - if (asprintf (&Room,"%s","") < 0) - Err_NotEnoughMemoryExit (); - } - HTM_OPTION (HTM_Type_LONG,&Grp->GrpCod, - GrpCod == Grp->GrpCod,false, - "%s %s%s", - GrpTyp->GrpTypName,Grp->GrpName,Room); - free (Room); - } - } + "name=\"TTDur\" class=\"Tmt_DUR\""); + for (i = Interval + Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals; + i < Timetable->Config.IntervalsPerDay; + i++) + if (Tmt_TimeTable[Weekday][i].NumColumns == Tmt_MAX_COLUMNS_PER_CELL) + break; + MaxDuration = i - Interval; + if (Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals > MaxDuration) + MaxDuration = Tmt_TimeTable[Weekday][Interval].Columns[Column].DurationIntervals; + for (Dur = 0; + Dur <= MaxDuration; + Dur++) + { + if (asprintf (&TTDur,"%u:%02u", + (Dur / Timetable->Config.IntervalsPerHour), // Hours + (Dur % Timetable->Config.IntervalsPerHour) * + Timetable->Config.Range.MinutesPerInterval) < 0) // Minutes + Err_NotEnoughMemoryExit (); + HTM_OPTION (HTM_Type_STRING,TTDur, + Dur == DurationNumIntervals,false, + "%s",TTDur); + free (TTDur); + } HTM_SELECT_End (); - /***** Info *****/ - HTM_BR (); - HTM_LABEL_Begin ("for=\"TTInf%s\"",CellStr); - HTM_Txt (Txt_Info); - HTM_LABEL_End (); - HTM_INPUT_TEXT ("TTInf",Tmt_MAX_CHARS_INFO,Info ? Info : - "", - HTM_SUBMIT_ON_CHANGE, - "id=\"TTInf%s\" size=\"1\" class=\"Tmt_INF\"", - CellStr); + if (Timetable->View == Tmt_CRS_EDIT) + { + /***** Group *****/ + HTM_BR (); + HTM_LABEL_Begin ("for=\"TTGrp%s\"",CellStr); + HTM_Txt (Txt_Group); + HTM_LABEL_End (); + HTM_SELECT_Begin (HTM_SUBMIT_ON_CHANGE, + "id=\"TTGrp%s\" name=\"TTGrp\"" + " class=\"Tmt_GRP\"", + CellStr); + HTM_OPTION (HTM_Type_STRING,"-1",GrpCod <= 0,false, + "%s",Txt_All_groups); + for (NumGrpTyp = 0; + NumGrpTyp < Gbl.Crs.Grps.GrpTypes.NumGrpTypes; + NumGrpTyp++) + { + GrpTyp = &Gbl.Crs.Grps.GrpTypes.LstGrpTypes[NumGrpTyp]; + + for (NumGrp = 0; + NumGrp < GrpTyp->NumGrps; + NumGrp++) + { + Grp = &GrpTyp->LstGrps[NumGrp]; + if (Grp->Room.RooCod > 0) + { + if (asprintf (&Room," (%s)",Grp->Room.ShrtName) < 0) + Err_NotEnoughMemoryExit (); + } + else + { + if (asprintf (&Room,"%s","") < 0) + Err_NotEnoughMemoryExit (); + } + HTM_OPTION (HTM_Type_LONG,&Grp->GrpCod, + GrpCod == Grp->GrpCod,false, + "%s %s%s", + GrpTyp->GrpTypName,Grp->GrpName,Room); + free (Room); + } + } + HTM_SELECT_End (); + + /***** Info *****/ + HTM_BR (); + HTM_LABEL_Begin ("for=\"TTInf%s\"",CellStr); + HTM_Txt (Txt_Info); + HTM_LABEL_End (); + HTM_INPUT_TEXT ("TTInf",Tmt_MAX_CHARS_INFO,Info ? Info : + "", + HTM_SUBMIT_ON_CHANGE, + "id=\"TTInf%s\" size=\"1\" class=\"Tmt_INF\"", + CellStr); + } + else // TimeTableView == Tmt_TUT_EDIT + { + /***** Info *****/ + HTM_BR (); + HTM_LABEL_Begin ("for=\"TTInf%s\" class=\"DAT_SMALL\"",CellStr); + HTM_Txt (Txt_Info); + HTM_LABEL_End (); + HTM_INPUT_TEXT ("TTInf",Tmt_MAX_CHARS_INFO,Info, + HTM_SUBMIT_ON_CHANGE, + "id=\"TTInf%s\" size=\"12\" class=\"Tmt_INF\"", + CellStr); + } } - else // TimeTableView == Tmt_TUT_EDIT - { - /***** Info *****/ - HTM_BR (); - HTM_LABEL_Begin ("for=\"TTInf%s\" class=\"DAT_SMALL\"",CellStr); - HTM_Txt (Txt_Info); - HTM_LABEL_End (); - HTM_INPUT_TEXT ("TTInf",Tmt_MAX_CHARS_INFO,Info, - HTM_SUBMIT_ON_CHANGE, - "id=\"TTInf%s\" size=\"12\" class=\"Tmt_INF\"", - CellStr); - } - } - /***** Free allocated unique string for this cell used in labels *****/ - free (CellStr); + /***** Free allocated unique string for this cell used in labels *****/ + free (CellStr); - break; - } + break; + } - /***** End form *****/ - if (Timetable->View == Tmt_CRS_EDIT || - Timetable->View == Tmt_TUT_EDIT) - Frm_EndForm (); + /***** End form *****/ + if (Timetable->View == Tmt_CRS_EDIT || + Timetable->View == Tmt_TUT_EDIT) + Frm_EndForm (); /***** End cell *****/ HTM_TD_End (); } - -/*****************************************************************************/ -/********** Orphan all groups of a given type in course timetable ************/ -/*****************************************************************************/ - -void Tmt_DB_OrphanAllGrpsOfATypeInCrsTimeTable (long GrpTypCod) - { - DB_QueryUPDATE ("can not update all groups of a type in course timetable", - "UPDATE tmt_courses" - " SET GrpCod=-1" - " WHERE GrpCod IN" - " (SELECT GrpCod" - " FROM grp_groups" - " WHERE GrpTypCod=%ld)", - GrpTypCod); - } - -/*****************************************************************************/ -/********************* Orphan a group in course timetable ********************/ -/*****************************************************************************/ - -void Tmt_DB_OrphanGrpInCrsTimeTable (long GrpCod) - { - DB_QueryUPDATE ("can not update a group in course timetable", - "UPDATE tmt_courses" - " SET GrpCod=-1" - " WHERE GrpCod=%ld", - GrpCod); - } diff --git a/swad_timetable.h b/swad_timetable.h index a56227be..b3b152f3 100644 --- a/swad_timetable.h +++ b/swad_timetable.h @@ -1,7 +1,7 @@ // swad_timetable.h: timetables -#ifndef _SWAD_TT -#define _SWAD_TT +#ifndef _SWAD_TMT +#define _SWAD_TMT /* SWAD (Shared Workspace At a Distance in Spanish), is a web platform developed at the University of Granada (Spain), @@ -106,6 +106,16 @@ struct Tmt_Timetable } ContextualIcons; }; +struct Tmt_Column + { + long CrsCod; // Course code (-1 if no course selected) + long GrpCod; // Group code (-1 if no group selected) + Tmt_IntervalType_t IntervalType; + Tmt_ClassType_t ClassType; + unsigned DurationIntervals; + char Info[Tmt_MAX_BYTES_INFO + 1]; + }; + /*****************************************************************************/ /****************************** Public prototypes ****************************/ /*****************************************************************************/ @@ -115,7 +125,4 @@ void Tmt_EditCrsTimeTable (void); void Tmt_EditMyTutTimeTable (void); void Tmt_ShowTimeTable (struct Tmt_Timetable *Timetable,long UsrCod); -void Tmt_DB_OrphanAllGrpsOfATypeInCrsTimeTable (long GrpTypCod); -void Tmt_DB_OrphanGrpInCrsTimeTable (long GrpCod); - #endif diff --git a/swad_timetable_database.c b/swad_timetable_database.c new file mode 100644 index 00000000..c3e342c4 --- /dev/null +++ b/swad_timetable_database.c @@ -0,0 +1,326 @@ +// swad_timetable_database.c: timetables, operations with database + +/* + SWAD (Shared Workspace At a Distance), + is a web platform developed at the University of Granada (Spain), + and used to support university teaching. + + This file is part of SWAD core. + Copyright (C) 1999-2021 Antonio Caņas Vargas + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/*****************************************************************************/ +/*********************************** Headers *********************************/ +/*****************************************************************************/ + +#include "swad_database.h" +#include "swad_global.h" +#include "swad_timetable_database.h" + +/*****************************************************************************/ +/*************************** External constants ******************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/************************** Public constants and types ***********************/ +/*****************************************************************************/ + +const char *Tmt_DB_ClassType[Tmt_NUM_CLASS_TYPES] = + { + [Tmt_FREE ] = "free", + [Tmt_LECTURE ] = "lecture", + [Tmt_PRACTICAL] = "practical", + [Tmt_TUTORING ] = "tutoring", + }; + +/*****************************************************************************/ +/************************** Private global variables *************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ***************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/********************* Insert class in course timetable **********************/ +/*****************************************************************************/ + +void Tmt_DB_InsertHourInCrsTimeTable (long CrsCod, + const struct Tmt_Column *Column, + unsigned Weekday,unsigned Hour,unsigned Min, + unsigned SecondsPerInterval) + { + DB_QueryINSERT ("can not insert hour in course timetable", + "INSERT INTO tmt_courses" + " (CrsCod,GrpCod,Weekday,StartTime,Duration," + "ClassType,Info)" + " VALUES" + " (%ld,%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u)," + "'%s','%s')", + CrsCod, + Column->GrpCod, + Weekday,Hour,Min, + Column->DurationIntervals * SecondsPerInterval, + Tmt_DB_ClassType[Column->ClassType], + Column->Info); + } + +/*****************************************************************************/ +/********************* Insert class in course timetable **********************/ +/*****************************************************************************/ + +void Tmt_DB_InsertHourInUsrTimeTable (long UsrCod, + const struct Tmt_Column *Column, + unsigned Weekday,unsigned Hour,unsigned Min, + unsigned SecondsPerInterval) + { + DB_QueryINSERT ("can not insert hour in user timetable", + "INSERT INTO tmt_tutoring" + " (UsrCod,Weekday,StartTime,Duration,Info)" + " VALUES" + " (%ld,%u,'%02u:%02u:00',SEC_TO_TIME(%u),'%s')", + UsrCod, + Weekday,Hour,Min, + Column->DurationIntervals * SecondsPerInterval, + Column->Info); + } + +/*****************************************************************************/ +/************************ Get timetable from database ************************/ +/*****************************************************************************/ + +unsigned Tmt_DB_GetTimeTable (MYSQL_RES **mysql_res, + Tmt_TimeTableType_t Type,long UsrCod) + { + switch (Type) + { + case Tmt_MY_TIMETABLE: + switch (Gbl.Crs.Grps.WhichGrps) + { + case Grp_MY_GROUPS: + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get timetable", + "SELECT tmt_courses.Weekday," // row[0] + "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] + "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] + "tmt_courses.Info," // row[3] + "tmt_courses.ClassType," // row[4] + "tmt_courses.GrpCod," // row[5] + "tmt_courses.CrsCod" // row[6] + " FROM tmt_courses," + "crs_users" + " WHERE crs_users.UsrCod=%ld" + " AND tmt_courses.GrpCod=-1" + " AND tmt_courses.CrsCod=crs_users.CrsCod" + " UNION DISTINCT " + "SELECT tmt_courses.Weekday," // row[0] + "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] + "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] + "tmt_courses.Info," // row[3] + "tmt_courses.ClassType," // row[4] + "tmt_courses.GrpCod," // row[5] + "tmt_courses.CrsCod" // row[6] + " FROM grp_users," + "tmt_courses" + " WHERE grp_users.UsrCod=%ld" + " AND grp_users.GrpCod=tmt_courses.GrpCod" + " UNION " + "SELECT Weekday," // row[0] + "TIME_TO_SEC(StartTime) AS S," // row[1] + "TIME_TO_SEC(Duration) AS D," // row[2] + "Info," // row[3] + "'tutoring' AS ClassType," // row[4] + "-1 AS GrpCod," // row[5] + "-1 AS CrsCod" // row[6] + " FROM tmt_tutoring" + " WHERE UsrCod=%ld" + " ORDER BY Weekday," + "S," + "ClassType," + "GrpCod," + "Info," + "D DESC," + "CrsCod", + UsrCod, + UsrCod, + UsrCod); + case Grp_ALL_GROUPS: + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get timetable", + "SELECT tmt_courses.Weekday," // row[0] + "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] + "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] + "tmt_courses.Info," // row[3] + "tmt_courses.ClassType," // row[4] + "tmt_courses.GrpCod," // row[5] + "tmt_courses.CrsCod" // row[6] + " FROM tmt_courses," + "crs_users" + " WHERE crs_users.UsrCod=%ld" + " AND tmt_courses.CrsCod=crs_users.CrsCod" + " UNION " + "SELECT Weekday," // row[0] + "TIME_TO_SEC(StartTime) AS S," // row[1] + "TIME_TO_SEC(Duration) AS D," // row[2] + "Info," // row[3] + "'tutoring' AS ClassType," // row[4] + "-1 AS GrpCod," // row[5] + "-1 AS CrsCod" // row[6] + " FROM tmt_tutoring" + " WHERE UsrCod=%ld" + " ORDER BY Weekday," + "S," + "ClassType," + "GrpCod," + "Info," + "D DESC," + "CrsCod", + UsrCod, + UsrCod); + } + return 0; // Not reached + case Tmt_COURSE_TIMETABLE: + if (Gbl.Crs.Grps.WhichGrps == Grp_ALL_GROUPS || + Gbl.Action.Act == ActEdiCrsTT || + Gbl.Action.Act == ActChgCrsTT) // If we are editing, all groups are shown + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get timetable", + "SELECT Weekday," // row[0] + "TIME_TO_SEC(StartTime) AS S," // row[1] + "TIME_TO_SEC(Duration) AS D," // row[2] + "Info," // row[3] + "ClassType," // row[4] + "GrpCod" // row[5] + " FROM tmt_courses" + " WHERE CrsCod=%ld" + " ORDER BY Weekday," + "S," + "ClassType," + "GrpCod," + "Info," + "D DESC", + Gbl.Hierarchy.Crs.CrsCod); + else + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get timetable", + "SELECT tmt_courses.Weekday," // row[0] + "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] + "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] + "tmt_courses.Info," // row[3] + "tmt_courses.ClassType," // row[4] + "tmt_courses.GrpCod" // row[5] + " FROM tmt_courses," + "crs_users" + " WHERE tmt_courses.CrsCod=%ld" + " AND tmt_courses.GrpCod=-1" + " AND crs_users.UsrCod=%ld" + " AND tmt_courses.CrsCod=crs_users.CrsCod" + " UNION DISTINCT " + "SELECT tmt_courses.Weekday," // row[0] + "TIME_TO_SEC(tmt_courses.StartTime) AS S," // row[1] + "TIME_TO_SEC(tmt_courses.Duration) AS D," // row[2] + "tmt_courses.Info," // row[3] + "tmt_courses.ClassType," // row[4] + "tmt_courses.GrpCod" // row[5] + " FROM tmt_courses," + "grp_users" + " WHERE tmt_courses.CrsCod=%ld" + " AND grp_users.UsrCod=%ld" + " AND tmt_courses.GrpCod=grp_users.GrpCod" + " ORDER BY Weekday," + "S," + "ClassType," + "GrpCod," + "Info," + "D DESC", + Gbl.Hierarchy.Crs.CrsCod,UsrCod, + Gbl.Hierarchy.Crs.CrsCod,UsrCod); + case Tmt_TUTORING_TIMETABLE: + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get timetable", + "SELECT Weekday," // row[0] + "TIME_TO_SEC(StartTime) AS S," // row[1] + "TIME_TO_SEC(Duration) AS D," // row[2] + "Info" // row[3] + " FROM tmt_tutoring" + " WHERE UsrCod=%ld" + " ORDER BY Weekday," + "S," + "Info," + "D DESC", + UsrCod); + default: + return 0; // Not reached + } + } + +/*****************************************************************************/ +/********** Orphan all groups of a given type in course timetable ************/ +/*****************************************************************************/ + +void Tmt_DB_OrphanAllGrpsOfATypeInCrsTimeTable (long GrpTypCod) + { + DB_QueryUPDATE ("can not update all groups of a type in course timetable", + "UPDATE tmt_courses" + " SET GrpCod=-1" + " WHERE GrpCod IN" + " (SELECT GrpCod" + " FROM grp_groups" + " WHERE GrpTypCod=%ld)", + GrpTypCod); + } + +/*****************************************************************************/ +/********************* Orphan a group in course timetable ********************/ +/*****************************************************************************/ + +void Tmt_DB_OrphanGrpInCrsTimeTable (long GrpCod) + { + DB_QueryUPDATE ("can not update a group in course timetable", + "UPDATE tmt_courses" + " SET GrpCod=-1" + " WHERE GrpCod=%ld", + GrpCod); + } + +/*****************************************************************************/ +/*************************** Remove course timetable *************************/ +/*****************************************************************************/ + +void Tmt_DB_RemoveCrsTimeTable (long CrsCod) + { + DB_QueryDELETE ("can not remove timetable", + "DELETE FROM tmt_courses" + " WHERE CrsCod=%ld", + CrsCod); + } + +/*****************************************************************************/ +/**************************** Remove user timetable **************************/ +/*****************************************************************************/ + +void Tmt_DB_RemoveUsrTimeTable (long UsrCod) + { + DB_QueryDELETE ("can not remove former timetable", + "DELETE FROM tmt_tutoring" + " WHERE UsrCod=%ld", + UsrCod); + } diff --git a/swad_timetable_database.h b/swad_timetable_database.h new file mode 100644 index 00000000..e6633e20 --- /dev/null +++ b/swad_timetable_database.h @@ -0,0 +1,60 @@ +// swad_timetable_database.h: timetables, operations with database + +#ifndef _SWAD_TMT_DB +#define _SWAD_TMT_DB +/* + SWAD (Shared Workspace At a Distance in Spanish), + is a web platform developed at the University of Granada (Spain), + and used to support university teaching. + + This file is part of SWAD core. + Copyright (C) 1999-2021 Antonio Caņas Vargas + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/*****************************************************************************/ +/********************************** Headers **********************************/ +/*****************************************************************************/ + +#include // To access MySQL databases + +#include "swad_timetable.h" + +/*****************************************************************************/ +/************************* Public constants and types ************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/****************************** Public prototypes ****************************/ +/*****************************************************************************/ + +void Tmt_DB_InsertHourInCrsTimeTable (long CrsCod, + const struct Tmt_Column *Column, + unsigned Weekday,unsigned Hour,unsigned Min, + unsigned SecondsPerInterval); +void Tmt_DB_InsertHourInUsrTimeTable (long UsrCod, + const struct Tmt_Column *Column, + unsigned Weekday,unsigned Hour,unsigned Min, + unsigned SecondsPerInterval); + +unsigned Tmt_DB_GetTimeTable (MYSQL_RES **mysql_res, + Tmt_TimeTableType_t Type,long UsrCod); + +void Tmt_DB_OrphanAllGrpsOfATypeInCrsTimeTable (long GrpTypCod); +void Tmt_DB_OrphanGrpInCrsTimeTable (long GrpCod); + +void Tmt_DB_RemoveCrsTimeTable (long CrsCod); +void Tmt_DB_RemoveUsrTimeTable (long UsrCod); + +#endif