Migrating existing menu structures to the SmartFramework menu

The SmartFramework menu structure is based on two database tables:

  • SmartFunction
  • SmartMenu

The SmartFunction table defines the functions that can be launched form the menu. Functions can be of various types as described in this article:

http://confluence.consultingwerkcloud.com/wiki/display/SCL/Using+IFunctionCallParameter

The SmartMenu structure is recursive and each leaf is representing a function to be launched refers to a SmartFunction record. As typically for the SmartDB records, the primary unique key fields (SmartFunction.FunctionGuid and SmartMenu.MenuGuid) are auto assigned using database create triggers (in src/SmartDBtrgs). The recursive relation between the SmartMenu records is defined using the SmartMenu.ParentMenuGuid field matching the SmartMenu.MenuGuid record of it’s parent. The root menu structures (the SmartFramework menu may contain multiple top level menu’s) is referencing the empty (“”) ParentMenuGuid value.

Creating SmartFunction records

The essence of the SmartFunction record is a JSON Serialized (XML on OpenEdge 10) object instance implementing the IFunctionCallParameter interface. In order to create an IFunctionCallParameter it’s recommended to create an appropriate object instance (in our sample an RunProcedureCallParameter), assign the object properties and use it’s Serialize() method to return the JSON String which is stored in the SmartFunction.FunctionCallParameter field.

The SmartFunction.FunctionModuleGuid is an optional reference to a SmartModule record (of a SmartProduct record). Those allow a logical grouping of functions into modules.

Sample code
/* find the module record */
FIND SmartModule WHERE SmartModule.ModuleName = "legacy" .


/* create menu function record */
ASSIGN 
    oCallParameter = NEW RunProcedureCallParameter () 
    oCallParameter:AllowMultiple                        = FALSE 
    oCallParameter:ProcedureName                        = "windows/cust.w"
    oCallParameter:RunPersistent                        = TRUE
    oCallParameter:InitializeInternalProcedure          = "dispatch"
    oCallParameter:InitializeInternalProcedureParameter = "initialize"
    oCallParameter:ReactivateInternalProcedure          = "dispatch"
    oCallParameter:ReactivateInternalProcedureParameter = "view"
    .

CREATE SmartFunction . 
ASSIGN SmartFunction.FunctionName          = "Sample function"
       SmartFunction.FunctionDescription   = "Imported menu function" 
       SmartFunction.FunctionModuleGuid    = SmartModule.ModuleGuid 
       SmartFunction.FunctionCallParameter = oCallParameter:Serialize() .

FIND CURRENT SmartFunction NO-LOCK . 

Creating SmartMenu records

The SmartMenu records build the recursive menu structure. When starting to query or create SmartMenu records you either start from the top (a SmartMenu record with ParentMenuGuid = “”) or an existing record. This existing record can be located using DB queries or in the Menu Function Maintenance. The contextual ribbon of the Menu Function Maintenance allows you to copy the MenuGuid of the currently selected menu item to the Windows clipboard so that you can copy it into your source code.

If you are going to create/import nested menu structures you will have to create child and grandchild records of a root menu structure. 

Sample code
/* Create/find menu structure */       
       
/* root menu structrue */
FIND SmartMenu WHERE SmartMenu.ParentMenuGuid = ""
                 AND SmartMenu.MenuName       = "Advantzware" NO-LOCK .
ASSIGN cRootMenuGuid = SmartMenu.MenuGuid . 


/* Find or create "master data" menu */
FIND SmartMenu WHERE SmartMenu.ParentMenuGuid = cRootMenuGuid
                 AND SmartMenu.MenuName       = "Master data" NO-ERROR .
       
IF NOT AVAILABLE SmartMenu THEN DO: 
    CREATE SmartMenu.
    ASSIGN SmartMenu.ParentMenuGuid         = cRootMenuGuid
           SmartMenu.MenuName               = "Master data"
           SmartMenu.MenuStructureType      = "Menu" .
    FIND CURRENT SmartMenu NO-LOCK . 
END.           
           
ASSIGN cParentMenuGuid = SmartMenu.MenuGuid .
       
/* Create an item menu structure under master data */       
CREATE SmartMenu.
ASSIGN SmartMenu.ParentMenuGuid         = cParentMenuGuid
       SmartMenu.MenuName               = "Customer"
       SmartMenu.MenuStructureType      = "Item" 
       SmartMenu.FunctionGuid           = SmartFunction.FunctionGuid .       

Complete sample code

Here's the complete sample code that creates the following entry in the menu structure:

Complete sample
/* ***************************  Definitions  ************************** */
USING Consultingwerk.SmartFramework.* FROM PROPATH.

DEFINE VARIABLE oCallParameter AS RunProcedureCallParameter NO-UNDO .  
DEFINE VARIABLE cRootMenuGuid    AS CHARACTER NO-UNDO.
DEFINE VARIABLE cParentMenuGuid  AS CHARACTER NO-UNDO.

/* ***************************  Main Block  *************************** */

/* find the module record */
FIND SmartModule WHERE SmartModule.ModuleName = "legacy" .

/* create menu function record */
ASSIGN 
    oCallParameter = NEW RunProcedureCallParameter () 
    oCallParameter:AllowMultiple                        = FALSE 
    oCallParameter:ProcedureName                        = "windows/cust.w"
    oCallParameter:RunPersistent                        = TRUE
    oCallParameter:InitializeInternalProcedure          = "dispatch"
    oCallParameter:InitializeInternalProcedureParameter = "initialize"
    oCallParameter:ReactivateInternalProcedure          = "dispatch"
    oCallParameter:ReactivateInternalProcedureParameter = "view"
    .
CREATE SmartFunction . 
ASSIGN SmartFunction.FunctionName          = "Sample function"
       SmartFunction.FunctionDescription   = "Imported menu function" 
       SmartFunction.FunctionModuleGuid    = SmartModule.ModuleGuid 
       SmartFunction.FunctionCallParameter = oCallParameter:Serialize() .
FIND CURRENT SmartFunction NO-LOCK . 

/* Create/find menu structure */       
       
/* root menu structrue */
FIND SmartMenu WHERE SmartMenu.ParentMenuGuid = ""
                 AND SmartMenu.MenuName       = "Advantzware" NO-LOCK .
ASSIGN cRootMenuGuid = SmartMenu.MenuGuid . 


/* Find or create "master data" menu */
FIND SmartMenu WHERE SmartMenu.ParentMenuGuid = cRootMenuGuid
                 AND SmartMenu.MenuName       = "Master data" NO-ERROR .
       
IF NOT AVAILABLE SmartMenu THEN DO: 
    CREATE SmartMenu.
    ASSIGN SmartMenu.ParentMenuGuid         = cRootMenuGuid
           SmartMenu.MenuName               = "Master data"
           SmartMenu.MenuStructureType      = "Menu" .
    FIND CURRENT SmartMenu NO-LOCK . 
END.           
           
ASSIGN cParentMenuGuid = SmartMenu.MenuGuid .
       
/* Create an item menu structure under master data */       
CREATE SmartMenu.
ASSIGN SmartMenu.ParentMenuGuid         = cParentMenuGuid
       SmartMenu.MenuName               = "Customer"
       SmartMenu.MenuStructureType      = "Item" 
       SmartMenu.FunctionGuid           = SmartFunction.FunctionGuid .