Steps to migrate from the legacy SmartFramework menu rendering to the new implementation

Add method to get a configured instance of the MainMenuRenderer class

The NewMainMenuRenderer method is used to create a new instance of the MainMenuRenderer class and configure it with the settings of your Main Menu Form. If you want to customize the rendering of the menu you can create a class that implements the IMainMenuRenderer interface and create an instance of that class here.

In the reference implementation of the MainMenuRenderer there are settings to customize the default behaviour

PropertyDefault ValueDescription
ConstantExplorerBarGroups""

Comma delimeted list of constant ExplorerBarGroups that do not get removed if the user is not authorized to see them

MenuTreeViewControlSortAlphabeticalFALSE

Defines sorting of MenuTreeViewControl. When menu should be sorted by alphabet and not by menu structure provider

RenderRecentGroupTRUEIndicates if the list of last recently used MenuItems should be rendered

 

 

GetConfiguredMainMenuRenderer
/*------------------------------------------------------------------------------
    Purpose: Creates and configures a new instance of the MainMenuRenderer class
    Notes:
    @return The configured instance of the MainMenuRenderer class
------------------------------------------------------------------------------*/
METHOD PUBLIC IMainMenuRenderer NewMainMenuRenderer ():

    DEFINE VARIABLE oMainMenuRenderer AS MainMenuRenderer NO-UNDO.

    oMainMenuRenderer = NEW MainMenuRenderer ().

    oMainMenuRenderer:ConstantExplorerBarGroups = "":U.
    oMainMenuRenderer:MenuTreeViewControlSortAlphabetical = FALSE.
    oMainMenuRenderer:RenderRecentGroup = TRUE.

    RETURN oMainMenuRenderer.

END METHOD .

 

Replace legacy rendering code from AfterShownHandler with the call to MainMenuRenderer

The previous implementation of rendering the Main Menu is located in the AfterShownHandler method. To migrate this method some changes are needed.

Define a new variable for the IMainMenuRenderer instance as follows

Variable definition
DEFINE VARIABLE oMainMenuRenderer AS IMainMenuRenderer NO-UNDO .

 

The previous SmartFramework rendering code looks similar to the following code block. However it should be surrounded by "&IF DEFINED (SmartFramework) NE 0 &THEN" and "&ENDIF". This block can be replaced with the call to the MainMenuRenderer class.

legacy menu rendering code
&IF DEFINED (SmartFramework) NE 0 &THEN
        ultraExplorerBar1:SuspendLayout() .

        Consultingwerk.Windows.API.Win32:LockWindowUpdate (THIS-OBJECT) .

        THIS-OBJECT:InitializeRecentlyUsedMenuItemsGroup ("Recent":U,
                                                          "Recent"{&TRAN},
                                                          "Consultingwerk/Windows/Framework/Images/step_16.png":U,
                                                          "Consultingwerk/Windows/Framework/Images/step_32.png":U,
                                                          0) .

        ASSIGN i = 1 .

        DEFINE VARIABLE oGroups AS CharacterHolder NO-UNDO .

        IF SessionManager:UserGroupKeys > "":U THEN DO:
            oGroups = NEW CharacterHolder (SessionManager:UserGroupKeys) .

            FrameworkSettings:ServiceAdapter:InvokeMethod ("":U,
                                                           "Consultingwerk.SmartFramework.Menu.MenuBusinessEntity":U,
                                                           "GetMenusForGroups":U,
                                                           INPUT-OUTPUT DATASET dsMenu,
                                                           oGroups) .

            FOR EACH eSmartMenu WHERE eSmartMenu.MenuStyleCode = "":U
                                   OR eSmartMenu.MenuStyleCode = "TREE":U
                                   OR eSmartMenu.MenuStyleCode = "EXPLORERBAR":U
                                   OR eSmartMenu.MenuStyleCode = "TASKLIST":U
                                BY eSmartMenu.MenuSequence:

                IF eSmartMenu.MenuStyleCode = "":U OR
                   eSmartMenu.MenuStyleCode = "TREE":U THEN

                THIS-OBJECT:InitializeExplorerBarGroup (eSmartMenu.MenuGuid,
                                                        eSmartMenu.MenuName,
                                                        eSmartMenu.MenuGuid,
                                                        eSmartMenu.MenuSmallImage,
                                                        eSmartMenu.MenuLargeImage,
                                                        i,
                                                        FALSE) .

                ELSE IF eSmartMenu.MenuStyleCode = "EXPLORERBAR":U THEN
                    THIS-OBJECT:InitializeNativeExplorerBarGroup (eSmartMenu.MenuGuid,
                                                                  eSmartMenu.MenuName,
                                                                  eSmartMenu.MenuGuid,
                                                                  eSmartMenu.MenuSmallImage,
                                                                  eSmartMenu.MenuLargeImage,
                                                                  i) .

                ELSE THIS-OBJECT:InitializeTaskList (eSmartMenu.MenuGuid,
                                                     eSmartMenu.MenuName,
                                                     eSmartMenu.MenuGuid,
                                                     eSmartMenu.MenuSmallImage,
                                                     eSmartMenu.MenuLargeImage,
                                                     i) .

                i = i + 1 .
            END.

            FOR EACH eSmartMenu WHERE eSmartMenu.MenuStyleCode = "RIBBON":U
                    BY eSmartMenu.MenuSequence:

                THIS-OBJECT:InitializeRibbonTab (eSmartMenu.MenuGuid) .
            END.

        END.

        Consultingwerk.Windows.API.Win32:LockWindowUpdate (0) .

        ultraExplorerBar1:ResumeLayout(TRUE) .
&ENDIF

 

Replace this code with the new code block calling the MainMenuRenderer 

MainMenuRenderer call
oMainMenuRenderer = NewMainMenuRenderer ().
oMainMenuRenderer:RenderMenuStructure (THIS-OBJECT:ultraExplorerBar1,
                                       THIS-OBJECT:smartToolbarController1,
                                       THIS-OBJECT).

 

At the end of the method a finally block needs to be inserted if not already existing, to cleanup the instance of the MainMenuRenderer class.

Finally
FINALLY:
    GarbageCollectorHelper:DeleteObject (oMainMenuRenderer).
END FINALLY.


However please review the method for unused variables. From the reference implementation there is the "i" variable that is no longer needed and schould be removed

 

Remove no longer used includes of the dsMenuGroup and dsMenu ProDatasets

If there is no custom code using these two ProDatasets anymore these includes can be removed from the form source code. All customizations should be moved to a MainMenuRenderer derived customization class as mentioned in section 1.

ProDataset includes
&IF DEFINED (SmartFramework) NE 0 &THEN
    { Consultingwerk/SmartFramework/Authorization/dsMenuGroup.i }
    { Consultingwerk/SmartFramework/Menu/dsMenu.i }
&ENDIF

 

Implement functionality to reload the complete menu

If applicable remove the method “ReloadMenu” and replace the call in smartToolbarController1_ToolClick event handler method with the call to the MainMenuRenderer instance as shown in section 2. There is no specialized method to reload the menu. The RenderMenuStructure method will refresh the current menu controls and Ribbon tabs, remove groups and tabs that are not accessible anymore and add newly accessible ones.

Variable definition
DEFINE VARIABLE oMainMenuRenderer AS IMainMenuRenderer NO-UNDO .
ToolClick code
WHEN "Reload Menu":U THEN DO:
    oMainMenuRenderer = NewMainMenuRenderer ().
    oMainMenuRenderer:RenderMenuStructure (THIS-OBJECT:ultraExplorerBar1,
                                           THIS-OBJECT:smartToolbarController1,
                                           THIS-OBJECT).
END.
Finally
FINALLY:
    GarbageCollectorHelper:DeleteObject (oMainMenuRenderer).
END FINALLY.