// swad_layout.c: page layout /* 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-2014 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 // For NULL #include // For exit, system, malloc, calloc, free, etc #include // For string functions #include "swad_action.h" #include "swad_changelog.h" #include "swad_config.h" #include "swad_connected.h" #include "swad_database.h" #include "swad_global.h" #include "swad_notice.h" #include "swad_notification.h" #include "swad_parameter.h" #include "swad_preference.h" #include "swad_theme.h" #include "swad_web_service.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ /*****************************************************************************/ extern struct Globals Gbl; extern struct Act_Actions Act_Actions[Act_NUM_ACTIONS]; /*****************************************************************************/ /****************************** Public constants *****************************/ /*****************************************************************************/ const char *Lay_LayoutIcons[Lay_NUM_LAYOUTS] = { "desktop", "mobile", }; /*****************************************************************************/ /****************************** Private constants ****************************/ /*****************************************************************************/ const char *Lay_TabIcons[Act_NUM_TABS] = { /* TabUnk */ NULL, /* TabSys */ "sys", /* TabCty */ "cty", /* TabIns */ "ins", /* TabCtr */ "ctr", /* TabDeg */ "deg", /* TabCrs */ "crs", /* TabAss */ "ass", /* TabUsr */ "usr", /* TabMsg */ "msg", /* TabSta */ "sta", /* TabPrf */ "prf", }; /*****************************************************************************/ /******************************* Private types *******************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Private prototypes ****************************/ /*****************************************************************************/ static void Lay_WriteEndOfPage (void); static void Lay_WritePageTitle (void); static void Lay_WriteRedirectionToMyLanguage (void); static void Lay_WriteScripts (void); static void Lay_WriteScriptInit (void); static void Lay_WriteScriptConnectedUsrs (void); static void Lay_WriteScriptCustomDropzone (void); static void Lay_WritePageTopHeading (void); static void Lay_DrawTabs (void); static void Lay_DrawTabsDeskTop (void); static void Lay_DrawTabsMobile (void); static bool Lay_CheckIfICanViewTab (Act_Tab_t Tab); static void Lay_DrawBreadcrumb (void); static void Lay_WriteMenuThisTabDesktop (void); static void Lay_WriteMenuThisTabMobile (void); static void Lay_WriteBreadcrumbHome (void); static void Lay_WriteBreadcrumbTab (void); static void Lay_WriteBreadcrumbAction (void); static void Lay_WriteTitleAction (void); static void Lay_ShowLeftColumn (void); static void Lay_ShowRightColumn (void); static void Lay_WriteFootFromHTMLFile (void); /*****************************************************************************/ /*************** Print a SHA512 ciphered text in hexadecimal *****************/ /*****************************************************************************/ /* void Lay_PrintDigest512 (unsigned char digest512[512/8]) { unsigned i; char Borrame[(512/8)*2+1]; for (i=0; i<(512/8); i++) { sprintf (&Borrame[i*2 ],"%01x",digest512[i] >> 4); sprintf (&Borrame[i*2+1],"%01x",digest512[i] & 0x0F); } Lay_ShowAlert (Lay_INFO,Borrame); } */ /*****************************************************************************/ /*********************** Write the start of the page *************************/ /*****************************************************************************/ void Lay_WriteStartOfPage (void) { extern const char *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES]; extern const unsigned Txt_Current_CGI_SWAD_Language; extern const char *The_TabOnBgColors[The_NUM_THEMES]; extern const char *Txt_NEW_YEAR_GREETING; unsigned ColspanCentralPart = 3; // char QueryDebug[1024]; /***** If, when this function is called, the head is being written, or the head is already written ==> ==> don't do anything *****/ if (Gbl.Layout.WritingHTMLStart || Gbl.Layout.HTMLStartWritten) return; // if (Gbl.Usrs.Me.UsrDat.UsrCod == 1346) // { // sprintf (QueryDebug,"INSERT INTO debug (DebugTime,Txt) VALUES (NOW(),'Act_Actions[ActRefLstClk].ActCod = %u --- Act_Actions[Gbl.CurrentAct].ActCod = %u')", // (unsigned) Act_Actions[ActRefLstClk].ActCod,(unsigned) Act_Actions[Gbl.CurrentAct].ActCod); // DB_QueryINSERT (QueryDebug,"Error inserting in debug table"); // } /***** Compute connected users *****/ if (Gbl.CurrentAct == ActLstCon || (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP && (Gbl.Prefs.SideCols & 1) && Gbl.CurrentCrs.Crs.CrsCod >= 0)) // Right column visible && There is a course selected Con_ComputeConnectedUsrsBelongingToCurrentCrs (); /***** Send head width the file type for the HTTP protocol *****/ if (Gbl.CurrentAct == ActRefCon || Gbl.CurrentAct == ActRefLstClk) // Don't generate a full HTML page, only refresh connected users { fprintf (Gbl.F.Out,"Content-Type: text/html; charset=ISO-8859-1\r\n"); fprintf (Gbl.F.Out,"Cache-Control: max-age=0, no-cache, must-revalidate\r\n\r\n"); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true; return; } /***** If serving a web service ==> don't do anything *****/ if (Gbl.WebService.IsWebService) { Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true; return; } Gbl.Layout.WritingHTMLStart = true; /***** Write header to standard output to avoid timeout *****/ // Two \r\n are necessary fprintf (stdout,"Content-type: text/html; charset=ISO-8859-1\r\n\r\n" "\n"); /***** Write start of XHTML code *****/ // It is necessary to comment the line AddDefaultCharset UTF8 in httpd.conf to enable meta tag fprintf (Gbl.F.Out,"\n" "\n" "\n", Txt_STR_LANG_ID[Gbl.Prefs.Language]); /* Title */ Lay_WritePageTitle (); /* Favicon */ fprintf (Gbl.F.Out,"\n" "\n", Gbl.Prefs.IconsURL, Gbl.Prefs.IconsURL); /* Style sheet for SWAD */ fprintf (Gbl.F.Out,"\n", Cfg_HTTPS_URL_SWAD_PUBLIC, (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) ? "swad_desktop.css" : "swad_mobile.css"); /* Style sheet for Dropzone.js (http://www.dropzonejs.com/) */ // The public directory dropzone must hold: // dropzone.js // css/dropzone.css // images/spritemap@2x.png // images/spritemap.png if (Gbl.CurrentAct == ActFrmCreDocCrs || // Brw_FILE_BRW_ADMIN_DOCUMENTS_CRS Gbl.CurrentAct == ActFrmCreDocGrp || // Brw_FILE_BRW_ADMIN_DOCUMENTS_GRP Gbl.CurrentAct == ActFrmCreComCrs || // Brw_FILE_BRW_COMMON_CRS Gbl.CurrentAct == ActFrmCreComGrp || // Brw_FILE_BRW_COMMON_GRP Gbl.CurrentAct == ActFrmCreAsgUsr || // Brw_FILE_BRW_ASSIGNMENTS_USR Gbl.CurrentAct == ActFrmCreAsgCrs || // Brw_FILE_BRW_ASSIGNMENTS_CRS Gbl.CurrentAct == ActFrmCreWrkUsr || // Brw_FILE_BRW_WORKS_USR Gbl.CurrentAct == ActFrmCreWrkCrs || // Brw_FILE_BRW_WORKS_CRS Gbl.CurrentAct == ActFrmCreMrkCrs || // Brw_FILE_BRW_ADMIN_MARKS_CRS Gbl.CurrentAct == ActFrmCreMrkGrp || // Brw_FILE_BRW_ADMIN_MARKS_GRP Gbl.CurrentAct == ActFrmCreBrf) // Brw_FILE_BRW_BRIEFCASE_USR fprintf (Gbl.F.Out,"\n", Cfg_HTTPS_URL_SWAD_PUBLIC); /* Redirect to correct language */ if ((Gbl.CurrentAct == ActAutUsrInt || Gbl.CurrentAct == ActAutUsrExt) && // Action is log in Gbl.Usrs.Me.Logged && // I am just logged Gbl.Usrs.Me.UsrDat.Prefs.Language != Txt_Current_CGI_SWAD_Language) // My language != current language Lay_WriteRedirectionToMyLanguage (); /* Soft transition between pages (avoid white screen) for Microsoft Internet Explorer */ if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW) fprintf (Gbl.F.Out,"\n"); /* Write initial scripts depending on the action */ Lay_WriteScripts (); fprintf (Gbl.F.Out,"\n"); /***** HTML body *****/ fprintf (Gbl.F.Out,"\n"); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = Gbl.Layout.TablEndWritten = true; return; } fprintf (Gbl.F.Out," onload=\"init()\">\n"); if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW) fprintf (Gbl.F.Out,"
" "\"\"
" "
" "
", Gbl.Prefs.IconsURL); /***** Header of layout *****/ fprintf (Gbl.F.Out,""); Lay_WritePageTopHeading (); if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) { if (Gbl.Prefs.SideCols == 3) // 11: both side columns visible, left and right ColspanCentralPart = 1; else if (Gbl.Prefs.SideCols != 0) // 10 or 01: only one side column visible, left or right ColspanCentralPart = 2; } fprintf (Gbl.F.Out,"" "" "
" "
" "" "", ColspanCentralPart, The_TabOnBgColors[Gbl.Prefs.Theme]); /***** Central (main) part *****/ switch (Gbl.Prefs.Layout) { case Lay_LAYOUT_DESKTOP: /* Left bar used to expand-contract central zone */ fprintf (Gbl.F.Out,""); /* Tab content, including always vertical menu (left) and always main zone (right) */ fprintf (Gbl.F.Out,""); /* Start of main zone for actions output */ fprintf (Gbl.F.Out,""); if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) { /* Right bar used to expand-contract central zone */ fprintf (Gbl.F.Out,""); } fprintf (Gbl.F.Out,"" "
"); Prf_PutLeftIconToHideShowCols (); fprintf (Gbl.F.Out,""); Lay_WriteMenuThisTabDesktop (); fprintf (Gbl.F.Out,""); Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin (); /* If it is mandatory to read any information about course */ if (Gbl.CurrentCrs.Info.ShowMsgMustBeRead) Inf_WriteMsgYouMustReadInfo (); break; case Lay_LAYOUT_MOBILE: /* Tab content */ fprintf (Gbl.F.Out,""); Usr_WarningWhenDegreeTypeDoesntAllowDirectLogin (); if (Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu < 0) // Write vertical menu { if (Gbl.CurrentAct == ActMnu) Lay_WriteMenuThisTabMobile (); else Lay_DrawTabsMobile (); } break; default: break; } /***** Main zone *****/ /* Write title of the current action */ if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP && Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu >= 0) Lay_WriteTitleAction (); Gbl.Layout.WritingHTMLStart = false; Gbl.Layout.HTMLStartWritten = true; /* Write new year greeting */ if (Gbl.CurrentAct == ActAutUsrInt || Gbl.CurrentAct == ActAutUsrExt || Gbl.CurrentAct == ActAutUsrChgLan) if (Gbl.Now.Date.Month == 1 && Gbl.Now.Date.Day == 1) { fprintf (Gbl.F.Out,"
" "


"); fprintf (Gbl.F.Out,Txt_NEW_YEAR_GREETING,Gbl.Now.Date.Year); fprintf (Gbl.F.Out,"


" "
"); } /* Write message indicating number of clicks allowed before sending my photo */ Usr_InformAboutNumClicksBeforePhoto (); } /*****************************************************************************/ /************************ Write the end of the page **************************/ /*****************************************************************************/ static void Lay_WriteEndOfPage (void) { if (!Gbl.Layout.TablEndWritten) { Gbl.Layout.TablEndWritten = true; fprintf (Gbl.F.Out,"
"); Prf_PutRigthIconToHideShowCols (); fprintf (Gbl.F.Out,"
" "
" "
\n"); } } /*****************************************************************************/ /************************* Write the title of the page ***********************/ /*****************************************************************************/ static void Lay_WritePageTitle (void) { fprintf (Gbl.F.Out,""); if (Gbl.GetMethod && Gbl.CurrentDeg.Deg.DegCod > 0) { fprintf (Gbl.F.Out,"%s > %s", Cfg_PLATFORM_PAGE_TITLE, Gbl.CurrentDeg.Deg.ShortName); if (Gbl.CurrentCrs.Crs.CrsCod > 0) fprintf (Gbl.F.Out," > %s", Gbl.CurrentCrs.Crs.ShortName); } else fprintf (Gbl.F.Out,"%s", Cfg_PLATFORM_PAGE_TITLE); fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /************* Write script and meta to redirect to my language **************/ /*****************************************************************************/ static void Lay_WriteRedirectionToMyLanguage (void) { extern const char *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES]; fprintf (Gbl.F.Out,"", Cfg_HTTPS_URL_SWAD_CGI, Txt_STR_LANG_ID[Gbl.Usrs.Me.UsrDat.Prefs.Language], Act_Actions[ActAutUsrChgLan].ActCod, Gbl.Session.Id); } /*****************************************************************************/ /************ Write some scripts depending on the current action *************/ /*****************************************************************************/ static void Lay_WriteScripts (void) { /***** General scripts for swad *****/ fprintf (Gbl.F.Out,"\n", Cfg_HTTPS_URL_SWAD_PUBLIC); if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW) { Lay_WriteScriptInit (); Lay_WriteScriptConnectedUsrs (); } /***** Script for uploading files using Dropzone.js (http://www.dropzonejs.com/) *****/ // The public directory dropzone must hold: // dropzone.js // css/dropzone.css // images/spritemap@2x.png // images/spritemap.png if (Gbl.CurrentAct == ActFrmCreDocCrs || // Brw_FILE_BRW_ADMIN_DOCUMENTS_CRS Gbl.CurrentAct == ActFrmCreDocGrp || // Brw_FILE_BRW_ADMIN_DOCUMENTS_GRP Gbl.CurrentAct == ActFrmCreComCrs || // Brw_FILE_BRW_COMMON_CRS Gbl.CurrentAct == ActFrmCreComGrp || // Brw_FILE_BRW_COMMON_GRP Gbl.CurrentAct == ActFrmCreAsgUsr || // Brw_FILE_BRW_ASSIGNMENTS_USR Gbl.CurrentAct == ActFrmCreAsgCrs || // Brw_FILE_BRW_ASSIGNMENTS_CRS Gbl.CurrentAct == ActFrmCreWrkUsr || // Brw_FILE_BRW_WORKS_USR Gbl.CurrentAct == ActFrmCreWrkCrs || // Brw_FILE_BRW_WORKS_CRS Gbl.CurrentAct == ActFrmCreMrkCrs || // Brw_FILE_BRW_ADMIN_MARKS_CRS Gbl.CurrentAct == ActFrmCreMrkGrp || // Brw_FILE_BRW_ADMIN_MARKS_GRP Gbl.CurrentAct == ActFrmCreBrf) // Brw_FILE_BRW_BRIEFCASE_USR { // Use charset="ISO-8859-1" to force error messages in ISO-8859-1 (default is UTF-8) fprintf (Gbl.F.Out,"\n", Cfg_HTTPS_URL_SWAD_PUBLIC); Lay_WriteScriptCustomDropzone (); } /***** Script to print world map *****/ if (Gbl.CurrentAct == ActSeeCty) Cty_WriteScriptGoogleGeochart (); /***** Script for Google Analytics *****/ fprintf (Gbl.F.Out,"%s",Cfg_GOOGLE_ANALYTICS); } // Change page title //function changeTitle(title) { // document.title = title; //} /*****************************************************************************/ /******* Write script with init function executed after loading page *********/ /*****************************************************************************/ static void Lay_WriteScriptInit (void) { extern const char *Txt_MONTHS_SMALL_SHORT[12]; extern const char *Txt_STR_LANG_ID[Txt_NUM_LANGUAGES]; fprintf (Gbl.F.Out,"\n"); } /*****************************************************************************/ /************** Write script to show connected users using AJAX **************/ /*****************************************************************************/ static void Lay_WriteScriptConnectedUsrs (void) { fprintf (Gbl.F.Out,"\n"); } /*****************************************************************************/ /******* Write script to customize upload of files using Dropzone.js *********/ /*****************************************************************************/ // More info: http://www.dropzonejs.com/ static void Lay_WriteScriptCustomDropzone (void) { fprintf (Gbl.F.Out,"\n"); } /*****************************************************************************/ /************************ Write top heading of the page **********************/ /*****************************************************************************/ static void Lay_WritePageTopHeading (void) { extern const char *The_ClassHead[The_NUM_THEMES]; const struct { const char *Icon; const unsigned Width; const unsigned Height; } LogoLayout[Lay_NUM_LAYOUTS] = { { // Lay_LAYOUT_DESKTOP "swad112x32.gif",112,32, }, { // Lay_LAYOUT_MOBILE "swad168x48.gif",168,48, }, }; fprintf (Gbl.F.Out,"", Gbl.Prefs.PathTheme); /***** 1st. row, 1st. column: logo *****/ fprintf (Gbl.F.Out,"", LogoLayout[Gbl.Prefs.Layout].Width + 16); /* Left logo */ fprintf (Gbl.F.Out,"" "\"%s\"" "", Cfg_HTTP_SwAD_HOME_PAGE,Gbl.Prefs.PathTheme, LogoLayout[Gbl.Prefs.Layout].Icon, LogoLayout[Gbl.Prefs.Layout].Width, LogoLayout[Gbl.Prefs.Layout].Height, Cfg_PLATFORM_FULL_NAME); fprintf (Gbl.F.Out,""); fprintf (Gbl.F.Out,"" "" ""); /***** 1st. row, 2nd. column: search, and logged user / language selection *****/ if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) { /* Search courses / teachers */ fprintf (Gbl.F.Out,""); } /* Logged user or language selection */ fprintf (Gbl.F.Out,"" "" "
", The_ClassHead[Gbl.Prefs.Theme]); Act_FormStart ( Gbl.CurrentCrs.Crs.CrsCod > 0 ? ActCrsSch : (Gbl.CurrentDeg.Deg.DegCod > 0 ? ActDegSch : (Gbl.CurrentCtr.Ctr.CtrCod > 0 ? ActCtrSch : (Gbl.CurrentIns.Ins.InsCod > 0 ? ActInsSch : (Gbl.CurrentCty.Cty.CtyCod > 0 ? ActCtySch : ActSysSch))))); Sco_PutParamScope (Sco_SCOPE_PLATFORM); Par_PutHiddenParamUnsigned ("WhatToSearch",(unsigned) Sch_SEARCH_ALL); Sch_PutFormToSearch (Gbl.Prefs.PathTheme); fprintf (Gbl.F.Out,"" "", The_ClassHead[Gbl.Prefs.Theme]); if (Gbl.Usrs.Me.Logged) Usr_WriteLoggedUsrHead (); else Prf_PutSelectorToSelectLanguage (); fprintf (Gbl.F.Out,"
" ""); /***** 1st. row, 3rd. column: link to open/close session *****/ fprintf (Gbl.F.Out,"", The_ClassHead[Gbl.Prefs.Theme]); if (Gbl.Usrs.Me.Logged) Usr_PutFormLogOut (); else Usr_PutFormLogIn (); fprintf (Gbl.F.Out,"" ""); /***** 2nd. row *****/ fprintf (Gbl.F.Out,"", Gbl.Prefs.PathTheme); switch (Gbl.Prefs.Layout) { case Lay_LAYOUT_DESKTOP: /***** 2nd. row, 1st. column *****/ /* Clock with hour:minute (server hour is shown) */ fprintf (Gbl.F.Out,""); Dat_ShowCurrentDateTime (); fprintf (Gbl.F.Out,""); // End of first column /***** 2nd. row, 2nd. column: degree and course *****/ fprintf (Gbl.F.Out,"" "
"); Deg_WriteCtyInsCtrDeg (); Crs_WriteSelectorMyCourses (); Deg_WriteBigNameCtyInsCtrDegCrs (); fprintf (Gbl.F.Out,"
" ""); /***** 2nd. row, 3rd. column *****/ fprintf (Gbl.F.Out,""); if (Gbl.Usrs.Me.Logged) { /* Number of new messages (not seen) */ fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh Ntf_WriteNumberOfNewNtfs (); fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh } break; case Lay_LAYOUT_MOBILE: fprintf (Gbl.F.Out,"", Gbl.Prefs.PathTheme); Deg_WriteCtyInsCtrDeg (); Crs_WriteSelectorMyCourses (); break; default: break; } fprintf (Gbl.F.Out,""); /***** 3rd. row *****/ fprintf (Gbl.F.Out,"" ""); switch (Gbl.Prefs.Layout) { case Lay_LAYOUT_DESKTOP: /***** 3rd. row, 1st. column *****/ if (Gbl.Prefs.SideCols & 2) // Left column visible fprintf (Gbl.F.Out,"" "", Gbl.Prefs.PathTheme); /***** 3rd. row, 2nd. column *****/ Lay_DrawTabs (); /***** 3rd. row, 3rd. column *****/ if (Gbl.Prefs.SideCols & 1) // Right column visible { fprintf (Gbl.F.Out,""); Lay_ShowRightColumn (); fprintf (Gbl.F.Out,""); } fprintf (Gbl.F.Out,"" ""); /***** 4th. row, 1st. column *****/ if (Gbl.Prefs.SideCols & 2) // Left column visible { fprintf (Gbl.F.Out,""); Lay_ShowLeftColumn (); fprintf (Gbl.F.Out,""); // End of first column } break; case Lay_LAYOUT_MOBILE: Lay_DrawTabs (); fprintf (Gbl.F.Out,"" ""); break; default: break; } } /*****************************************************************************/ /*************** Set current tab depending on current action *****************/ /*****************************************************************************/ void Lay_SetCurrentTab (void) { Gbl.CurrentTab = Act_Actions[Gbl.CurrentAct].Tab; /***** Change action and tab if country, institution, centre or degree are incompatible with the current tab *****/ switch (Gbl.CurrentTab) { case TabCty: if (Gbl.CurrentCty.Cty.CtyCod <= 0) // No country selected Gbl.CurrentAct = ActSeeCty; break; case TabIns: if (Gbl.CurrentIns.Ins.InsCod <= 0) // No institution selected { if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected Gbl.CurrentAct = ActSeeIns; else // No country selected Gbl.CurrentAct = ActSeeCty; } break; case TabCtr: if (Gbl.CurrentCtr.Ctr.CtrCod <= 0) // No centre selected { if (Gbl.CurrentIns.Ins.InsCod > 0) // Institution selected, but no centre selected Gbl.CurrentAct = ActSeeCtr; else if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected Gbl.CurrentAct = ActSeeIns; else // No country selected Gbl.CurrentAct = ActSeeCty; } break; case TabDeg: if (Gbl.CurrentDeg.Deg.DegCod <= 0) // No degree selected { if (Gbl.CurrentCtr.Ctr.CtrCod > 0) // Centre selected, but no degree selected Gbl.CurrentAct = ActSeeDeg; else if (Gbl.CurrentIns.Ins.InsCod > 0) // Institution selected, but no centre selected Gbl.CurrentAct = ActSeeCtr; else if (Gbl.CurrentCty.Cty.CtyCod > 0) // Country selected, but no institution selected Gbl.CurrentAct = ActSeeIns; else // No country selected Gbl.CurrentAct = ActSeeCty; } break; default: break; } Gbl.CurrentTab = Act_Actions[Gbl.CurrentAct].Tab; Lay_DisableIncompatibleTabs (); } /*****************************************************************************/ /************************** Disable incompatible tabs ************************/ /*****************************************************************************/ void Lay_DisableIncompatibleTabs (void) { /***** Set country, institution, centre, degree and course depending on the current tab. This will disable tabs incompatible with the current one. *****/ switch (Gbl.CurrentTab) { case TabSys: Gbl.CurrentCty.Cty.CtyCod = -1L; // no break case TabCty: Gbl.CurrentIns.Ins.InsCod = -1L; // no break case TabIns: Gbl.CurrentCtr.Ctr.CtrCod = -1L; // no break case TabCtr: Gbl.CurrentDeg.Deg.DegCod = -1L; // no break case TabDeg: Gbl.CurrentCrs.Crs.CrsCod = -1L; break; default: break; } } /*****************************************************************************/ /**************** Draw tabs with the current tab highlighted *****************/ /*****************************************************************************/ static void Lay_DrawTabs (void) { unsigned ColspanCentralPart = 3; if (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP) { if (Gbl.Prefs.SideCols == 3) // 11: both side columns visible, left and right ColspanCentralPart = 1; else if (Gbl.Prefs.SideCols != 0) // 10 or 01: only one side column visible, left or right ColspanCentralPart = 2; } fprintf (Gbl.F.Out,"" "
", ColspanCentralPart,Gbl.Prefs.PathTheme); switch (Gbl.Prefs.Layout) { case Lay_LAYOUT_DESKTOP: Lay_DrawTabsDeskTop (); break; case Lay_LAYOUT_MOBILE: Lay_DrawBreadcrumb (); break; default: break; } fprintf (Gbl.F.Out,"
" ""); } /*****************************************************************************/ /**************** Draw tabs with the current tab highlighted *****************/ /*****************************************************************************/ static void Lay_DrawTabsDeskTop (void) { extern const char *The_ClassTabOn[The_NUM_THEMES]; extern const char *The_ClassTabOff[The_NUM_THEMES]; extern const char *The_TabOnBgColors[The_NUM_THEMES]; extern const char *The_TabOffBgColors[The_NUM_THEMES]; extern const char *Txt_TABS_FULL_TXT[Act_NUM_TABS]; extern const char *Txt_TABS_SHORT_TXT[Act_NUM_TABS]; Act_Tab_t NumTab; bool ICanViewTab; /***** Table start *****/ fprintf (Gbl.F.Out,"
    "); /***** Draw the tabs *****/ for (NumTab = (Act_Tab_t) 1; NumTab <= (Act_Tab_t) Act_NUM_TABS - 1; NumTab++) { ICanViewTab = Lay_CheckIfICanViewTab (NumTab); /* If current tab is unknown, then activate the first one with access allowed */ if (Gbl.CurrentTab == TabUnk) { Gbl.CurrentTab = NumTab; Lay_DisableIncompatibleTabs (); } if (ICanViewTab || NumTab > TabCrs) // Don't show the first hidden tabs { /* Form, icon (at top) and text (at bottom) of the tab */ fprintf (Gbl.F.Out,"
  • ", NumTab == Gbl.CurrentTab ? "TAB_ON" : "TAB_OFF", NumTab == Gbl.CurrentTab ? The_TabOnBgColors[Gbl.Prefs.Theme] : The_TabOffBgColors[Gbl.Prefs.Theme]); if (ICanViewTab) { fprintf (Gbl.F.Out,""); Act_FormStart (ActMnu); Par_PutHiddenParamUnsigned ("NxtTab",(unsigned) NumTab); Act_LinkFormSubmit (Txt_TABS_FULL_TXT[NumTab], NumTab == Gbl.CurrentTab ? The_ClassTabOn[Gbl.Prefs.Theme] : The_ClassTabOff[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"" "
    %s" "" "", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_32x32, Lay_TabIcons[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_SHORT_TXT[NumTab]); } else fprintf (Gbl.F.Out,"
    " "\"%s\"" "
    %s
    ", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_32x32, Lay_TabIcons[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_FULL_TXT[NumTab], The_ClassTabOff[Gbl.Prefs.Theme], Txt_TABS_SHORT_TXT[NumTab]); fprintf (Gbl.F.Out,"
    " "
  • "); } } /***** End of the table *****/ fprintf (Gbl.F.Out,"
"); } /*****************************************************************************/ /************************ Draw vertical menu with tabs ***********************/ /*****************************************************************************/ static void Lay_DrawTabsMobile (void) { extern const char *The_ClassMenuOff[The_NUM_THEMES]; extern const char *Txt_TABS_FULL_TXT[Act_NUM_TABS]; unsigned NumTabVisible; Act_Tab_t NumTab; bool ICanViewTab; /***** Table start *****/ fprintf (Gbl.F.Out,""); /***** Loop to write all tabs. Each row holds a tab *****/ for (NumTabVisible = 0, NumTab = (Act_Tab_t) 1; NumTab <= (Act_Tab_t) Act_NUM_TABS - 1; NumTab++) { ICanViewTab = Lay_CheckIfICanViewTab (NumTab); if (ICanViewTab || NumTab > TabCrs) // Don't show the first hidden tabs { if (NumTabVisible % Cfg_LAYOUT_MOBILE_NUM_COLUMNS == 0) fprintf (Gbl.F.Out,""); /* Icon at top and text at bottom */ fprintf (Gbl.F.Out,""); if ((NumTabVisible % Cfg_LAYOUT_MOBILE_NUM_COLUMNS) == (Cfg_LAYOUT_MOBILE_NUM_COLUMNS-1)) fprintf (Gbl.F.Out,""); NumTabVisible++; } } /***** End of the table *****/ fprintf (Gbl.F.Out,"
" "" "" "" "" "
"); if (ICanViewTab) { fprintf (Gbl.F.Out,"
"); Act_FormStart (ActMnu); Par_PutHiddenParamUnsigned ("NxtTab",(unsigned) NumTab); Act_LinkFormSubmit (Txt_TABS_FULL_TXT[NumTab],The_ClassMenuOff[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"" "
%s" "" "" "
", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_64x64, Lay_TabIcons[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_FULL_TXT[NumTab]); } else fprintf (Gbl.F.Out,"
" "\"%s\"" "
%s
" "
", Gbl.Prefs.PathIconSet, Cfg_ICON_ACTION_64x64, Lay_TabIcons[NumTab], Txt_TABS_FULL_TXT[NumTab], Txt_TABS_FULL_TXT[NumTab], The_ClassMenuOff[Gbl.Prefs.Theme], Txt_TABS_FULL_TXT[NumTab]); fprintf (Gbl.F.Out,"
" "
"); } /*****************************************************************************/ /************************* Check if I can view a tab *************************/ /*****************************************************************************/ static bool Lay_CheckIfICanViewTab (Act_Tab_t Tab) { switch (Tab) { case TabUnk: return false; case TabSys: return (Gbl.CurrentCty.Cty.CtyCod <= 0); case TabCty: return (Gbl.CurrentCty.Cty.CtyCod > 0 && Gbl.CurrentIns.Ins.InsCod <= 0); case TabIns: return (Gbl.CurrentIns.Ins.InsCod > 0 && Gbl.CurrentCtr.Ctr.CtrCod <= 0); case TabCtr: return (Gbl.CurrentCtr.Ctr.CtrCod > 0 && Gbl.CurrentDeg.Deg.DegCod <= 0); case TabDeg: return (Gbl.CurrentDeg.Deg.DegCod > 0 && Gbl.CurrentCrs.Crs.CrsCod <= 0); case TabCrs: case TabAss: return (Gbl.CurrentCrs.Crs.CrsCod > 0); case TabMsg: return (Gbl.Usrs.Me.Logged || Gbl.CurrentCrs.Crs.CrsCod > 0); default: return true; } } /*****************************************************************************/ /********************* Draw breadcrumb with tab and action *******************/ /*****************************************************************************/ static void Lay_DrawBreadcrumb (void) { extern const char *The_TabOnBgColors[The_NUM_THEMES]; extern const char *The_ClassTabOn[The_NUM_THEMES]; fprintf (Gbl.F.Out,"
", The_TabOnBgColors[Gbl.Prefs.Theme]); /***** Home *****/ Lay_WriteBreadcrumbHome (); if (Gbl.CurrentAct == ActMnu || Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu >= 0) { /***** Tab *****/ fprintf (Gbl.F.Out," > ", The_ClassTabOn[Gbl.Prefs.Theme]); Lay_WriteBreadcrumbTab (); if (Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].IndexInMenu >= 0) { /***** Menu *****/ fprintf (Gbl.F.Out," > ", The_ClassTabOn[Gbl.Prefs.Theme]); Lay_WriteBreadcrumbAction (); } } fprintf (Gbl.F.Out,"
"); } /*****************************************************************************/ /************* Write the menu of current tab (desktop layout) ****************/ /*****************************************************************************/ static void Lay_WriteMenuThisTabDesktop (void) { extern const char *The_ClassMenuOn[The_NUM_THEMES]; extern const char *The_ClassMenuOff[The_NUM_THEMES]; extern const char *The_ClassSeparator[The_NUM_THEMES]; extern const struct Act_Menu Act_Menu[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB]; extern const char *Txt_MENU_BR[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB]; unsigned NumOptInMenu; Act_Action_t NumAct; const char *Title; bool IsTheSelectedAction; bool SeparationBetweenPreviousAndCurrentOption = false; bool PreviousVisibleOptions = false; /***** List start *****/ fprintf (Gbl.F.Out,"
    "); /***** Loop to write all options in menu. Each row holds an option *****/ for (NumOptInMenu = 0; NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB; NumOptInMenu++) { NumAct = Act_Menu[Gbl.CurrentTab][NumOptInMenu].Action; if (NumAct == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu break; if (Act_CheckIfIHavePermissionToExecuteAction (NumAct)) { IsTheSelectedAction = (NumAct == Act_Actions[Gbl.CurrentAct].SuperAction); Title = Act_GetTitleAction (NumAct); if (SeparationBetweenPreviousAndCurrentOption) { if (PreviousVisibleOptions) fprintf (Gbl.F.Out,"
  • " "
    " "
  • ", The_ClassSeparator[Gbl.Prefs.Theme]); SeparationBetweenPreviousAndCurrentOption = false; } /***** Start of element *****/ fprintf (Gbl.F.Out,"
  • "); /***** Start of container used to highlight this option *****/ if (!IsTheSelectedAction) fprintf (Gbl.F.Out,"
    "); /***** Start of form and link *****/ Act_FormStart (NumAct); Act_LinkFormSubmit (Title,IsTheSelectedAction ? The_ClassMenuOn[Gbl.Prefs.Theme] : The_ClassMenuOff[Gbl.Prefs.Theme]); /***** Icon *****/ fprintf (Gbl.F.Out,"
    ", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_32x32, Act_Actions[NumAct].Icon); /***** Text *****/ fprintf (Gbl.F.Out,"
    " "%s", IsTheSelectedAction ? The_ClassMenuOn[Gbl.Prefs.Theme] : The_ClassMenuOff[Gbl.Prefs.Theme], Txt_MENU_BR[Gbl.CurrentTab][NumOptInMenu]); /***** End of link and form *****/ fprintf (Gbl.F.Out,"
    " "
    " "" ""); /***** End of container used to highlight this option *****/ if (!IsTheSelectedAction) fprintf (Gbl.F.Out,"
    "); /***** End of element *****/ fprintf (Gbl.F.Out,"
  • "); PreviousVisibleOptions = true; } SeparationBetweenPreviousAndCurrentOption |= Act_Menu[Gbl.CurrentTab][NumOptInMenu].SubsequentSeparation; } /***** List end *****/ fprintf (Gbl.F.Out,"
"); } /*****************************************************************************/ /************* Write the menu of current tab (mobile layout) *****************/ /*****************************************************************************/ static void Lay_WriteMenuThisTabMobile (void) { extern const char *The_ClassMenuOn[The_NUM_THEMES]; extern const char *The_ClassMenuOff[The_NUM_THEMES]; extern const struct Act_Menu Act_Menu[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB]; extern const char *Txt_MENU_BR[Act_NUM_TABS][Act_MAX_OPTIONS_IN_MENU_PER_TAB]; unsigned NumOptInMenu; unsigned NumOptVisible; // Only options I can see Act_Action_t NumAct; const char *Title; /***** Table start *****/ fprintf (Gbl.F.Out,""); /***** Loop to write all options in menu. Each row holds an option *****/ for (NumOptInMenu = NumOptVisible = 0; NumOptInMenu < Act_MAX_OPTIONS_IN_MENU_PER_TAB; NumOptInMenu++) { if ((NumAct = Act_Menu[Gbl.CurrentTab][NumOptInMenu].Action) == 0) // At the end of each tab, actions are initialized to 0, so 0 marks the end of the menu break; if (Act_CheckIfIHavePermissionToExecuteAction (NumAct)) { Title = Act_GetTitleAction (NumAct); if (NumOptVisible % Cfg_LAYOUT_MOBILE_NUM_COLUMNS == 0) fprintf (Gbl.F.Out,""); /* Icon at top and text at bottom */ fprintf (Gbl.F.Out,"", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_64x64, Act_Actions[NumAct].Icon, Title, Title, Txt_MENU_BR[Gbl.CurrentTab][NumOptInMenu]); if ((NumOptVisible % Cfg_LAYOUT_MOBILE_NUM_COLUMNS) == (Cfg_LAYOUT_MOBILE_NUM_COLUMNS - 1)) fprintf (Gbl.F.Out,""); NumOptVisible++; } } /***** Table end *****/ fprintf (Gbl.F.Out,"
" "
"); Act_FormStart (NumAct); Act_LinkFormSubmit (Title, (NumAct == Act_Actions[Gbl.CurrentAct].SuperAction) ? The_ClassMenuOn[Gbl.Prefs.Theme] : The_ClassMenuOff[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"" "
%s" "" "" "
" "
"); } /*****************************************************************************/ /************************ Write home in breadcrumb ***************************/ /*****************************************************************************/ static void Lay_WriteBreadcrumbHome (void) { extern const char *The_ClassTabOn[The_NUM_THEMES]; extern const char *Txt_Home_PAGE; Act_FormStart (ActHom); Act_LinkFormSubmit (Txt_Home_PAGE,The_ClassTabOn[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s" "", Txt_Home_PAGE); } /*****************************************************************************/ /************ Write icon and title associated to the current tab *************/ /*****************************************************************************/ static void Lay_WriteBreadcrumbTab (void) { extern const char *The_ClassTabOn[The_NUM_THEMES]; extern const char *Txt_TABS_FULL_TXT[Act_NUM_TABS]; /***** Start form *****/ Act_FormStart (ActMnu); Par_PutHiddenParamUnsigned ("NxtTab",(unsigned) Gbl.CurrentTab); Act_LinkFormSubmit (Txt_TABS_FULL_TXT[Gbl.CurrentTab],The_ClassTabOn[Gbl.Prefs.Theme]); /***** Title and end of form *****/ fprintf (Gbl.F.Out,"%s" "", Txt_TABS_FULL_TXT[Gbl.CurrentTab]); } /*****************************************************************************/ /***************** Write title associated to the current action **************/ /*****************************************************************************/ static void Lay_WriteBreadcrumbAction (void) { extern const char *The_ClassTabOn[The_NUM_THEMES]; const char *Title = Act_GetMenuTxtAction (Gbl.CurrentAct); /***** Start form *****/ Act_FormStart (Act_Actions[Gbl.CurrentAct].SuperAction); Act_LinkFormSubmit (Title,The_ClassTabOn[Gbl.Prefs.Theme]); /***** Title and end of form *****/ fprintf (Gbl.F.Out,"%s" "", Title); } /*****************************************************************************/ /*********** Write icon and title associated to the current action ***********/ /*****************************************************************************/ static void Lay_WriteTitleAction (void) { extern const char *The_ClassTitleAction[The_NUM_THEMES]; extern const char *The_ClassSubtitleAction[The_NUM_THEMES]; extern const char *Txt_TABS_FULL_TXT[Act_NUM_TABS]; /***** Container start *****/ fprintf (Gbl.F.Out,"
", Gbl.Prefs.PathIconSet,Cfg_ICON_ACTION_64x64, Act_Actions[Act_Actions[Gbl.CurrentAct].SuperAction].Icon); /***** Title *****/ fprintf (Gbl.F.Out,"%s > %s", The_ClassTitleAction[Gbl.Prefs.Theme], Txt_TABS_FULL_TXT[Act_Actions[Gbl.CurrentAct].Tab], Act_GetTitleAction (Gbl.CurrentAct)); /***** Subtitle *****/ fprintf (Gbl.F.Out,"
%s
", The_ClassSubtitleAction[Gbl.Prefs.Theme], Act_GetSubtitleAction (Gbl.CurrentAct)); /***** Container end *****/ fprintf (Gbl.F.Out,"
"); } /*****************************************************************************/ /***************************** Show left column ******************************/ /*****************************************************************************/ static void Lay_ShowLeftColumn (void) { struct Act_ListMFUActions ListMFUActions; fprintf (Gbl.F.Out,"" "" "" "" "
" ""); /***** Most frequently used actions *****/ if (Gbl.Usrs.Me.Logged) { fprintf (Gbl.F.Out,"" "" ""); } /***** Month *****/ fprintf (Gbl.F.Out,"" "" ""); /***** Notices (yellow notes) *****/ if (Gbl.CurrentCrs.Crs.CrsCod > 0) { fprintf (Gbl.F.Out,"" "" ""); } fprintf (Gbl.F.Out,"
"); Act_AllocateMFUActions (&ListMFUActions,6); Act_GetMFUActions (&ListMFUActions,6); Act_WriteSmallMFUActions (&ListMFUActions); Act_FreeMFUActions (&ListMFUActions); fprintf (Gbl.F.Out,"
"); Dat_DrawCurrentMonth (); fprintf (Gbl.F.Out,"
"); Not_ShowNotices (Not_LIST_BRIEF_NOTICES); fprintf (Gbl.F.Out,"
" "
"); } /*****************************************************************************/ /**************************** Show right column ******************************/ /*****************************************************************************/ static void Lay_ShowRightColumn (void) { extern const char *The_ClassConnected[The_NUM_THEMES]; extern const char *Txt_Connected_users; extern const char *Txt_Connected_PLURAL; extern const char *Txt_If_you_have_an_Android_device_try_SWADroid; Gbl.Usrs.Connected.WhereToShow = Con_SHOW_ON_RIGHT_COLUMN; /***** Connected users *****/ fprintf (Gbl.F.Out,"" "" "" "" "
" "", Gbl.Prefs.PathTheme); /***** Banners *****/ Ban_WriteMenuWithBanners (); fprintf (Gbl.F.Out,"" "" ""); /***** SWADroid advertisement *****/ if (!Gbl.Usrs.Me.Logged || Gbl.CurrentAct == ActAutUsrInt || Gbl.CurrentAct == ActAutUsrExt) fprintf (Gbl.F.Out,"" "" "", Txt_If_you_have_an_Android_device_try_SWADroid, Gbl.Prefs.IconsURL); /***** Institutional links *****/ Lnk_WriteMenuWithInstitutionalLinks (); fprintf (Gbl.F.Out,"
"); Act_FormStart (ActLstCon); Act_LinkFormSubmit (Txt_Connected_users,The_ClassConnected[Gbl.Prefs.Theme]); fprintf (Gbl.F.Out,"%s" "", Txt_Connected_PLURAL); /***** Number of connected users in the whole platform *****/ fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh Con_ShowGlobalConnectedUsrs (); fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh /***** Number of connected users in the current course *****/ fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh if (Gbl.CurrentCrs.Crs.CrsCod > 0) // There is a course selected { Gbl.Scope.Current = Sco_SCOPE_COURSE; Con_ShowConnectedUsrsBelongingToScope (); } fprintf (Gbl.F.Out,"
"); // Used for AJAX based refresh fprintf (Gbl.F.Out,"
" "" "\"SWADroid\"" "" "
" "
"); } /*****************************************************************************/ /************************* Put a link (form) to edit *************************/ /*****************************************************************************/ void Lay_PutFormToEdit (Act_Action_t Action) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Edit; fprintf (Gbl.F.Out,"
"); Act_FormStart (Action); Act_LinkFormSubmit (Txt_Edit,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("edit",Txt_Edit,Txt_Edit); fprintf (Gbl.F.Out,"" "
"); } /*****************************************************************************/ /**************** Put a icon with a text to submit a form ********************/ /*****************************************************************************/ void Lay_PutSendIcon (const char *Icon,const char *Alt,const char *Text) { // margin-left is used because this form link may be placed after another one fprintf (Gbl.F.Out,"\"%s\""" " %s", Gbl.Prefs.IconsURL,Icon,Alt,Text); } /*****************************************************************************/ /********************** Put a button to submit a form ************************/ /*****************************************************************************/ void Lay_PutSendButton (const char *TextSendButton) { fprintf (Gbl.F.Out,"
" "" "
", TextSendButton); } /*****************************************************************************/ /************ Write a centered message with the title of a table *************/ /*****************************************************************************/ void Lay_WriteTitle (const char *Title) { fprintf (Gbl.F.Out,"
%s
",Title); } /*****************************************************************************/ /****************** Start and end a table with rounded frame *****************/ /*****************************************************************************/ void Lay_StartRoundFrameTable10 (const char *Width,unsigned CellPadding,const char *Title) { fprintf (Gbl.F.Out,"
" "
"); if (Title) fprintf (Gbl.F.Out,"
%s
", Title); fprintf (Gbl.F.Out,"", CellPadding); } void Lay_StartRoundFrameTable10Shadow (const char *Width,unsigned CellPadding) { fprintf (Gbl.F.Out,"
" "
" "
", CellPadding); } void Lay_EndRoundFrameTable10 (void) { fprintf (Gbl.F.Out,"
" "
" "
"); } /*****************************************************************************/ /******* Write error message, close files, remove lock file, and exit ********/ /*****************************************************************************/ void Lay_ShowErrorAndExit (const char *Message) { /***** Unlock tables if locked *****/ if (Gbl.DB.LockedTables) { Gbl.DB.LockedTables = false; mysql_query (&Gbl.mysql,"UNLOCK TABLES"); } if (!Gbl.WebService.IsWebService) { /***** Write possible error message *****/ Lay_ShowAlert (Lay_ERROR,Message); /***** Finish the page, except and *****/ Lay_WriteEndOfPage (); } /***** Free memory and close all the open files *****/ Gbl_Cleanup (); /***** Page is generated (except and ). Compute time to generate page *****/ if (Gbl.CurrentAct != ActRefCon && // Refreshing connected users Gbl.CurrentAct != ActRefLstClk) // Refreshing last clics Sta_ComputeTimeToGeneratePage (); /***** Send page. The HTML output is now in Gbl.F.Out file ==> copy it to standard output *****/ if (!Gbl.WebService.IsWebService) { rewind (Gbl.F.Out); Fil_FastCopyOfOpenFiles (Gbl.F.Out,stdout); Fil_CloseAndRemoveFileForXHTMLOutput (); } if (Gbl.WebService.IsWebService) // Serving a plugin request { /***** Log access *****/ Gbl.TimeSendInMicroseconds = 0L; Sta_LogAccess (Message); } else if (Gbl.CurrentAct != ActRefCon && // Refreshing connected users Gbl.CurrentAct != ActRefLstClk) // Refreshing last clicks { /***** Compute time to send page *****/ Sta_ComputeTimeToSendPage (); /***** Write page footer *****/ if (Act_Actions[Gbl.CurrentAct].BrowserWindow == Act_MAIN_WINDOW) Lay_WritePageFooter (); /***** Log access *****/ Sta_LogAccess (Message); /***** End the output *****/ if (!Gbl.Layout.HTMLEndWritten) { fprintf (Gbl.F.Out,"\n\n"); Gbl.Layout.HTMLEndWritten = true; } } /***** Close database connection *****/ DB_CloseDBConnection (); /***** Exit *****/ if (Gbl.WebService.IsWebService) Svc_Exit (Message); exit (0); } /*****************************************************************************/ /******************** Show an alert message to the user **********************/ /*****************************************************************************/ void Lay_ShowAlert (Lay_AlertType_t MsgType,const char *Message) { static const char *MsgIcons[Lay_NUM_ALERT_TYPES] = { "info", "success", "warning", "error", }; /****** If start of page is not written yet, do it now ******/ if (!Gbl.Layout.HTMLStartWritten) Lay_WriteStartOfPage (); if (Message) fprintf (Gbl.F.Out,"
" "
" "%s" "
" "
", Gbl.Prefs.IconsURL,MsgIcons[MsgType], Message); } /*****************************************************************************/ /*********** Refresh notifications and connected users via AJAX **************/ /*****************************************************************************/ void Lay_RefreshNotifsAndConnected (void) { unsigned NumUsr; bool ShowConnected = (Gbl.Prefs.Layout == Lay_LAYOUT_DESKTOP && (Gbl.Prefs.SideCols & 1) && Gbl.CurrentCrs.Crs.CrsCod > 0); // Right column visible && There is a course selected // Sometimes, someone must do this work, so who best than processes that refresh via AJAX? if (!(Gbl.PID % 11)) // Do this only one of 11 times ( 11 is prime) Ntf_SendPendingNotifByEMailToAllUsrs (); // Send pending notifications by e-mail else if (!(Gbl.PID % 1013)) // Do this only one of 1013 times (1013 is prime) Brw_RemoveExpiredExpandedFolders (); // Remove old expanded folders (from all users) else if (!(Gbl.PID % 1019)) // Do this only one of 1019 times (1019 is prime) Prf_RemoveOldPrefsFromIP (); // Remove old preferences from IP else if (!(Gbl.PID % 1021)) // Do this only one of 1021 times (1021 is prime) Sta_RemoveOldEntriesRecentLog (); // Remove old entries in recent log table, it's a slow query Gbl.Usrs.Connected.WhereToShow = Con_SHOW_ON_RIGHT_COLUMN; // Send, before the HTML, the refresh time fprintf (Gbl.F.Out,"%lu|",Gbl.Usrs.Connected.TimeToRefreshInMs); if (Gbl.Usrs.Me.Logged) Ntf_WriteNumberOfNewNtfs (); fprintf (Gbl.F.Out,"|"); Con_ShowGlobalConnectedUsrs (); fprintf (Gbl.F.Out,"|"); if (ShowConnected) { Gbl.Scope.Current = Sco_SCOPE_COURSE; Con_ShowConnectedUsrsBelongingToScope (); } fprintf (Gbl.F.Out,"|"); if (ShowConnected) fprintf (Gbl.F.Out,"%u",Gbl.Usrs.Connected.NumUsrsToList); fprintf (Gbl.F.Out,"|"); if (ShowConnected) for (NumUsr = 0; NumUsr < Gbl.Usrs.Connected.NumUsrsToList; NumUsr++) fprintf (Gbl.F.Out,"%u|",Gbl.Usrs.Connected.Lst[NumUsr].Seconds); /***** All the output is made, so don't write anymore *****/ Gbl.Layout.TablEndWritten = Gbl.Layout.HTMLEndWritten = true; } /*****************************************************************************/ /******************** Refresh connected users via AJAX ***********************/ /*****************************************************************************/ void Lay_RefreshLastClicks (void) { // Send, before the HTML, the refresh time fprintf (Gbl.F.Out,"%lu|",Cfg_TIME_TO_REFRESH_LAST_CLICKS); Con_GetAndShowLastClicks (); /***** All the output is made, so don't write anymore *****/ Gbl.Layout.TablEndWritten = Gbl.Layout.HTMLEndWritten = true; } /*****************************************************************************/ /*************************** Write footer of page ****************************/ /*****************************************************************************/ void Lay_WritePageFooter (void) { extern const char *Txt_About_X; extern const char *Txt_Questions_and_problems; switch (Gbl.Prefs.Layout) { case Lay_LAYOUT_DESKTOP: Lay_WriteFootFromHTMLFile (); fprintf (Gbl.F.Out,"

"); /***** Institution and centre hosting the platform *****/ fprintf (Gbl.F.Out,"" "\"%s\"
" "%s" "

", Cfg_ABOUT_URL, Gbl.Prefs.IconsURL,Cfg_ABOUT_LOGO, Cfg_ABOUT_LOGO_WIDTH,Cfg_ABOUT_LOGO_HEIGHT, Cfg_ABOUT_NAME, Cfg_ABOUT_NAME); fprintf (Gbl.F.Out,"%s: " "%s
", Cfg_HELP_WEB,Txt_Questions_and_problems, Cfg_PLATFORM_RESPONSIBLE_E_MAIL,Cfg_PLATFORM_RESPONSIBLE_E_MAIL); /***** About *****/ fprintf (Gbl.F.Out,"", Cfg_ABOUT_SWAD_URL); fprintf (Gbl.F.Out,Txt_About_X,Log_PLATFORM_VERSION); fprintf (Gbl.F.Out,"     "); /***** Write time to generate and send page *****/ Sta_WriteTimeToGenerateAndSendPage (); fprintf (Gbl.F.Out,"
"); break; case Lay_LAYOUT_MOBILE: default: break; } } /*****************************************************************************/ /************************ Write the end of the page **************************/ /*****************************************************************************/ static void Lay_WriteFootFromHTMLFile (void) { FILE *FileHTML; /***** Open file with the HTML page for the chat *****/ if ((FileHTML = fopen (Cfg_PATH_AND_FILE_REL_HTML_PRIVATE,"rb"))) { /***** Copy HTML to output file *****/ Fil_FastCopyOfOpenFiles (FileHTML,Gbl.F.Out); fclose (FileHTML); } } /*****************************************************************************/ /****** Write header and footer of the class photo or academic calendar ******/ /*****************************************************************************/ void Lay_WriteHeaderClassPhoto (unsigned NumColumns,bool PrintView,bool DrawingClassPhoto, long InsCod,long DegCod,long CrsCod) { struct Institution Ins; struct Degree Deg; struct Course Crs; unsigned Size = (PrintView ? 64 : 32); /***** Get data of institution *****/ Ins.InsCod = InsCod; Ins_GetDataOfInstitutionByCod (&Ins,Ins_GET_MINIMAL_DATA); /***** Get data of degree *****/ Deg.DegCod = DegCod; Deg_GetDataOfDegreeByCod (&Deg); /***** Get data of course *****/ Crs.CrsCod = CrsCod; Crs_GetDataOfCourseByCod (&Crs); /***** Table start *****/ fprintf (Gbl.F.Out,"" "" "" "", NumColumns); /***** First column: institution logo *****/ fprintf (Gbl.F.Out,""); /***** Second column: class photo title *****/ fprintf (Gbl.F.Out,""); /***** Third column: degree logo *****/ fprintf (Gbl.F.Out,""); /***** Table end *****/ fprintf (Gbl.F.Out,"" "
"); if (InsCod > 0) { if (!PrintView) fprintf (Gbl.F.Out,"",Ins.WWW); Ins_DrawInstitutionLogo (Ins.Logo,Ins.ShortName,Size,NULL); if (!PrintView) fprintf (Gbl.F.Out,""); } fprintf (Gbl.F.Out,""); if (InsCod > 0) { if (!PrintView) fprintf (Gbl.F.Out,"", Ins.WWW); fprintf (Gbl.F.Out,"%s",Ins.FullName); if (!PrintView) fprintf (Gbl.F.Out,""); } if (DegCod > 0) { if (Ins.InsCod > 0) fprintf (Gbl.F.Out," - "); if (!PrintView) fprintf (Gbl.F.Out,"", Deg.WWW); fprintf (Gbl.F.Out,"%s",Deg.FullName); if (!PrintView) fprintf (Gbl.F.Out,""); } fprintf (Gbl.F.Out,"
"); if (CrsCod > 0) { fprintf (Gbl.F.Out,"%s",Crs.FullName); if (DrawingClassPhoto && !Gbl.Usrs.ClassPhoto.AllGroups) { fprintf (Gbl.F.Out,"
"); Grp_WriteNamesOfSelectedGrps (); } } fprintf (Gbl.F.Out,"
"); if (DegCod > 0) { if (!PrintView) fprintf (Gbl.F.Out,"", Deg.WWW); Deg_DrawDegreeLogo (Deg.Logo,Deg.ShortName,Size,NULL); if (!PrintView) fprintf (Gbl.F.Out,""); } fprintf (Gbl.F.Out,"
" "" ""); } /*****************************************************************************/ /************************ Put icons to select a layout ***********************/ /*****************************************************************************/ void Lay_PutIconsToSelectLayout (void) { extern const char *Txt_LAYOUT_NAMES[Lay_NUM_LAYOUTS]; Lay_Layout_t Layout; fprintf (Gbl.F.Out,""); for (Layout = (Lay_Layout_t) 0; Layout < Lay_NUM_LAYOUTS; Layout++) { fprintf (Gbl.F.Out,"", Gbl.Prefs.IconsURL, Lay_LayoutIcons[Layout], Txt_LAYOUT_NAMES[Layout], Txt_LAYOUT_NAMES[Layout]); } fprintf (Gbl.F.Out,"
", Layout == Gbl.Prefs.Layout ? "LAYOUT_ON" : "LAYOUT_OFF"); Act_FormStart (ActChgLay); Par_PutHiddenParamUnsigned ("Layout",(unsigned) Layout); fprintf (Gbl.F.Out,"" "" "
"); } /*****************************************************************************/ /******************************** Change layout ******************************/ /*****************************************************************************/ void Lay_ChangeLayout (void) { char Query[512]; /***** Get param layout *****/ Gbl.Prefs.Layout = Lay_GetParamLayout (); /***** Store layout in database *****/ if (Gbl.Usrs.Me.Logged) { sprintf (Query,"UPDATE usr_data SET Layout='%u' WHERE UsrCod='%ld'", (unsigned) Gbl.Prefs.Layout,Gbl.Usrs.Me.UsrDat.UsrCod); DB_QueryUPDATE (Query,"can not update your preference about layout"); } /***** Set preferences from current IP *****/ Prf_SetPrefsFromIP (); } /*****************************************************************************/ /**************************** Get parameter layout ***************************/ /*****************************************************************************/ Lay_Layout_t Lay_GetParamLayout (void) { char UnsignedStr[1+10+1]; unsigned UnsignedNum; Par_GetParToText ("Layout",UnsignedStr,1+10); if (sscanf (UnsignedStr,"%u",&UnsignedNum) == 1) if (UnsignedNum < Lay_NUM_LAYOUTS) return (Lay_Layout_t) UnsignedNum; return Lay_LAYOUT_UNKNOWN; } /*****************************************************************************/ /************************* Put link to print view ****************************/ /*****************************************************************************/ void Lay_PutLinkToPrintView1 (Act_Action_t NextAction) { Act_FormStart (NextAction); } void Lay_PutLinkToPrintView2 (void) { extern const char *The_ClassFormul[The_NUM_THEMES]; extern const char *Txt_Print_view; Act_LinkFormSubmit (Txt_Print_view,The_ClassFormul[Gbl.Prefs.Theme]); Lay_PutSendIcon ("print",Txt_Print_view,Txt_Print_view); fprintf (Gbl.F.Out,""); } /*****************************************************************************/ /**************** Show advertisement about mobile version ********************/ /*****************************************************************************/ #define Lay_SHOW_ADVERTISEMENT_ONE_TIME_OF_X 1 // n ==> show advertisement 1/n of the times void Lay_AdvertisementMobile (void) { extern const char *Txt_Stay_connected_with_SWADroid; if (!(rand () % Lay_SHOW_ADVERTISEMENT_ONE_TIME_OF_X)) { /***** Table start *****/ Lay_StartRoundFrameTable10 (NULL,8,NULL); /***** Show advertisement *****/ fprintf (Gbl.F.Out,"" "" "" "%s

" "\"SWADroid\"" "
" "" "", Txt_Stay_connected_with_SWADroid, Gbl.Prefs.IconsURL); /***** End table *****/ Lay_EndRoundFrameTable10 (); } }