From 942db928ce0458e6fcac50f6e65b3034ae0f7e67 Mon Sep 17 00:00:00 2001 From: acanas Date: Fri, 15 Jul 2022 18:15:40 +0200 Subject: [PATCH] Version 21.107: Jul 15, 2022 Move up/down resource of program item. --- swad_changelog.h | 5 +- swad_database.c | 12 +++ swad_database.h | 2 + swad_exam_database.c | 12 --- swad_exam_database.h | 1 - swad_exam_set.c | 2 +- swad_game.c | 2 +- swad_game_database.c | 12 --- swad_game_database.h | 1 - swad_group.c | 4 +- swad_group_database.c | 12 --- swad_group_database.h | 1 - swad_program.c | 8 +- swad_program_database.c | 222 +++++++++++++++++++++++++++------------- swad_program_database.h | 19 ++-- swad_program_resource.c | 182 +++++++++++++++++++++++--------- swad_program_resource.h | 8 +- 17 files changed, 332 insertions(+), 173 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index e6dbd795..b77b4dec 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -606,11 +606,12 @@ TODO: Fix bug: error al enviar un mensaje a dos recipientes, error on duplicate TODO: Attach pdf files in multimedia. */ -#define Log_PLATFORM_VERSION "SWAD 21.106 (2022-07-14)" +#define Log_PLATFORM_VERSION "SWAD 21.107 (2022-07-15)" #define CSS_FILE "swad21.103.6.css" #define JS_FILE "swad21.100.js" /* - Version 21.106: Jul 14, 2022 Hide/unhide resource from program item. (328816 lines) + Version 21.107: Jul 15, 2022 Move up/down resource of program item. (328953 lines) + Version 21.106: Jul 14, 2022 Hide/unhide resource of program item. (328816 lines) Version 21.105: Jul 14, 2022 Removing resource from program item. (328617 lines) Version 21.104.1: Jul 13, 2022 Adding resources to program items. (328504 lines) Version 21.104: Jul 12, 2022 Adding resources to program items. (328263 lines) diff --git a/swad_database.c b/swad_database.c index 1def65d0..be819195 100644 --- a/swad_database.c +++ b/swad_database.c @@ -4337,3 +4337,15 @@ void DB_ExitOnMySQLError (const char *Message) Message,mysql_error (&Gbl.mysql)); Err_ShowErrorAndExit (BigErrorMsg); } + +/*****************************************************************************/ +/********** Unlock tables to make the exchange of items atomic ***************/ +/*****************************************************************************/ + +void DB_UnlockTables (void) + { + Gbl.DB.LockedTables = false; // Set to false before the following unlock... + // ...to not retry the unlock if error in unlocking + DB_Query ("can not unlock tables", + "UNLOCK TABLES"); + } diff --git a/swad_database.h b/swad_database.h index 2d927614..4aaf9122 100644 --- a/swad_database.h +++ b/swad_database.h @@ -77,4 +77,6 @@ void DB_Query (const char *MsgError,const char *fmt,...); void DB_FreeMySQLResult (MYSQL_RES **mysql_res); void DB_ExitOnMySQLError (const char *Message); +void DB_UnlockTables (void); + #endif diff --git a/swad_exam_database.c b/swad_exam_database.c index 4faccfee..a960d016 100644 --- a/swad_exam_database.c +++ b/swad_exam_database.c @@ -619,18 +619,6 @@ void Exa_DB_LockTables (void) Gbl.DB.LockedTables = true; } -/*****************************************************************************/ -/********** Unlock tables to make the exchange of sets atomic ****************/ -/*****************************************************************************/ - -void Exa_DB_UnlockTables (void) - { - Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking - DB_Query ("can not unlock tables after exchanging sets of questions", - "UNLOCK TABLES"); - } - /*****************************************************************************/ /*********************** Get number of sets in an exam ***********************/ /*****************************************************************************/ diff --git a/swad_exam_database.h b/swad_exam_database.h index 397f5f69..e698f075 100644 --- a/swad_exam_database.h +++ b/swad_exam_database.h @@ -61,7 +61,6 @@ void Exa_DB_UpdateNumQstsToExam (long SetCod,long ExaCod,unsigned NumQstsToPrint void Exa_DB_UpdateSetIndexesInExamGreaterThan (long ExaCod,long SetInd); void Exa_DB_UpdateSetIndex (long SetInd,long SetCod,long ExaCod); void Exa_DB_LockTables (void); -void Exa_DB_UnlockTables (void); unsigned Exa_DB_GetNumSetsExam (long ExaCod); unsigned Exa_DB_GetNumQstsExam (long ExaCod); unsigned Exa_DB_GetExamSets (MYSQL_RES **mysql_res,long ExaCod); diff --git a/swad_exam_set.c b/swad_exam_set.c index 640e7729..95a52cc8 100644 --- a/swad_exam_set.c +++ b/swad_exam_set.c @@ -1797,7 +1797,7 @@ static void ExaSet_ExchangeSets (long ExaCod, Exa_DB_UpdateSetIndex ( (long) SetIndBottom ,SetCodTop ,ExaCod); /***** Unlock table *****/ - Exa_DB_LockTables (); + DB_UnlockTables (); } /*****************************************************************************/ diff --git a/swad_game.c b/swad_game.c index 35528fe5..9dc0c052 100644 --- a/swad_game.c +++ b/swad_game.c @@ -2173,7 +2173,7 @@ static void Gam_ExchangeQuestions (long GamCod, Gam_DB_UpdateQstIndex ( (long) QstIndBottom ,GamCod,QstCodTop ); /***** Unlock table *****/ - Gam_DB_UnlockTable (); + DB_UnlockTables (); } /*****************************************************************************/ diff --git a/swad_game_database.c b/swad_game_database.c index b4d3f78b..79980fdf 100644 --- a/swad_game_database.c +++ b/swad_game_database.c @@ -487,18 +487,6 @@ void Gam_DB_LockTable (void) Gbl.DB.LockedTables = true; } -/*****************************************************************************/ -/********** Unlock table to make the exchange of questions atomic ************/ -/*****************************************************************************/ - -void Gam_DB_UnlockTable (void) - { - Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking - DB_Query ("can not unlock tables after moving game questions", - "UNLOCK TABLES"); - } - /*****************************************************************************/ /******************* Get number of questions of a game *********************/ /*****************************************************************************/ diff --git a/swad_game_database.h b/swad_game_database.h index 1a3fe258..125c71d7 100644 --- a/swad_game_database.h +++ b/swad_game_database.h @@ -55,7 +55,6 @@ void Gam_DB_InsertQstInGame (long GamCod,unsigned QstInd,long QstCod); void Gam_DB_UpdateIndexesOfQstsGreaterThan (long GamCod,unsigned QstInd); void Gam_DB_UpdateQstIndex (long QstInd,long GamCod,long QstCod); void Gam_DB_LockTable (void); -void Gam_DB_UnlockTable (void); unsigned Gam_DB_GetNumQstsGame (long GamCod); unsigned Gam_DB_GetGameQuestionsBasic (MYSQL_RES **mysql_res,long GamCod); diff --git a/swad_group.c b/swad_group.c index a78f9fd2..f0bb4312 100644 --- a/swad_group.c +++ b/swad_group.c @@ -881,7 +881,7 @@ bool Grp_ChangeMyGrpsAtomically (struct ListCodGrps *LstGrpsIWant) Grp_FreeListCodGrp (&LstGrpsIBelong); /***** Unlock tables after changes in my groups *****/ - Grp_DB_UnlockTables (); + DB_UnlockTables (); /***** Free list of groups types and groups in this course *****/ Grp_FreeListGrpTypesAndGrps (); @@ -946,7 +946,7 @@ void Grp_ChangeGrpsOtherUsrAtomically (struct ListCodGrps *LstGrpsUsrWants) /***** Unlock tables after changes in groups *****/ if (Gbl.Usrs.Other.UsrDat.Roles.InCurrentCrs == Rol_STD) - Grp_DB_UnlockTables (); + DB_UnlockTables (); /***** Free list of groups types and groups in this course *****/ Grp_FreeListGrpTypesAndGrps (); diff --git a/swad_group_database.c b/swad_group_database.c index 61d545d4..d8d4a089 100644 --- a/swad_group_database.c +++ b/swad_group_database.c @@ -57,18 +57,6 @@ void Grp_DB_LockTables (void) Gbl.DB.LockedTables = true; } -/*****************************************************************************/ -/*********** Unlock tables after changes in registration in groups ***********/ -/*****************************************************************************/ - -void Grp_DB_UnlockTables (void) - { - Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking - DB_Query ("can not unlock tables after changing user's groups", - "UNLOCK TABLES"); - } - /*****************************************************************************/ /************************** Create a new group type **************************/ /*****************************************************************************/ diff --git a/swad_group_database.h b/swad_group_database.h index 9dc1112c..f42048c5 100644 --- a/swad_group_database.h +++ b/swad_group_database.h @@ -34,7 +34,6 @@ /*****************************************************************************/ void Grp_DB_LockTables (void); -void Grp_DB_UnlockTables (void); long Grp_DB_CreateGroupType (const struct GroupType *GrpTyp); void Grp_DB_CreateGroup (const struct Grp_Groups *Grps); diff --git a/swad_program.c b/swad_program.c index a9fa854a..36bd41b0 100644 --- a/swad_program.c +++ b/swad_program.c @@ -1314,7 +1314,7 @@ static bool Prg_ExchangeItemRanges (int NumItemTop,int NumItemBottom) DiffEnd = Bottom.End - Top.End; /***** Lock table to make the move atomic *****/ - Prg_DB_LockTable (); + Prg_DB_LockTableItems (); /***** Exchange indexes of items *****/ // This implementation works with non continuous indexes @@ -1357,7 +1357,7 @@ Bottom.End: | 49| 222|-->|-->-49| 222| | -49| 222|-->|--> 26| 2 -((long) Bottom.Begin)); // All indexes in bottom part /***** Unlock table *****/ - Prg_DB_UnlockTable (); + DB_UnlockTables (); return true; // Success } @@ -1894,7 +1894,7 @@ static void Prg_InsertItem (const struct Prg_Item *ParentItem, unsigned NumItemLastChild; /***** Lock table to create program item *****/ - Prg_DB_LockTable (); + Prg_DB_LockTableItems (); /***** Get list of program items *****/ Prg_GetListItems (); @@ -1941,7 +1941,7 @@ static void Prg_InsertItem (const struct Prg_Item *ParentItem, Item->Hierarchy.ItmCod = Prg_DB_InsertItem (Item,Txt); /***** Unlock table *****/ - Prg_DB_UnlockTable (); + DB_UnlockTables (); /***** Free list items *****/ Prg_FreeListItems (); diff --git a/swad_program_database.c b/swad_program_database.c index 6c5e3577..55020569 100644 --- a/swad_program_database.c +++ b/swad_program_database.c @@ -120,28 +120,16 @@ void Prg_DB_UpdateIndexRange (long Diff,long Begin,long End) } /*****************************************************************************/ -/************ Lock tables to make the exchange of items atomic ***************/ +/************ Lock table to make the exchange of items atomic ****************/ /*****************************************************************************/ -void Prg_DB_LockTable (void) +void Prg_DB_LockTableItems (void) { DB_Query ("can not lock table", "LOCK TABLES prg_items WRITE"); Gbl.DB.LockedTables = true; } -/*****************************************************************************/ -/********** Unlock tables to make the exchange of items atomic ***************/ -/*****************************************************************************/ - -void Prg_DB_UnlockTable (void) - { - Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking - DB_Query ("can not unlock tables", - "UNLOCK TABLES"); - } - /*****************************************************************************/ /************ Move down all indexes of after last child of parent ************/ /*****************************************************************************/ @@ -256,63 +244,6 @@ void Prg_DB_GetItemTxt (long ItmCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) Gbl.Hierarchy.Crs.CrsCod); } -/*****************************************************************************/ -/****************** Get list of item resources from database *****************/ -/*****************************************************************************/ - -unsigned Prg_DB_GetListResources (MYSQL_RES **mysql_res,long ItmCod, - bool ShowHiddenResources) - {/* - static const char *HiddenSubQuery[Rol_NUM_ROLES] = - { - [Rol_UNK ] = " AND Hidden='N'", - [Rol_GST ] = " AND Hidden='N'", - [Rol_USR ] = " AND Hidden='N'", - [Rol_STD ] = " AND Hidden='N'", - [Rol_NET ] = " AND Hidden='N'", - [Rol_TCH ] = "", - [Rol_DEG_ADM] = " AND Hidden='N'", - [Rol_CTR_ADM] = " AND Hidden='N'", - [Rol_INS_ADM] = " AND Hidden='N'", - [Rol_SYS_ADM] = "", - }; */ - static const char *HiddenSubQuery[2] = - { - [false] = " AND Hidden='N'", - [true ] = "", - }; - - return (unsigned) - DB_QuerySELECT (mysql_res,"can not get item resources", - "SELECT ItmCod," // row[0] - "RscCod," // row[1] - "Hidden," // row[2] - "Title" // row[3] - " FROM prg_resources" - " WHERE ItmCod=%ld" - "%s" - " ORDER BY RscInd", - ItmCod, - HiddenSubQuery[ShowHiddenResources]); - } - -/*****************************************************************************/ -/****************** Get item resource data using its code ********************/ -/*****************************************************************************/ - -unsigned Prg_DB_GetDataOfResourceByCod (MYSQL_RES **mysql_res,long RscCod) - { - return (unsigned) - DB_QuerySELECT (mysql_res,"can not get item resource data", - "SELECT ItmCod," // row[0] - "RscCod," // row[1] - "Hidden," // row[2] - "Title" // row[3] - " FROM prg_resources" - " WHERE RscCod=%ld", - RscCod); - } - /*****************************************************************************/ /****************** Get number of courses with program items *****************/ /*****************************************************************************/ @@ -494,6 +425,130 @@ void Prg_DB_RemoveCrsItems (long CrsCod) CrsCod); } +/*****************************************************************************/ +/****************** Get list of item resources from database *****************/ +/*****************************************************************************/ + +unsigned Prg_DB_GetListResources (MYSQL_RES **mysql_res,long ItmCod, + bool ShowHiddenResources) + {/* + static const char *HiddenSubQuery[Rol_NUM_ROLES] = + { + [Rol_UNK ] = " AND Hidden='N'", + [Rol_GST ] = " AND Hidden='N'", + [Rol_USR ] = " AND Hidden='N'", + [Rol_STD ] = " AND Hidden='N'", + [Rol_NET ] = " AND Hidden='N'", + [Rol_TCH ] = "", + [Rol_DEG_ADM] = " AND Hidden='N'", + [Rol_CTR_ADM] = " AND Hidden='N'", + [Rol_INS_ADM] = " AND Hidden='N'", + [Rol_SYS_ADM] = "", + }; */ + static const char *HiddenSubQuery[2] = + { + [false] = " AND Hidden='N'", + [true ] = "", + }; + + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get item resources", + "SELECT ItmCod," // row[0] + "RscCod," // row[1] + "RscInd," // row[2] + "Hidden," // row[3] + "Title" // row[4] + " FROM prg_resources" + " WHERE ItmCod=%ld" + "%s" + " ORDER BY RscInd", + ItmCod, + HiddenSubQuery[ShowHiddenResources]); + } + +/*****************************************************************************/ +/****************** Get item resource data using its code ********************/ +/*****************************************************************************/ + +unsigned Prg_DB_GetDataOfResourceByCod (MYSQL_RES **mysql_res,long RscCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get item resource data", + "SELECT ItmCod," // row[0] + "RscCod," // row[1] + "RscInd," // row[2] + "Hidden," // row[3] + "Title" // row[4] + " FROM prg_resources" + " WHERE RscCod=%ld", + RscCod); + } + +/*****************************************************************************/ +/****************** Get item resource data using its code ********************/ +/*****************************************************************************/ + +unsigned Prg_DB_GetDataOfResourceByInd (MYSQL_RES **mysql_res, + long ItmCod,unsigned RscInd) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get item resource data", + "SELECT ItmCod," // row[0] + "RscCod," // row[1] + "RscInd," // row[2] + "Hidden," // row[3] + "Title" // row[4] + " FROM prg_resources" + " WHERE ItmCod=%ld" + " AND RscInd=%u", + ItmCod,RscInd); + } + +/*****************************************************************************/ +/************* Get the resource index before/after a given one ***************/ +/*****************************************************************************/ + +unsigned Prg_DB_GetRscIndBefore (long ItmCod,unsigned RscInd) + { + return + DB_QuerySELECTUnsigned ("can not get the resource before", + "SELECT COALESCE(MAX(RscInd),0)" + " FROM prg_resources" + " WHERE ItmCod=%ld" + " AND RscInd<%u", + ItmCod,RscInd); + } + +unsigned Prg_DB_GetRscIndAfter (long ItmCod,unsigned RscInd) + { + return + DB_QuerySELECTUnsigned ("can not get the resource after", + "SELECT COALESCE(MIN(RscInd),0)" + " FROM prg_resources" + " WHERE ItmCod=%ld" + " AND RscInd>%u", + ItmCod,RscInd); + } + +/*****************************************************************************/ +/*********** Get resource code given item code and resource index ************/ +/*****************************************************************************/ + +long Prg_DB_GetRscCodFromRscInd (long ItmCod,unsigned RscInd) + { + /***** Trivial check: resource index should be > 0 *****/ + if (RscInd == 0) + return -1L; + + /***** Get resource code given item code and resource index *****/ + return DB_QuerySELECTCode ("can not get resource code", + "SELECT RscCod" + " FROM prg_resources" + " WHERE ItmCod=%ld" + " AND RscInd=%u", + ItmCod,RscInd); + } + /*****************************************************************************/ /************************** Remove an item resource **************************/ /*****************************************************************************/ @@ -522,3 +577,28 @@ void Prg_DB_HideOrUnhideResource (long RscCod,bool Hide) 'N', RscCod); } + +/*****************************************************************************/ +/********** Lock table to make the exchange of resources atomic **************/ +/*****************************************************************************/ + +void Prg_DB_LockTableResources (void) + { + DB_Query ("can not lock table", + "LOCK TABLES prg_resources WRITE"); + Gbl.DB.LockedTables = true; + } + +/*****************************************************************************/ +/************* Update the index of a resource given its code *****************/ +/*****************************************************************************/ + +void Prg_DB_UpdateRscInd (long RscCod,int RscInd) + { + DB_QueryUPDATE ("can not update index of resource", + "UPDATE prg_resources" + " SET RscInd=%d" + " WHERE RscCod=%ld", + RscInd, + RscCod); + } diff --git a/swad_program_database.h b/swad_program_database.h index d6ebfd4f..9c0333ad 100644 --- a/swad_program_database.h +++ b/swad_program_database.h @@ -40,8 +40,7 @@ long Prg_DB_InsertItem (const struct Prg_Item *Item,const char *Txt); void Prg_DB_UpdateItem (const struct Prg_Item *Item,const char *Txt); void Prg_DB_HideOrUnhideItem (long ItmCod,bool Hide); void Prg_DB_UpdateIndexRange (long Diff,long Begin,long End); -void Prg_DB_LockTable (void); -void Prg_DB_UnlockTable (void); +void Prg_DB_LockTableItems (void); void Prg_DB_MoveDownItems (unsigned Index); void Prg_DB_MoveLeftRightItemRange (const struct Prg_ItemRange *ToMove, Prg_MoveLeftRight_t LeftRight); @@ -50,10 +49,6 @@ unsigned Prg_DB_GetListItems (MYSQL_RES **mysql_res); unsigned Prg_DB_GetDataOfItemByCod (MYSQL_RES **mysql_res,long ItmCod); void Prg_DB_GetItemTxt (long ItmCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); -unsigned Prg_DB_GetListResources (MYSQL_RES **mysql_res,long ItmCod, - bool ShowHiddenResources); -unsigned Prg_DB_GetDataOfResourceByCod (MYSQL_RES **mysql_res,long RscCod); - unsigned Prg_DB_GetNumCoursesWithItems (HieLvl_Level_t Scope); unsigned Prg_DB_GetNumItems (HieLvl_Level_t Scope); @@ -61,8 +56,20 @@ void Prg_DB_RemoveItemRange (const struct Prg_ItemRange *ToRemove); void Prg_DB_RemoveCrsItems (long CrsCod); //------------------------------ Resources ------------------------------------ +unsigned Prg_DB_GetListResources (MYSQL_RES **mysql_res,long ItmCod, + bool ShowHiddenResources); +unsigned Prg_DB_GetDataOfResourceByCod (MYSQL_RES **mysql_res,long RscCod); +unsigned Prg_DB_GetDataOfResourceByInd (MYSQL_RES **mysql_res, + long ItmCod,unsigned RscInd); +unsigned Prg_DB_GetRscIndBefore (long ItmCod,unsigned RscInd); +unsigned Prg_DB_GetRscIndAfter (long ItmCod,unsigned RscInd); +long Prg_DB_GetRscCodFromRscInd (long ItmCod,unsigned RscInd); + void Prg_DB_RemoveResource (const struct PrgRsc_Resource *Resource); void Prg_DB_HideOrUnhideResource (long RscCod,bool Hide); +void Prg_DB_LockTableResources (void); +void Prg_DB_UpdateRscInd (long RscCod,int RscInd); + #endif diff --git a/swad_program_resource.c b/swad_program_resource.c index 993feb5a..4097bdcd 100644 --- a/swad_program_resource.c +++ b/swad_program_resource.c @@ -82,6 +82,14 @@ struct Level bool Hidden; // If each level from 1 to maximum level is hidden }; */ + +#define PrgRsc_NUM_MOVEMENTS_UP_DOWN 2 +typedef enum + { + PrgRsc_MOVE_UP, + PrgRsc_MOVE_DOWN, + } PrgRsc_MoveUpDown_t; + /*****************************************************************************/ /***************************** Private variables *****************************/ /*****************************************************************************/ @@ -139,9 +147,9 @@ static long PrgRsc_GetParamRscCod (void); static void PrgRsc_HideOrUnhideResource (bool Hide); -static bool PrgRsc_CheckIfMoveUpIsAllowed (unsigned NumRsc); -static bool PrgRsc_CheckIfMoveDownIsAllowed (unsigned NumRsc, - unsigned NumResources); +static void PrgRsc_MoveUpDownResource (PrgRsc_MoveUpDown_t UpDown); +static bool PrgRsc_ExchangeResources (const struct PrgRsc_Rsc *Rsc1, + const struct PrgRsc_Rsc *Rsc2); /*****************************************************************************/ /****************************** Show resources *******************************/ @@ -348,10 +356,10 @@ static void PrgRsc_GetDataOfResourceByCod (struct PrgRsc_Resource *Resource) { MYSQL_RES *mysql_res; - if (Resource->RscCod > 0) + if (Resource->Rsc.Cod > 0) { /***** Get data of item resource *****/ - if (Prg_DB_GetDataOfResourceByCod (&mysql_res,Resource->RscCod)) + if (Prg_DB_GetDataOfResourceByCod (&mysql_res,Resource->Rsc.Cod)) PrgRsc_GetDataOfResource (Resource,&mysql_res); else PrgRsc_ResetResource (Resource); @@ -379,20 +387,22 @@ static void PrgRsc_GetDataOfResource (struct PrgRsc_Resource *Resource, /* ItmCod row[0] RscCod row[1] - Hidden row[2] - Title row[3] + RscInd row[2] + Hidden row[3] + Title row[4] */ /* Get code of the program item (row[0]) */ Resource->ItmCod = Str_ConvertStrCodToLongCod (row[0]); - /* Get code of the item resource (row[1]) */ - Resource->RscCod = Str_ConvertStrCodToLongCod (row[1]); + /* Get code and index of the item resource (row[1], row[2]) */ + Resource->Rsc.Cod = Str_ConvertStrCodToLongCod (row[1]); + Resource->Rsc.Ind = Str_ConvertStrToUnsigned (row[2]); - /* Get whether the program item is hidden (row(2)) */ - Resource->Hidden = (row[2][0] == 'Y'); + /* Get whether the program item is hidden (row(3)) */ + Resource->Hidden = (row[3][0] == 'Y'); - /* Get the title of the item resource (row[3]) */ - Str_Copy (Resource->Title,row[3],sizeof (Resource->Title) - 1); + /* Get the title of the item resource (row[4]) */ + Str_Copy (Resource->Title,row[4],sizeof (Resource->Title) - 1); } /*****************************************************************************/ @@ -402,7 +412,8 @@ static void PrgRsc_GetDataOfResource (struct PrgRsc_Resource *Resource, static void PrgRsc_ResetResource (struct PrgRsc_Resource *Resource) { Resource->ItmCod = -1L; - Resource->RscCod = -1L; + Resource->Rsc.Cod = -1L; + Resource->Rsc.Ind = 0; Resource->Hidden = false; Resource->Title[0] = '\0'; } @@ -480,15 +491,15 @@ static void PrgRsc_PutFormsToRemEditOneResource (unsigned NumRsc, case Rol_SYS_ADM: /***** Put form to remove item resource *****/ Ico_PutContextualIconToRemove (ActReqRemPrgRsc,PrgRsc_RESOURCE_SECTION_ID, - PrgRsc_PutParams,&Resource->RscCod); + PrgRsc_PutParams,&Resource->Rsc.Cod); /***** Put form to hide/show item resource *****/ if (Resource->Hidden) Ico_PutContextualIconToUnhide (ActUnhPrgRsc,PrgRsc_RESOURCE_SECTION_ID, - PrgRsc_PutParams,&Resource->RscCod); + PrgRsc_PutParams,&Resource->Rsc.Cod); else Ico_PutContextualIconToHide (ActHidPrgRsc,PrgRsc_RESOURCE_SECTION_ID, - PrgRsc_PutParams,&Resource->RscCod); + PrgRsc_PutParams,&Resource->Rsc.Cod); /***** Put form to edit program item *****/ // Ico_PutContextualIconToEdit (ActFrmChgPrgItm,"item_form", @@ -501,17 +512,17 @@ static void PrgRsc_PutFormsToRemEditOneResource (unsigned NumRsc, HTM_BR (); /***** Put icon to move up the item *****/ - if (PrgRsc_CheckIfMoveUpIsAllowed (NumRsc)) + if (NumRsc > 0) Lay_PutContextualLinkOnlyIcon (ActUp_PrgRsc,PrgRsc_RESOURCE_SECTION_ID, - PrgRsc_PutParams,&Resource->RscCod, + PrgRsc_PutParams,&Resource->Rsc.Cod, "arrow-up.svg",Ico_BLACK); else Ico_PutIconOff ("arrow-up.svg",Ico_BLACK,Txt_Movement_not_allowed); /***** Put icon to move down the item *****/ - if (PrgRsc_CheckIfMoveDownIsAllowed (NumRsc,NumResources)) + if (NumRsc < NumResources - 1) Lay_PutContextualLinkOnlyIcon (ActDwnPrgRsc,PrgRsc_RESOURCE_SECTION_ID, - PrgRsc_PutParams,&Resource->RscCod, + PrgRsc_PutParams,&Resource->Rsc.Cod, "arrow-down.svg",Ico_BLACK); else Ico_PutIconOff ("arrow-down.svg",Ico_BLACK,Txt_Movement_not_allowed); @@ -569,7 +580,7 @@ void PrgRsc_ReqRemResource (void) Prg_GetListItems (); /***** Get data of the item resource from database *****/ - Resource.RscCod = PrgRsc_GetParamRscCod (); + Resource.Rsc.Cod = PrgRsc_GetParamRscCod (); PrgRsc_GetDataOfResourceByCod (&Resource); if (Resource.ItmCod <= 0) Err_WrongResourceExit (); @@ -578,7 +589,7 @@ void PrgRsc_ReqRemResource (void) Ale_CreateAlert (Ale_QUESTION,PrgRsc_RESOURCE_SECTION_ID, Txt_Do_you_really_want_to_remove_the_resource_X, Resource.Title); - PrgSrc_RscCodToBeRemoved = Resource.RscCod; + PrgSrc_RscCodToBeRemoved = Resource.Rsc.Cod; /***** Get the code of the program item *****/ ItmCodBeforeForm = Resource.ItmCod; @@ -609,7 +620,7 @@ void PrgRsc_RemoveResource (void) Prg_GetListItems (); /***** Get data of the item resource from database *****/ - Resource.RscCod = PrgRsc_GetParamRscCod (); + Resource.Rsc.Cod = PrgRsc_GetParamRscCod (); PrgRsc_GetDataOfResourceByCod (&Resource); if (Resource.ItmCod <= 0) Err_WrongResourceExit (); @@ -659,13 +670,13 @@ static void PrgRsc_HideOrUnhideResource (bool Hide) Prg_GetListItems (); /***** Get data of the item resource from database *****/ - Resource.RscCod = PrgRsc_GetParamRscCod (); + Resource.Rsc.Cod = PrgRsc_GetParamRscCod (); PrgRsc_GetDataOfResourceByCod (&Resource); if (Resource.ItmCod <= 0) Err_WrongResourceExit (); /***** Hide/unhide item resource *****/ - Prg_DB_HideOrUnhideResource (Resource.RscCod,Hide); + Prg_DB_HideOrUnhideResource (Resource.Rsc.Cod,Hide); /***** Get the code of the program item *****/ ItmCodBeforeForm = Resource.ItmCod; @@ -681,32 +692,111 @@ static void PrgRsc_HideOrUnhideResource (bool Hide) } /*****************************************************************************/ -/********************* Check if resource can be moved up *********************/ +/**************************** Move up/down resource **************************/ /*****************************************************************************/ -static bool PrgRsc_CheckIfMoveUpIsAllowed (unsigned NumRsc) - { - /***** Trivial check: if resource is the first one, move up is not allowed *****/ - return (NumRsc != 0); - } - -/*****************************************************************************/ -/******************** Check if resource can be moved down ********************/ -/*****************************************************************************/ - -static bool PrgRsc_CheckIfMoveDownIsAllowed (unsigned NumRsc, - unsigned NumResources) - { - /***** Trivial check: if resource is the last one, move up is not allowed *****/ - return (NumRsc < NumResources - 1); - } - void PrgRsc_MoveUpResource (void) { - + PrgRsc_MoveUpDownResource (PrgRsc_MOVE_UP); } void PrgRsc_MoveDownResource (void) { - + PrgRsc_MoveUpDownResource (PrgRsc_MOVE_DOWN); + } + +static void PrgRsc_MoveUpDownResource (PrgRsc_MoveUpDown_t UpDown) + { + extern const char *Txt_Movement_not_allowed; + struct PrgRsc_Resource Resource; + struct PrgRsc_Rsc Rsc2; + long ItmCodBeforeForm; + unsigned FormLevel; + struct Prg_ItemRange ToHighlight; + bool Success = false; + static unsigned (*GetOtherRscInd[PrgRsc_NUM_MOVEMENTS_UP_DOWN])(long ItmCod,unsigned RscInd) = + { + [PrgRsc_MOVE_UP ] = Prg_DB_GetRscIndBefore, + [PrgRsc_MOVE_DOWN] = Prg_DB_GetRscIndAfter, + }; + + /***** Get list of program items *****/ + Prg_GetListItems (); + + /***** Get data of the item resource from database *****/ + Resource.Rsc.Cod = PrgRsc_GetParamRscCod (); + PrgRsc_GetDataOfResourceByCod (&Resource); + if (Resource.ItmCod <= 0) + Err_WrongResourceExit (); + + /***** Move up/down resource *****/ + if ((Rsc2.Ind = GetOtherRscInd[UpDown] (Resource.ItmCod,Resource.Rsc.Ind))) // 0 ==> movement not allowed + { + /* Get the other resource code */ + Rsc2.Cod = Prg_DB_GetRscCodFromRscInd (Resource.ItmCod,Rsc2.Ind); + + /* Exchange subtrees */ + Success = PrgRsc_ExchangeResources (&Resource.Rsc,&Rsc2); + } + if (!Success) + Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed); + + /***** Get the code of the program item *****/ + ItmCodBeforeForm = Resource.ItmCod; + FormLevel = Prg_GetLevelFromNumItem (Prg_GetNumItemFromItmCod (Resource.ItmCod)); + + /***** Show current program items, if any *****/ + Prg_SetItemRangeEmpty (&ToHighlight); + Prg_ShowAllItems (Prg_PUT_FORM_CHANGE_ITEM, + &ToHighlight,-1L,ItmCodBeforeForm,FormLevel); + + /***** Free list of program items *****/ + Prg_FreeListItems (); + } + +/*****************************************************************************/ +/**** Exchange the order of two consecutive subtrees in a course program *****/ +/*****************************************************************************/ +// Return true if success + +static bool PrgRsc_ExchangeResources (const struct PrgRsc_Rsc *Rsc1, + const struct PrgRsc_Rsc *Rsc2) + { + if (Rsc1->Ind > 0 && // Indexes should be in the range [1, 2,...] + Rsc2->Ind > 0) + { + /***** Lock table to make the move atomic *****/ + Prg_DB_LockTableResources (); + + /***** Exchange indexes of items *****/ + // This implementation works with non continuous indexes + /* + Example: + Rsc1->Ind = 5 + Rsc2->Ind = 17 + Step 1 Step 2 Step 3 (Equivalent to) + +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ + |Rsc.Ind|Rsc.Cod| |Rsc.Ind|Rsc.Cod| |Rsc.Ind|Rsc.Cod| |Rsc.Ind|Rsc.Cod| |Rsc.Ind|Rsc.Cod| + +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ + | 5 | 218 | | 5 | 218 |-->|--> 17 | 218 | | 17 | 218 | | 5 | 240 | + | 17 | 240 |-->|-->-17 | 240 | | -17 | 240 |-->|--> 5 | 240 | | 17 | 218 | + +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ +-------+-------+ + */ + /* Step 1: Change second index to negative, + necessary to preserve unique index (ItmCod,RscInd) */ + Prg_DB_UpdateRscInd (Rsc2->Cod,-(int) Rsc2->Ind); + + /* Step 2: Change first index */ + Prg_DB_UpdateRscInd (Rsc1->Cod, (int) Rsc2->Ind); + + /* Step 3: Change second index */ + Prg_DB_UpdateRscInd (Rsc2->Cod, (int) Rsc1->Ind); + + /***** Unlock table *****/ + DB_UnlockTables (); + + return true; // Success + } + + return false; // No success } diff --git a/swad_program_resource.h b/swad_program_resource.h index 16d6c4f1..093cdc9d 100644 --- a/swad_program_resource.h +++ b/swad_program_resource.h @@ -40,10 +40,16 @@ #define PrgRsc_MAX_CHARS_PROGRAM_RESOURCE_TITLE (128 - 1) // 127 #define PrgRsc_MAX_BYTES_PROGRAM_RESOURCE_TITLE ((PrgRsc_MAX_CHARS_PROGRAM_RESOURCE_TITLE + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 +struct PrgRsc_Rsc + { + long Cod; + unsigned Ind; // 1, 2, 3... + }; + struct PrgRsc_Resource { long ItmCod; - long RscCod; + struct PrgRsc_Rsc Rsc; bool Hidden; char Title[PrgRsc_MAX_BYTES_PROGRAM_RESOURCE_TITLE + 1]; };