VERSION 5.00
Object = "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}#2.1#0"; "mscomctl.OCX"
Begin VB.UserControl SPA_Admin_Navig 
   ClientHeight    =   10500
   ClientLeft      =   0
   ClientTop       =   0
   ClientWidth     =   16965
   ScaleHeight     =   10500
   ScaleWidth      =   16965
   Begin VB.Frame fra_MainItem 
      Caption         =   "   #Market - Product link 2"
      Height          =   9090
      Index           =   5
      Left            =   2445
      TabIndex        =   32
      Tag             =   "fra_ProductGroup2"
      Top             =   975
      Visible         =   0   'False
      Width           =   9810
      Begin VB.Frame fra_MainFilter 
         BorderStyle     =   0  'None
         Height          =   8760
         Index           =   5
         Left            =   120
         TabIndex        =   34
         Tag             =   "fra_MainFilter3"
         Top             =   225
         Width           =   3855
         Begin VB.CommandButton cmd_TVReLoad 
            Height          =   735
            Index           =   5
            Left            =   30
            Style           =   1  'Graphical
            TabIndex        =   38
            Tag             =   "cmd_TVReLoad"
            Top             =   870
            Visible         =   0   'False
            Width           =   735
         End
         Begin VB.CheckBox chk_inclSpecialProducts 
            Caption         =   "#Include special products"
            Height          =   375
            Left            =   30
            TabIndex        =   37
            Tag             =   "chk_inclSpecPrd"
            Top             =   0
            Width           =   3825
         End
         Begin Project1.ArmCombobox cbo_View 
            Height          =   345
            Index           =   5
            Left            =   0
            TabIndex        =   39
            Top             =   360
            Width           =   3870
            _ExtentX        =   6826
            _ExtentY        =   609
         End
         Begin Project1.ArmTreeView tvw_Main 
            Height          =   7740
            Index           =   5
            Left            =   30
            TabIndex        =   40
            Top             =   870
            Width           =   3825
            _ExtentX        =   6747
            _ExtentY        =   13653
         End
      End
      Begin VB.PictureBox pic_filtersReset 
         Appearance      =   0  'Flat
         AutoSize        =   -1  'True
         BackColor       =   &H80000005&
         BorderStyle     =   0  'None
         ForeColor       =   &H80000008&
         Height          =   240
         Index           =   5
         Left            =   -30
         Picture         =   "SPA_Admin_Navig.ctx":0000
         ScaleHeight     =   16
         ScaleMode       =   3  'Pixel
         ScaleWidth      =   16
         TabIndex        =   33
         Top             =   90
         Width           =   240
      End
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   5
         Left            =   4080
         TabIndex        =   35
         Tag             =   "grd_PG_MKT2"
         Top             =   1020
         Width           =   10140
         _ExtentX        =   17886
         _ExtentY        =   15319
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   5
         Left            =   4080
         TabIndex        =   36
         Top             =   255
         Width           =   10170
         _ExtentX        =   17939
         _ExtentY        =   1217
      End
   End
   Begin VB.Frame fra_MainItem 
      Caption         =   "   Market - Product link "
      Height          =   3585
      Index           =   4
      Left            =   8055
      TabIndex        =   25
      Tag             =   "fra_ProductGroup"
      Top             =   5970
      Visible         =   0   'False
      Width           =   4395
      Begin VB.PictureBox pic_filtersReset 
         Appearance      =   0  'Flat
         AutoSize        =   -1  'True
         BackColor       =   &H80000005&
         BorderStyle     =   0  'None
         ForeColor       =   &H80000008&
         Height          =   240
         Index           =   4
         Left            =   -30
         Picture         =   "SPA_Admin_Navig.ctx":0542
         ScaleHeight     =   16
         ScaleMode       =   3  'Pixel
         ScaleWidth      =   16
         TabIndex        =   26
         Top             =   90
         Width           =   240
      End
      Begin VB.Frame fra_MainFilter 
         Height          =   2595
         Index           =   4
         Left            =   120
         TabIndex        =   27
         Tag             =   "fra_MainFilter3"
         Top             =   225
         Width           =   3855
         Begin Project1.ArmCombobox cbo_filterMKT2 
            Height          =   345
            Left            =   120
            TabIndex        =   31
            Tag             =   "SPM_Code"
            Top             =   720
            Width           =   3615
            _ExtentX        =   6376
            _ExtentY        =   609
         End
         Begin VB.Label lbl_Label 
            Caption         =   "#Authorization Market"
            Height          =   255
            Index           =   3
            Left            =   120
            TabIndex        =   28
            Tag             =   "lbl_filterMKT"
            Top             =   360
            Width           =   3615
         End
      End
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   4
         Left            =   4080
         TabIndex        =   29
         Tag             =   "grd_PG_MKT"
         Top             =   1020
         Width           =   10140
         _ExtentX        =   17886
         _ExtentY        =   15319
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   4
         Left            =   4080
         TabIndex        =   30
         Top             =   255
         Width           =   10170
         _ExtentX        =   17939
         _ExtentY        =   1217
      End
   End
   Begin VB.Frame fra_MainItem 
      Caption         =   "    ProductGroup - Market link"
      Height          =   3585
      Index           =   3
      Left            =   720
      TabIndex        =   19
      Tag             =   "fra_ProductGroup"
      Top             =   5550
      Visible         =   0   'False
      Width           =   4395
      Begin VB.PictureBox pic_filtersReset 
         Appearance      =   0  'Flat
         AutoSize        =   -1  'True
         BackColor       =   &H80000005&
         BorderStyle     =   0  'None
         ForeColor       =   &H80000008&
         Height          =   240
         Index           =   3
         Left            =   -30
         Picture         =   "SPA_Admin_Navig.ctx":0A84
         ScaleHeight     =   16
         ScaleMode       =   3  'Pixel
         ScaleWidth      =   16
         TabIndex        =   21
         Top             =   90
         Width           =   240
      End
      Begin VB.Frame fra_MainFilter 
         Height          =   2595
         Index           =   3
         Left            =   120
         TabIndex        =   20
         Tag             =   "fra_MainFilter3"
         Top             =   240
         Width           =   3855
         Begin Project1.ArmCombobox cbo_filterMKT 
            Height          =   345
            Left            =   120
            TabIndex        =   1
            Tag             =   "SPM_Code"
            Top             =   720
            Width           =   3615
            _ExtentX        =   6376
            _ExtentY        =   609
         End
         Begin Project1.ArmCombobox cbo_filterPG 
            Height          =   345
            Left            =   120
            TabIndex        =   2
            Tag             =   "SPG_Code"
            Top             =   1680
            Width           =   3615
            _ExtentX        =   6376
            _ExtentY        =   609
         End
         Begin VB.Label lbl_Label 
            Caption         =   "#Product group"
            Height          =   255
            Index           =   2
            Left            =   120
            TabIndex        =   24
            Tag             =   "lbl_filterPG"
            Top             =   1320
            Width           =   3615
         End
         Begin VB.Label lbl_Label 
            Caption         =   "#Authorization Market"
            Height          =   255
            Index           =   1
            Left            =   120
            TabIndex        =   23
            Tag             =   "lbl_filterMKT"
            Top             =   360
            Width           =   3615
         End
      End
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   3
         Left            =   4080
         TabIndex        =   3
         Tag             =   "grd_PG_MKT"
         Top             =   1020
         Width           =   10140
         _ExtentX        =   17886
         _ExtentY        =   15319
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   3
         Left            =   4080
         TabIndex        =   22
         Top             =   255
         Width           =   10170
         _ExtentX        =   17939
         _ExtentY        =   1217
      End
   End
   Begin VB.Frame fra_MainItem 
      Caption         =   "    Market - user link"
      Height          =   3570
      Index           =   0
      Left            =   360
      TabIndex        =   14
      Tag             =   "fra_MarketUserLink"
      Top             =   480
      Visible         =   0   'False
      Width           =   4305
      Begin VB.Frame fra_MainFilter 
         Height          =   675
         Index           =   0
         Left            =   120
         TabIndex        =   17
         Tag             =   "fra_MainFilter0"
         Top             =   240
         Width           =   3855
         Begin VB.CheckBox chk_onlyExisting 
            Caption         =   "Only existing"
            Height          =   255
            Left            =   120
            TabIndex        =   4
            Tag             =   "chk_OnlyExisting"
            Top             =   240
            Value           =   1  'Checked
            Width           =   3615
         End
      End
      Begin VB.PictureBox pic_filtersReset 
         Appearance      =   0  'Flat
         AutoSize        =   -1  'True
         BackColor       =   &H80000005&
         BorderStyle     =   0  'None
         ForeColor       =   &H80000008&
         Height          =   240
         Index           =   0
         Left            =   -30
         Picture         =   "SPA_Admin_Navig.ctx":0FC6
         ScaleHeight     =   16
         ScaleMode       =   3  'Pixel
         ScaleWidth      =   16
         TabIndex        =   16
         Top             =   90
         Width           =   240
      End
      Begin VB.CommandButton cmd_TVReLoad 
         Height          =   735
         Index           =   0
         Left            =   0
         Style           =   1  'Graphical
         TabIndex        =   15
         Tag             =   "cmd_TVReLoad"
         Top             =   1560
         Visible         =   0   'False
         Width           =   735
      End
      Begin Project1.ArmCombobox cbo_View 
         Height          =   345
         Index           =   0
         Left            =   150
         TabIndex        =   5
         Top             =   1140
         Width           =   3870
         _ExtentX        =   6826
         _ExtentY        =   609
      End
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   0
         Left            =   4080
         TabIndex        =   7
         Tag             =   "grd_MarketUser"
         Top             =   1020
         Width           =   10140
         _ExtentX        =   17886
         _ExtentY        =   15319
      End
      Begin Project1.ArmTreeView tvw_Main 
         Height          =   8160
         Index           =   0
         Left            =   90
         TabIndex        =   6
         Top             =   1605
         Width           =   3825
         _ExtentX        =   6747
         _ExtentY        =   14393
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   0
         Left            =   4080
         TabIndex        =   18
         Top             =   255
         Width           =   10170
         _ExtentX        =   17939
         _ExtentY        =   1217
      End
   End
   Begin VB.Frame fra_MainItem 
      Caption         =   "Authorisation Market "
      Height          =   2430
      Index           =   2
      Left            =   6615
      TabIndex        =   11
      Tag             =   "fra_AuthorisationMarket"
      Top             =   720
      Visible         =   0   'False
      Width           =   4620
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   2
         Left            =   120
         TabIndex        =   12
         Tag             =   "grd_AuthMarket"
         Top             =   1080
         Width           =   14100
         _ExtentX        =   24871
         _ExtentY        =   15319
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   2
         Left            =   120
         TabIndex        =   13
         Top             =   255
         Width           =   14130
         _ExtentX        =   24924
         _ExtentY        =   1217
      End
   End
   Begin VB.Frame fra_MainItem 
      Caption         =   "Product group "
      Height          =   2880
      Index           =   1
      Left            =   7455
      TabIndex        =   8
      Tag             =   "fra_ProductGroup"
      Top             =   3420
      Visible         =   0   'False
      Width           =   4275
      Begin Project1.ArmGrid grd_Main 
         Height          =   8685
         Index           =   1
         Left            =   120
         TabIndex        =   9
         Tag             =   "grd_ProductGroup"
         Top             =   1080
         Width           =   14100
         _ExtentX        =   24871
         _ExtentY        =   15319
      End
      Begin Project1.ToolbarControl tlb_Main 
         Height          =   690
         Index           =   1
         Left            =   120
         TabIndex        =   10
         Top             =   255
         Width           =   14130
         _ExtentX        =   24924
         _ExtentY        =   1217
      End
   End
   Begin MSComctlLib.TabStrip tbs_Main 
      Height          =   375
      Left            =   0
      TabIndex        =   0
      Tag             =   "tbs_Main"
      Top             =   0
      Width           =   10860
      _ExtentX        =   19156
      _ExtentY        =   661
      _Version        =   393216
      BeginProperty Tabs {1EFB6598-857C-11D1-B16A-00C0F0283628} 
         NumTabs         =   1
         BeginProperty Tab1 {1EFB659A-857C-11D1-B16A-00C0F0283628} 
            ImageVarType    =   2
         EndProperty
      EndProperty
   End
End
Attribute VB_Name = "SPA_Admin_Navig"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

'what is new
'2.6.9 : new tab for products linked (JN)
'2.7.1 : Default product group - market link configuration for inserting new Base Items (JN)

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK API FUNCTION DECLARES
'**********************************************************************************************************************************
'**********************************************************************************************************************************
Private Declare Function GetLocaleInfo Lib "kernel32" Alias "GetLocaleInfoA" (ByVal Locale As Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function GetSystemDefaultLCID Lib "kernel32" () As Long
Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" _
   (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
Private Declare Function LoadIconFromDLL Lib "user32" Alias "LoadIconA" (ByVal hInstance As Long, ByVal lpIconName As Long) As Long
Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" (lpPictDesc As PictDesc, riid As Guid, ByVal fPictureOwnsHandle As Long, ipic As IPicture) As Long
Private Declare Function GetTempPath Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As Long, ByVal lpBuffer As String) As Long

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK CONSTANTS
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Private Const SEP = "®©"
Private Const SEP1 As String = "®"
Private Const SEP2 As String = "©"

Private Const SCREEN_NAME As String = "SPA_Admin_Navig"

Private Const LOCALE_USER_DEFAULT = &H400
Private Const LOCALE_SDECIMAL = &HE ' Decimal separator
Private Const LOCALE_STHOUSAND = &HF ' Thousand separator

Private Const CL_COLOR_ENABLED As Long = &H80000005
Private Const CL_COLOR_DISABLED As Long = &H8000000F
Private Const CL_COLOR_LOCKED As Long = &H80000018
Private Const C_ERRORRAISE As Long = 2500
Private Const ICON_RELOAD = 115
Private Const FRM_SPACE_VER = 120
Private Const FRM_SPACE_HOR = 100
Private Const STATUS_COLUMN = "Status"

'**********************************************************************************************************************************

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK VARIABLES
'**********************************************************************************************************************************
'**********************************************************************************************************************************


#If LIVE = 1 Then
    Dim mo_Db As Object
#Else
    Dim mo_Db As ARMSYSCOMLib.ArmDb
#End If

#If LIVE = 1 Then
    Dim mo_FSO As Object
#Else
    Dim mo_FSO As Scripting.FileSystemObject
#End If

Private ms_Language_Code                As String       'current user interface language
Private ml_U_Code                       As Long         'U_Code (GEN_Systems_Users) of logged user
Private ms_LoginName                    As String       'contain loginname
Private ms_UserName                     As String       'contain name of logged user as defined in GEN_People
Private mb_InternalInit                 As Boolean      'framework is doing some own control manipulation, all events should handle
Private mb_Initialized                  As Boolean      'framework is initialised or not
Private ms_DecimalSeparator             As String       'locale decimal separator
Private ms_ThousandSeparator            As String       'locale thousand separator
Private ms_Title                        As String       'title of user control - can be assigned as Caption to the parent form or title for printing
Private mt_MainConfig()                 As TMainConfig
Private mc_Toolbars                     As Long         'cursor which will contain all toolbars for current usercontrol
Private ms_ToolbarRequest               As String       'request which load all toolbars for current usercontrol
Private mc_ScreenLabels                 As Long         'cursor containing screen constants for current component


Private WithEvents mo_SPA_Admin_PG              As SPA_Admin_PG
Attribute mo_SPA_Admin_PG.VB_VarHelpID = -1
Private WithEvents mo_SPA_Admin_MKT             As SPA_Admin_MKT
Attribute mo_SPA_Admin_MKT.VB_VarHelpID = -1
Private WithEvents mo_SPA_Admin_MKT_USER        As SPA_Admin_MKT_USER
Attribute mo_SPA_Admin_MKT_USER.VB_VarHelpID = -1
Private WithEvents mo_SPA_Admin_PG_MKT          As SPA_Admin_PG_MKT
Attribute mo_SPA_Admin_PG_MKT.VB_VarHelpID = -1

'**********************************************************************************************************************************

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK CUSTOM TYPES
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Private Type PictDesc
    cbSizeofStruct As Long
    picType As Long
    hImage As Long
    xExt As Long
    yExt As Long
End Type

Private Type Guid
    Data1 As Long
    Data2 As Integer
    Data3 As Integer
    Data4(0 To 7) As Byte
End Type

Private Type TTreeViewInfo
    Levels As Long
    NodeRequest() As String
    GridRequest() As String
    ExcelRequest() As String
    CountRequest() As String
    FindRequest() As String
    Images() As Integer
    SelectedImages() As Integer
    TreeViewCode As String
    Loaded As Boolean
End Type

Private Enum ArmErr
    DBCnxFailed = C_ERRORRAISE + 1             ' Unable to connect to the database
    CPTAlreadyInitialized = C_ERRORRAISE + 2   ' We try to initialize a component that is already initialized
    CPTNotInitialized = C_ERRORRAISE + 3       ' We try to use or free that is not initialized yet
    InvalidArgument = C_ERRORRAISE + 4
    PropertyNotSet = C_ERRORRAISE + 5
    SQLFailure = C_ERRORRAISE + 6               ' A SQL runtime error has occured : syntax wrong....
    SQLBadRowAffectedCount = C_ERRORRAISE + 7   ' A SQL request has not affected the expected rowcount (ex: one Update do nothing)
    SQLBadRowExpectedCount = C_ERRORRAISE + 8   ' A SQL request does not return the expected rowcount : select an item return nothing...
    DrivingError = C_ERRORRAISE + 9
    CompFncFailed = C_ERRORRAISE + 10           ' when component function fail
    GridLoadFailed = C_ERRORRAISE + 11          ' load function failed ... bad sql
    InvalidValue = C_ERRORRAISE + 12          ' load function failed ... bad sql
End Enum

Private Const SIFYB_CM_ERROR_MESSAGE = 8000
Private Enum ArmCusErr
    NoError = 0
    DuplicityDetected = C_ERRORRAISE + 2301                ' detected row with same unique id
    WarMsgSelectRow = 2304
    ErrMsg_M000 = SIFYB_CM_ERROR_MESSAGE + 0                ' undefined message
    ErrMsg_M610 = SIFYB_CM_ERROR_MESSAGE + 610              'This configuration will be active from today or tomorrow and you cannot change it again today.
    ErrMsg_M700 = SIFYB_CM_ERROR_MESSAGE + 700              'User cannot be deleted as they are not defined in SPA System
End Enum

Private Type TMainConfig
    NameFrame                       As String
    ViewCode                        As String
    FrameIndex                      As Long
    IsMultiDetailView               As Boolean
    Initialized                     As Boolean
    ToolbarFace                     As String
    ToolbarIndex                    As Long
    ToolbarID                       As Long
    CurrentTvwSelMethod             As eTvwSelMethod
    GridDelayMethod                 As eGridLoadMethod
    GridDelayed                     As Boolean
    TreeDelayed                     As Boolean
    mTreeViewInfos()                As TTreeViewInfo
    MainGridColumns                 As Variant
    ActiveDetailControl             As Object
    HasTreeview                     As Boolean
    HasFilters                      As Boolean
    GridRequest                     As String
End Type

Private Enum eMode
    emNone
    emList
    emView
    emAdd
    emUpdate
    emDelete
End Enum

Private Enum eControlPropertyIndex
    cpiControl
    cpiTag
    cpiVisible
    cpiRequest
End Enum

Private Enum eControlAction
    caDoubleClick
    caClick
    caSelect
    caLoad
End Enum

' The different way to select data in the treeview
Private Enum eTvwSelMethod
    etmNone = 0
    etmNode = 1         ' User click on the last node of a branch
    etmBranch = 2       ' User click on a branch and use the load button
    etmCheckBoxes = 3   ' User click on the load button when checkboxes mode is set
End Enum

Private Enum eGridLoadMethod
    egmDelayedAlways = 0
    egmDelayedExceptLastLevel = 1
    egmLoadAlways = 2
End Enum

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK EVENTS
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Public Event quit()

'**********************************************************************************************************************************

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK INTERFACE AND PROPERTIES
' please DO NOT change anything in this part of code
'**********************************************************************************************************************************
'**********************************************************************************************************************************
Public Property Let Visible(ByVal aVisible As Boolean)
    UserControl.Extender.Visible = aVisible
End Property
Public Property Get Visible() As Boolean
    Visible = UserControl.Extender.Visible
End Property
Public Property Let Top(ByVal aTop As Single)
    UserControl.Extender.Top = aTop
End Property
Public Property Get Top() As Single
    Top = UserControl.Extender.Top
End Property
Public Property Let Height(ByVal aHeight As Single)
    UserControl.Extender.Height = aHeight
End Property
Public Property Get Height() As Single
    Height = UserControl.Extender.Height
End Property
Public Property Let Left(ByVal aLeft As Single)
    UserControl.Extender.Left = aLeft
End Property
Public Property Get Left() As Single
    Left = UserControl.Extender.Left
End Property
Public Property Let Width(ByVal aWidth As Single)
    UserControl.Extender.Width = aWidth
End Property
Public Property Get Width() As Single
    Width = UserControl.Extender.Width
End Property
Public Sub Move(ByVal aLeft As Single, ByVal aTop As Single, ByVal aWidth As Single, ByVal aHeight As Single)
    Call UserControl.Extender.Move(aLeft, aTop, aWidth, aHeight)
End Sub
Public Property Get Initialized() As Boolean
    Initialized = mb_Initialized
End Property
Public Property Get Title() As String
    Title = ms_Title
End Property
Public Property Let U_Code(ByVal al_U_Code As Long)
On Error GoTo ErrHandler
    
    If Initialized Then Call Err.Raise(ArmErr.CPTAlreadyInitialized)
    
    ml_U_Code = al_U_Code
    Exit Property
ErrHandler:
    Call ErrorHandler("U_Code(Let)")
End Property

Public Property Let LoginName(ByVal as_LoginName As String)
On Error GoTo ErrHandler
    
    If Initialized Then Call Err.Raise(ArmErr.CPTAlreadyInitialized)
    
    ms_LoginName = as_LoginName
    Exit Property
ErrHandler:
    Call ErrorHandler("LoginName(Let)")
End Property

Public Property Let Language_Code(as_Language_Code As String)
On Error GoTo ErrHandler
    
    If Initialized Then Call Err.Raise(ArmErr.CPTAlreadyInitialized)
    If Len(as_Language_Code) <> 1 Then Call Err.Raise(ArmErr.InvalidArgument, "", "Language_code must contains only 1 char")
    
    ms_Language_Code = as_Language_Code
    Exit Property
ErrHandler:
    Call ErrorHandler("Language(Let)")
End Property

Public Property Set DB(ByRef ao_DB As ArmDb)
On Error GoTo ErrHandler
    
    If Initialized Then Call Err.Raise(ArmErr.CPTAlreadyInitialized)
    If ao_DB Is Nothing Then Call Err.Raise(ArmErr.InvalidArgument)
    
    Set mo_Db = ao_DB
    Exit Property
ErrHandler:
    Call ErrorHandler("Db(Set)")
End Property


'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK METHODS
' please DO NOT change anything in this part of code
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Private Function AddNewTab(ByRef ao_TabStrip As Object, ByVal as_Key As String, ByVal as_Tag As String, ByVal as_caption As String) As Object
On Error GoTo ErrHandler
    Dim lo_retTab As Object
    If (ao_TabStrip.Tabs.Count = 1) And (ao_TabStrip.Tabs(1).Tag = "") Then
        Set lo_retTab = ao_TabStrip.Tabs(1)
        lo_retTab.Key = as_Key
        lo_retTab.Tag = as_Tag
        lo_retTab.Caption = as_caption
    Else
        Set lo_retTab = ao_TabStrip.Tabs.Add(, as_Key, as_caption)
        lo_retTab.Tag = as_Tag
    End If

    Set AddNewTab = lo_retTab
    Exit Function
ErrHandler:
    Call ErrorHandler("AddNewTab")
End Function

Private Sub Load_ConfigInfo()
On Error GoTo ErrHandler

Dim ll_Index As Long
    
    ReDim mt_MainConfig(5)
    For ll_Index = 0 To UBound(mt_MainConfig)
        mt_MainConfig(ll_Index).GridDelayMethod = egmDelayedExceptLastLevel
        Set mt_MainConfig(ll_Index).ActiveDetailControl = Nothing
        mt_MainConfig(ll_Index).HasTreeview = False
        mt_MainConfig(ll_Index).HasFilters = False
    Next
    
    
    grd_Main(0).AllowExcelExport = True
    grd_Main(0).ExportTitles = True
    grd_Main(0).ExportOnlyVisibleColumns = True
    grd_Main(0).Title = "#Market - User Link"
    With mt_MainConfig(0)
        .HasFilters = True
        .HasTreeview = True
        .FrameIndex = 0
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_MKT_USER"
        .ViewCode = "SPA_Admin_MKT_USER"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_MKT_USER_ID
        .MainGridColumns = Array( _
            "U_Code®©600®©1®©U_Code®©#U_Code", _
            "P_Name®©1700®©0®©P_Name®©#Last Name", _
            "P_First_Name®©1700®©0®©P_First_Name®©#First Name", _
            "SPR_SDesc®©2500®©0®©SPR_SDesc®©#Role", _
            "MarketCount®©0®©0®©MarketCount®©#MarketCount", _
            "SPR_Code®©0®©0®©SPR_Code®©#SPR Code")
    End With
    
    grd_Main(1).AllowExcelExport = True
    grd_Main(1).ExportTitles = True
    grd_Main(1).ExportOnlyVisibleColumns = True
    grd_Main(1).Title = "#Products groups"
    With mt_MainConfig(1)
        .FrameIndex = 1
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_PG"
        .ViewCode = "SPA_PG"
        .GridRequest = "SPA_PG_Lst"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_PG_ID
        .MainGridColumns = Array( _
            "SPG_Code®©0®©1®©SPG_Code®©#ID", _
            "SPG_SDesc®©3000®©0®©SPG_SDesc®©#Short Description", _
            "SPG_Desc®©7000®©0®©SPG_Desc®©#Description" _
            )
    End With
    
    grd_Main(2).AllowExcelExport = True
    grd_Main(2).ExportTitles = True
    grd_Main(2).ExportOnlyVisibleColumns = True
    grd_Main(2).Title = "#Authorization markets"
    With mt_MainConfig(2)
        .FrameIndex = 2
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_MKT"
        .ViewCode = "SPA_MKT"
        .GridRequest = "SPA_MKT_Lst"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_MKT_ID
        .MainGridColumns = Array( _
            "SPM_Code®©0®©1®©SPM_Code®©#SPM_Code", _
            "SPM_SDesc®©3000®©0®©SPM_SDesc®©#Short description", _
            "SPM_Desc®©7000®©0®©SPM_Desc®©#description" _
            )
    End With
    
    grd_Main(3).AllowExcelExport = True
    grd_Main(3).ExportTitles = True
    grd_Main(3).ExportOnlyVisibleColumns = True
    grd_Main(3).Title = "#Product Group - Market Link"
    With mt_MainConfig(3)
        .HasFilters = True
        .FrameIndex = 3
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_PG_MKT"
        .ViewCode = "SPA_PG_MKT"
        .GridRequest = "SPA_PG_MKT_Lst $SPG_Code$,$SPM_Code$"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_PG_MKT_ID
        .MainGridColumns = Array( _
            "SPGAM_Id®©0®©1®©SPGAM_Id®©#SPGAM_Id", _
            "SPM_SDesc®©3000®©0®©SPM_SDesc®©#Market short Description", _
            "SPG_SDesc®©3000®©0®©SPG_SDesc®©#Product short Description", _
            "isDefault®©1000®©0®©SPG_DefaultOld®©#Default", _
            "isActive®©1000®©0®©isActive®©#Active", _
            "VDate_End®©1000®©0®©VDate_End®©#VDate_End®©Date" _
            )
'            "SPM_Desc®©3000®©0®©SPM_Desc®©#Market Description",
'            "SPG_Desc®©3000®©0®©SPG_Desc®©#Product Description",
    End With
    
    grd_Main(4).AllowExcelExport = True
    grd_Main(4).ExportTitles = True
    grd_Main(4).ExportOnlyVisibleColumns = True
    grd_Main(4).Title = "#Product Group - Market Link 2"
    With mt_MainConfig(4)
        .HasFilters = True
        .FrameIndex = 4
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_PG_MKT_BI"
        .ViewCode = "SPA_PG_MKT_BI"
        .GridRequest = "SPA_PG_MKT_Lst2 $SPM_Code$"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_PG_MKT_ID2
        .MainGridColumns = Array( _
            "SPGAM_Id®©0®©1®©SPGAM_Id®©#SPGAM_Id", _
            "SPM_SDesc®©2000®©0®©SPM_SDesc®©#Market short Description", _
            "SPG_SDesc®©2000®©0®©SPG_SDesc®©#Product Group", _
            "BI_SAP_Code®©1000®©1®©BI_SAP_Code®©#BI_SAP_Code", _
            "BI_Desc®©3000®©0®©BI_Desc®©#Product Description", _
            "L1Discount®©1000®©0®©L1Discount®©#REP®©Float®©" & PERCENT_FORMAT, _
            "L2Discount®©1000®©0®©L2Discount®©#ASM®©Float®©" & PERCENT_FORMAT, _
            "L3Discount®©1000®©0®©L3Discount®©#FSM®©Float®©" & PERCENT_FORMAT, _
            "L4Discount®©1000®©0®©L4Discount®©#CSM®©Float®©" & PERCENT_FORMAT, _
            "L5Discount®©1000®©0®©L5Discount®©#GSM®©Float®©" & PERCENT_FORMAT, _
            "L6Discount®©1000®©0®©L6Discount®©#MDS®©Float®©" & PERCENT_FORMAT, _
            "L8Discount®©1000®©0®©L8Discount®©#SVPE®©Float®©" & PERCENT_FORMAT _
            )
    End With
    
    grd_Main(5).AllowExcelExport = True
    grd_Main(5).ExportTitles = True
    grd_Main(5).ExportOnlyVisibleColumns = True
    grd_Main(5).Title = "#Product Group - Market Link 3"
    With mt_MainConfig(5)
        .HasFilters = True
        .HasTreeview = True
        .FrameIndex = 5
        .IsMultiDetailView = False
        .Initialized = False
        .NameFrame = "SPA_PG_MKT_BI2"
        .ViewCode = "SPA_Admin_PG_MKT_BI2"
        .GridRequest = "SPA_PG_MKT_Lst3 $SPG_Code$,$SPM_Code$, $BI_SAP_CODE$"
        .ToolbarFace = "0"
        .ToolbarIndex = 0
        .ToolbarID = TLB_SPA_PG_MKT_ID3
        .MainGridColumns = Array( _
            "SPGAM_Id®©0®©1®©SPGAM_Id®©#SPGAM_Id", _
            "SPM_SDesc®©2000®©0®©SPM_SDesc®©#Market short Description", _
            "SPG_SDesc®©2000®©0®©SPG_SDesc®©#Product short Description", _
            "BI_SAP_Code®©1000®©1®©BI_SAP_Code®©#BI_SAP_Code", _
            "BI_Desc®©3000®©0®©BI_Desc®©#Product Description", _
            "L1Discount®©1000®©0®©L1Discount®©#REP®©Float®©" & PERCENT_FORMAT, _
            "L2Discount®©1000®©0®©L2Discount®©#ASM®©Float®©" & PERCENT_FORMAT, _
            "L3Discount®©1000®©0®©L3Discount®©#FSM®©Float®©" & PERCENT_FORMAT, _
            "L4Discount®©1000®©0®©L4Discount®©#CSM®©Float®©" & PERCENT_FORMAT, _
            "L5Discount®©1000®©0®©L5Discount®©#GSM®©Float®©" & PERCENT_FORMAT, _
            "L6Discount®©1000®©0®©L6Discount®©#MDS®©Float®©" & PERCENT_FORMAT, _
            "L8Discount®©1000®©0®©L8Discount®©#SVPE®©Float®©" & PERCENT_FORMAT _
            )
    
    End With
    
    For ll_Index = 0 To UBound(mt_MainConfig)
        If mt_MainConfig(ll_Index).HasTreeview Then
            cmd_TVReLoad(ll_Index).Picture = LoadIconFromA_Icons(ICON_RELOAD)
            Call SetTreeDelayedMode(mt_MainConfig(ll_Index).FrameIndex, False)
        End If
    Next
    Exit Sub
ErrHandler:
    Call ErrorMessage("Load_ConfigInfo")
End Sub
    
Private Function tlb_Main_CustomAction(Index As Integer, ByVal as_Role As String, as_Language As String) As Boolean
On Error GoTo ErrHandler
    tlb_Main_CustomAction = False
    Exit Function
ErrHandler:
    Call ErrorHandler("tlb_Main_CustomAction")
End Function

Private Function grd_Main_CustomAction(Index As Integer, ByVal ae_Action As eControlAction) As Boolean
On Error GoTo ErrHandler
    Dim ll_frameIndex As Long
    
    Call InitDetailControl(Index)
    ll_frameIndex = mt_MainConfig(Index).FrameIndex
    
    Select Case ae_Action
        Case eControlAction.caDoubleClick
        ' load detail
        If Not mt_MainConfig(Index).ActiveDetailControl Is Nothing Then
            Call mt_MainConfig(Index).ActiveDetailControl.Run(SPA_Mode.emView, grd_Main(ll_frameIndex).CurrentKey)
            mt_MainConfig(Index).ActiveDetailControl.Visible = True
        End If
    Case Else
        Debug.Assert (False)
    End Select

    grd_Main_CustomAction = True
    Exit Function
ErrHandler:
    Call ErrorHandler("grd_Main_CustomAction")
End Function

Private Function Resize_Custom() As Boolean
On Error GoTo ErrHandler

    Resize_Custom = False
    Exit Function
ErrHandler:
    Call ErrorHandler("Resize_Custom")
End Function

Private Function IsItemInFilterCustom(ByRef ao_data As Dictionary, ByVal al_MainConfig As Long, ByRef ab_CheckDone As Boolean) As Boolean
On Error GoTo ErrHandler
    ab_CheckDone = False
    IsItemInFilterCustom = False
    Dim lb_retVal As Boolean
    lb_retVal = False
    
    Select Case al_MainConfig
    Case 0  ' SPA_MKT_USER
    Case 1  ' SPA_PG
    Case 2  ' SPA_MKT
    Case 3  ' SPA_PG_MKT
        ' check market
        Dim ls_Key As String
        
        ls_Key = GetComboKey(cbo_filterMKT)
        lb_retVal = ((ls_Key = "") Or (ls_Key = ao_data.Item("MKT_Code")))
        
        ' check PG
        If lb_retVal Then
            ls_Key = GetComboKey(cbo_filterPG)
            lb_retVal = ((ls_Key = "") Or (ls_Key = ao_data.Item("PG_Code")))
        End If
        
        ab_CheckDone = True
    Case Else
        Debug.Print ("IsItemInFilterCustom: invalid al_MainConfig")
    End Select

    IsItemInFilterCustom = lb_retVal
    Exit Function
ErrHandler:
    Call ErrorHandler("IsItemInFilterCustom")
End Function

Private Function IsItemSelectedInTreeCustom(ByVal al_DetailIndex As Long, ByRef ao_Tree As ArmTreeView, ByVal av_PathData As Variant, ByRef ab_CheckDone As Boolean) As Boolean

    IsItemSelectedInTreeCustom = False
    ab_CheckDone = False
    
    Exit Function
ErrHandler:
    Call ErrorHandler("IsItemSelectedInTreeCustom")
End Function

Private Sub SetDisabledDetailControls()
On Error GoTo ErrHandler

    Exit Sub
ErrHandler:
    Call ErrorHandler("SetDisabledDetailControls")
End Sub

Private Sub FillDataSrcArray(ByRef ao_dataSrc As Dictionary, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    
    Dim ll_i As Long
    Dim lsa_DataFields() As String
    Dim lv_Values As Variant
    lsa_DataFields = Split(as_SrzFields, SEP)
    
    For ll_i = LBound(lsa_DataFields) To UBound(lsa_DataFields)
        lv_Values = Split(lsa_DataFields(ll_i), SEP1)
        If UBound(lv_Values) >= 1 Then
            If lv_Values(0) <> "" Then
                If ao_dataSrc.Exists(lv_Values(0)) = False Then
                    If UBound(lv_Values) = 1 Then
                        Call ao_dataSrc.Add(lv_Values(0), lv_Values(1))
                    Else
                        Call ao_dataSrc.Add(lv_Values(0), lv_Values)
                    End If
                End If
            End If
        End If
    Next
    
    Exit Sub
ErrHandler:
    Call ErrorHandler("FillDataSrcArray")
End Sub

Private Function IsInArray(ByVal as_val As String, ByRef av_Array As Variant) As Boolean
On Error GoTo ErrHandler
    Dim ll_i As Long
    IsInArray = False
    For ll_i = LBound(av_Array) To UBound(av_Array)
        If StrComp(av_Array(ll_i), as_val, vbTextCompare) <> 0 Then Exit Function
    Next
    IsInArray = True
    Exit Function
ErrHandler:
    Call ErrorHandler("IsInArray")
End Function
Private Sub DeleteLineToGrid(ByVal ao_grid As ArmGrid, ByVal av_KeyFields As Variant, ByVal al_KeyVal As Variant)
On Error GoTo ErrHandler
    
    Dim ll_Col As Long
    Dim lo_Column As ArmColumn
    Dim lba_bckKeys() As Boolean
    Dim lv_bckKey As Variant
    ReDim lba_bckKeys(0 To ao_grid.Cols - 1)
    
    ' backup keys
    lv_bckKey = ao_grid.CurrentKey
    For ll_Col = 0 To ao_grid.Cols - 1
        Set lo_Column = ao_grid.Columns(ll_Col)
        lba_bckKeys(ll_Col) = lo_Column.Key
        lo_Column.Key = IsInArray(lo_Column.FieldName, av_KeyFields)
    Next

    ' delete all lines
    While ao_grid.SearchKey(True, al_KeyVal)
        ao_grid.DeleteLine
    Wend
    
    ' restore keys
    For ll_Col = 0 To ao_grid.Cols - 1
        ao_grid.Columns(ll_Col).Key = lba_bckKeys(ll_Col)
    Next
    Call ao_grid.SearchKey(True, lv_bckKey)

    Exit Sub
ErrHandler:
    Call ErrorHandler("DeleteLineToGrid")
End Sub

Private Function IsKeyRow(ByVal ao_grid As ArmGrid, ByVal al_Row As Long, ByVal av_keyCols As Variant, ByRef ao_dataSrc As Dictionary) As Boolean
On Error GoTo ErrHandler
    IsKeyRow = False
    Dim ll_i As Long
    For ll_i = LBound(av_keyCols) To UBound(av_keyCols)
        If StrComp(ao_grid.Data(al_Row, av_keyCols(ll_i)), ao_dataSrc(av_keyCols(ll_i)), vbTextCompare) <> 0 Then
            Exit Function
        End If
    Next
    IsKeyRow = True
    Exit Function
ErrHandler:
    Call ErrorHandler("IsKeyRow")
End Function


Private Sub UpdateLineToGrid(ByVal ao_grid As ArmGrid, ByRef ao_dataSrc As Dictionary, ByVal av_keyCols As Variant, Optional ByVal al_Color As Long = COLOR_UPDLINE)
On Error GoTo ErrHandler

    Debug.Assert (ao_grid.Cols > 0)
    Dim ll_Row As Long, ll_RowCount As Long, ll_Col As Long
    Dim lo_Column As ArmColumn
    
    ll_RowCount = ao_grid.Rows - 1
    For ll_Row = 0 To ll_RowCount
        If IsKeyRow(ao_grid, ll_Row, av_keyCols, ao_dataSrc) Then
            For ll_Col = 0 To ao_grid.Cols - 1
                Set lo_Column = ao_grid.Columns(ll_Col)
                If ao_dataSrc.Exists(lo_Column.FieldName) Then
                    Call lo_Column.SetData(ll_Row, ao_dataSrc(lo_Column.FieldName))
                End If
            Next
            ao_grid.LineColor(ll_Row) = al_Color
        End If
    Next

    Exit Sub
ErrHandler:
    Call ErrorHandler("UpdateLineToGrid")
End Sub

Private Sub AddLineToGrid(ByVal ao_grid As ArmGrid, ByRef ao_dataSrc As Dictionary)
On Error GoTo ErrHandler
    
    ' insert row at the end of grid
    Debug.Assert (ao_grid.Cols > 0)
    Dim lo_Column As ArmColumn
    Dim ll_Index As Long
    Dim lsa_newRow() As String
    ReDim lsa_newRow(0 To ao_grid.Cols - 1)
    
    Call ao_grid.DeselectRow
    
    For ll_Index = 0 To ao_grid.Cols - 1
        Set lo_Column = ao_grid.Columns(ll_Index)
        If ao_dataSrc.Exists(lo_Column.FieldName) Then
            lsa_newRow(ll_Index) = ao_dataSrc.Item(lo_Column.FieldName)
        Else
            lsa_newRow(ll_Index) = "TODO:"
        End If
    Next
    Call ao_grid.AddLine(lsa_newRow)
    ao_grid.LineColor(ao_grid.Row) = COLOR_ADDLINE
    
    Exit Sub
ErrHandler:
    Call ErrorHandler("AddLineToGrid")
End Sub
Private Function GetFieldValueFromSrz(ByVal as_SrzFields As String, ByVal as_Param As String) As String
On Error GoTo ErrHandler
    
    Dim lv_SrzFields As Variant
    Dim lv_Values
    Dim ll_Count As Long
    Dim ll_Nb As Long
       
    If right(as_SrzFields, 2) <> SEP Then as_SrzFields = as_SrzFields & SEP
       
    lv_SrzFields = Split(as_SrzFields, SEP)
    ll_Nb = UBound(lv_SrzFields) - 1

    For ll_Count = 0 To ll_Nb
        lv_Values = Split(lv_SrzFields(ll_Count), SEP1)
         If UCase(as_Param) = UCase(lv_Values(0)) Then
           GetFieldValueFromSrz = lv_Values(1)
           Exit For
         End If
    Next ll_Count
    
    Exit Function
ErrHandler:
    Call ErrorHandler("GetFieldValueFromSrz")
End Function

' parameter is nothing if all driven combo request should be set,
'it is control reference, if just driven controls request for specific control should be set
Private Sub SetDrivenDetailControls(ByRef ao_Control As Object)
On Error GoTo ErrHandler

    Call SetDisabledDetailControls
    Exit Sub
ErrHandler:
    Call ErrorHandler("SetDrivenDetailControls")
End Sub

Private Sub UpdateMainToolbarCustom(ByVal al_MainIndex As Long)
On Error GoTo ErrHandler
    Dim ll_frameIndex As Long
    Dim lb_isOwner As Boolean, lb_isCompleted As Boolean
    ll_frameIndex = mt_MainConfig(al_MainIndex).FrameIndex
    Select Case mt_MainConfig(al_MainIndex).NameFrame
        Case "SPA_PG"
        Case Else
    End Select

    Exit Sub
ErrHandler:
    Call ErrorHandler("UpdateMainToolbarCustom")
End Sub

Private Sub UpdateDetailToolbarCustom(ByVal al_Detailndex As Long)
On Error GoTo ErrHandler
    Exit Sub
ErrHandler:
    Call ErrorHandler("UpdateDetailToolbarCustom")
End Sub

Private Sub UpdateSubdetailToolbarCustom(ByVal al_Subdetailndex As Long)
On Error GoTo ErrHandler
    Exit Sub
ErrHandler:
    Call ErrorHandler("UpdateSubdetailToolbarCustom")
End Sub

Private Sub cbo_filterMKT2_ComboItemSelected()
On Error GoTo ErrHandler
    
    If mb_InternalInit Then Exit Sub
    
    Call ReloadMainFilterGrid
    Exit Sub
ErrHandler:
    Call ErrorMessage("cbo_filterMKT2_ComboItemSelected")
End Sub

Private Sub chk_inclSpecialProducts_Click()
On Error GoTo ErrHandler
    
    If mb_InternalInit Then Exit Sub
    
    Call cbo_View_ComboItemSelected(5)
    Exit Sub
ErrHandler:
    Call ErrorMessage("chk_inclSpecialProducts_Click")
End Sub

Private Sub mo_SPA_Admin_MKT_OnExit()
On Error GoTo ErrHandler
    Call X_OnExit("SPA_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnExit")
End Sub

Private Sub mo_SPA_Admin_MKT_OnItemAdd(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Call X_OnItemAdd("SPA_MKT", av_Key, as_SrzFields)
    ' propagate changes to Admin_PG_MKT
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
        ' new line must be inserted
        Call mo_SPA_Admin_PG_MKT.MKT_Updated(av_Key(0), lo_dataSrc.Item("SPM_SDesc"))
    End If
    
    Call cbo_Updated(cbo_filterMKT, av_Key(0), lo_dataSrc.Item("SPM_SDesc"))
    Set lo_dataSrc = Nothing
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemAdd")
End Sub

Private Sub mo_SPA_Admin_MKT_OnItemUpdate(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Call X_OnItemUpdate("SPA_MKT", av_Key, as_SrzFields)
    ' propagate changes to Admin_PG_MKT
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
        ' new line must be inserted
        Call mo_SPA_Admin_PG_MKT.MKT_Updated(av_Key(0), lo_dataSrc.Item("SPM_SDesc"))
    End If
    
    Call cbo_Updated(cbo_filterMKT, av_Key(0), lo_dataSrc.Item("SPM_SDesc"))
    Set lo_dataSrc = Nothing
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemUpdate")
End Sub

Private Sub mo_SPA_Admin_MKT_OnItemDelete(ByVal av_Key As Variant)
On Error GoTo ErrHandler
    Call X_OnItemDelete("SPA_MKT", av_Key)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
    Call mo_SPA_Admin_PG_MKT.MKT_Deleted(av_Key(0))
    End If
    
    Call cbo_Deleted(cbo_filterMKT, av_Key(0))
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemDelete")
End Sub

Private Sub mo_SPA_Admin_MKT_OnItemNext()
On Error GoTo ErrHandler
    Call X_OnItemNext("SPA_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemNext")
End Sub

Private Sub mo_SPA_Admin_MKT_OnItemPrevious()
On Error GoTo ErrHandler
    Call X_OnItemPrevious("SPA_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemPrevious")
End Sub

Private Sub chk_onlyExisting_Click()
On Error GoTo ErrHandler

Dim ll_frameIndex As Long, ll_MainConfigIndex As Long

    ll_MainConfigIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    ll_frameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
 
    Call LockScreen(True)
    Call SetTreeDelayedMode(ll_frameIndex, True)
    Call LockScreen(False)

    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".chk_onlyExisting_Click")
End Sub

Private Sub mo_SPA_Admin_MKT_USER_OnItemUpdate(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Call X_OnItemUpdate("SPA_MKT_USER", av_Key, as_SrzFields)
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_USER_OnItemUpdate")
End Sub

Private Sub mo_SPA_Admin_MKT_USER_OnItemDelete(ByVal av_Key As Variant)
On Error GoTo ErrHandler
    Call X_OnItemDelete("SPA_MKT_USER", av_Key)
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_USER_OnItemDelete")
End Sub

Private Sub mo_SPA_Admin_MKT_USER_OnItemNext()
On Error GoTo ErrHandler
    Call X_OnItemNext("SPA_MKT_USER")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_USER_OnItemNext")
End Sub

Private Sub mo_SPA_Admin_MKT_USER_OnItemPrevious()
On Error GoTo ErrHandler
    Call X_OnItemPrevious("SPA_MKT_USER")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_USER_OnItemPrevious")
End Sub

Private Sub mo_SPA_Admin_MKT_USER_OnExit()
On Error GoTo ErrHandler
    Call X_OnExit("SPA_MKT_USER")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_USER_OnExit")
End Sub

Private Sub X_OnExit(ByVal as_configName As String)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    
    mt_MainConfig(ll_MainConfig).ActiveDetailControl.Visible = False
    Set mt_MainConfig(ll_MainConfig).ActiveDetailControl = Nothing

    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnExit")
End Sub

Private Function X_OnItemAdd(ByVal as_configName As String, ByVal av_Key As Variant, ByVal as_SrzFields As String) As Boolean
On Error GoTo ErrHandler
    X_OnItemAdd = False
    Dim ll_MainConfig As Long, ll_frameIndex As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)

    Dim lo_Node As Node
    Dim ls_pathTmp As String
    Dim lv_pathData As Variant
    
    ' test if item is visible
    If Not IsItemInFilter(lo_dataSrc, ll_MainConfig) Then
        Call MsgBox(MsgText(7204, ms_Language_Code, "#Updated item cannot be displayed with current filter"))
        Exit Function
    End If
    
        ' create path from selected line
        ll_frameIndex = mt_MainConfig(ll_MainConfig).FrameIndex
        If mt_MainConfig(ll_MainConfig).HasTreeview Then   ' JN 22.4.2013 BUGFIX
            Debug.Assert (cbo_View.Ubound >= ll_frameIndex)
            ls_pathTmp = cbo_View(ll_frameIndex).SelectedItem.GetData(2)
        End If
        If ls_pathTmp = "" Then
            Call AddLineToGrid(grd_Main(ll_frameIndex), lo_dataSrc)
        X_OnItemAdd = True
        Exit Function
        End If
    
        ' try to find in treeView
        ' generate path from detail values
        lv_pathData = GetCurrentPathData(lo_dataSrc, ls_pathTmp)
        Set lo_Node = tvw_Main(ll_frameIndex).SelectedItem
        
        Call FindInTreeView(tvw_Main(ll_frameIndex), lv_pathData, True, False)
        If IsChildNode(lo_Node, tvw_Main(ll_frameIndex).SelectedItem) Then
            If mt_MainConfig(ll_MainConfig).GridDelayed Then
                If Not grd_Main(ll_frameIndex).Execute Then
                    Err.Raise ArmErr.CompFncFailed, "grd_Main(" & ll_frameIndex & ").Execute", "Method Execute failed: " & grd_Main(ll_frameIndex).Requests(0)
                End If
                 mt_MainConfig(ll_MainConfig).GridDelayed = False
                Call grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex).SearchKey(True, av_Key)
            Else
                Call AddLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc)
            End If
        X_OnItemAdd = True
        Else
            MsgBox MsgText(7209, ms_Language_Code, "#Item not found under current filter criteria"), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
        End If
        Set tvw_Main(ll_frameIndex).SelectedItem = lo_Node

    Exit Function
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnItemAdd")
End Function

Private Sub X_OnItemDelete(ByVal as_configName As String, ByVal av_Key As Variant)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    
    Call DeleteLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), av_Key)

    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnItemDelete")
End Sub

' return true if line was updated, false if deleted
Private Function X_OnItemUpdate(ByVal as_configName As String, ByVal av_Key As Variant, ByVal as_SrzFields As String) As Boolean
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long, ll_frameIndex As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    X_OnItemUpdate = False
    
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)

    Dim lo_Node As Node
    Dim ls_pathTmp As String
    Dim lv_pathData As Variant
    
    ' test if item is visible
    If Not IsItemInFilter(lo_dataSrc, ll_MainConfig) Then
        Call DeleteLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), av_Key)
'        Call MsgBox(MsgText(7204, ms_Language_Code, "#Updated item cannot be displayed with current filter"))
        Exit Function
    Else
        ' create path from selected line
        ll_frameIndex = mt_MainConfig(ll_MainConfig).FrameIndex
        If mt_MainConfig(ll_MainConfig).HasTreeview Then   ' JN 22.4.2013 BUGFIX
            Debug.Assert (cbo_View.Ubound >= ll_frameIndex)
            ls_pathTmp = cbo_View(ll_frameIndex).SelectedItem.GetData(2)
        End If
        If ls_pathTmp = "" Then
            Call UpdateLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc, Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))))
            X_OnItemUpdate = True
            Exit Function
        End If
    
        ' try to find in treeView
        ' generate path from detail values
        lv_pathData = GetCurrentPathData(lo_dataSrc, ls_pathTmp)
        
        Set lo_Node = tvw_Main(ll_frameIndex).SelectedItem
        
        Call FindInTreeView(tvw_Main(ll_frameIndex), lv_pathData, True, False)
        If IsChildNode(lo_Node, tvw_Main(ll_frameIndex).SelectedItem) Then
            If mt_MainConfig(ll_MainConfig).GridDelayed Then
                If Not grd_Main(ll_frameIndex).Execute Then
                    Err.Raise ArmErr.CompFncFailed, "grd_Main(" & ll_frameIndex & ").Execute", "Method Execute failed: " & grd_Main(ll_frameIndex).Requests(0)
                End If
                 mt_MainConfig(ll_MainConfig).GridDelayed = False
            End If
            Call UpdateLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc, Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))))
            X_OnItemUpdate = True
        Else
            Call DeleteLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), av_Key)
            Call grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex).DeselectRow
        End If
        Set tvw_Main(ll_frameIndex).SelectedItem = lo_Node
    End If

    Exit Function
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnItemUpdate")
End Function

Private Function IsChildNode(ByVal ao_parent As Node, ByRef ao_testNode As Node) As Boolean
On Error GoTo ErrHandler
    Dim lb_retVal As Boolean
    lb_retVal = (ao_testNode Is ao_parent)
    If lb_retVal Or ao_testNode.Parent Is Nothing Then
        IsChildNode = lb_retVal
        Exit Function
    End If
    lb_retVal = IsChildNode(ao_parent, ao_testNode.Parent)
    IsChildNode = lb_retVal
    Exit Function
ErrHandler:
    Call ErrorHandler(Extender.Name & ".IsChildNode")
End Function

Private Sub X_OnItemNext(ByVal as_configName As String)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long, ll_MainFrame As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    ll_MainFrame = mt_MainConfig(ll_MainConfig).FrameIndex
    
    If Not grd_Main(ll_MainFrame).NextItem Then
        Call MsgBox(MsgText(928, ms_Language_Code, "#No more next item"), vbInformation)
    End If

    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnItemNext")
End Sub

Private Sub X_OnItemPrevious(ByVal as_configName As String)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long, ll_MainFrame As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    ll_MainFrame = mt_MainConfig(ll_MainConfig).FrameIndex
    
    If Not grd_Main(ll_MainFrame).PreviousItem Then
        Call MsgBox(MsgText(928, ms_Language_Code, "#No more next item"), vbInformation)
    End If

    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnItemPrevious")
End Sub

Private Sub X_OnPrint(ByVal as_configName As String, ByVal av_Key As Variant)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long, ll_MainFrame As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    ll_MainFrame = mt_MainConfig(ll_MainConfig).FrameIndex
    
'    Call GenerateTemplate(av_Key(0))
    
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".X_OnPrint")
End Sub

Private Function GetGridKeyColumnFieldName(ByRef ao_grid As ArmGrid) As String
On Error GoTo ErrHandler
    Dim ll_Col As Long
    
    GetGridKeyColumnFieldName = ""
    For ll_Col = 0 To ao_grid.Cols - 1
        If ao_grid.Columns(ll_Col).Key Then
            ' we have key
            GetGridKeyColumnFieldName = ao_grid.Columns(ll_Col).FieldName
            Exit For
        End If
    Next

    Exit Function
ErrHandler:
    Call ErrorHandler(Extender.Name & ".GetGridKeyColumnFieldName")
End Function

Private Sub mo_SPA_Admin_PG_OnExit()
On Error GoTo ErrHandler
    Call X_OnExit("SPA_PG")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_OnExit")
End Sub

Private Sub mo_SPA_Admin_PG_OnItemAdd(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Call X_OnItemAdd("SPA_PG", av_Key, as_SrzFields)
    ' propagate changes to Admin_PG_MKT
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
        ' new line must be inserted
        Call mo_SPA_Admin_PG_MKT.PG_Updated(av_Key(0), lo_dataSrc.Item("SPG_SDesc"))
    End If
    
    Call cbo_Updated(cbo_filterPG, av_Key(0), lo_dataSrc.Item("SPG_SDesc"))
    Set lo_dataSrc = Nothing
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_OnItemAdd")
End Sub

Private Sub mo_SPA_Admin_PG_OnItemDelete(ByVal av_Key As Variant)
On Error GoTo ErrHandler
    Call X_OnItemDelete("SPA_PG", av_Key)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
    Call mo_SPA_Admin_PG_MKT.PG_Deleted(av_Key(0))
    End If
    
    Call cbo_Deleted(cbo_filterPG, av_Key(0))
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_OnItemDelete")
End Sub

Private Sub mo_SPA_Admin_PG_OnItemNext()
On Error GoTo ErrHandler
    Call X_OnItemNext("SPA_PG")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_OnItemNext")
End Sub

Private Sub mo_SPA_Admin_PG_OnItemPrevious()
On Error GoTo ErrHandler
    Call X_OnItemPrevious("SPA_PG")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_MKT_OnItemPrevious")
End Sub

Private Sub mo_SPA_Admin_PG_OnItemUpdate(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Call X_OnItemUpdate("SPA_PG", av_Key, as_SrzFields)
    ' propagate changes to Admin_PG_MKT
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)
    
    If Not mo_SPA_Admin_PG_MKT Is Nothing Then
        ' line must be updated
        Call mo_SPA_Admin_PG_MKT.PG_Updated(av_Key(0), lo_dataSrc.Item("SPG_SDesc"))
    End If
    
    Call cbo_Updated(cbo_filterPG, av_Key(0), lo_dataSrc.Item("SPG_SDesc"))
    Set lo_dataSrc = Nothing
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_OnItemUpdate")
End Sub

Private Sub cbo_Updated(ByRef ao_Cbo As ArmCombobox, ByVal al_Code As Long, ByVal as_Desc As String)
On Error GoTo ErrHandler

Dim lb_InternalInitBackup As Boolean

    lb_InternalInitBackup = mb_InternalInit
    mb_InternalInit = True

    If ao_Cbo.Count > 0 Then
        ' combobox is loaded
        Dim ll_i As Long
        For ll_i = 1 To ao_Cbo.Count
            If ao_Cbo.ComboItems(ll_i).Key = al_Code Then
                ao_Cbo.ComboItems(ll_i).DisplayText = as_Desc
                Exit Sub
            End If
        Next
        ' item not found
        Call ao_Cbo.AddItem(Array(al_Code, as_Desc))
    End If
    
    mb_InternalInit = lb_InternalInitBackup
    
    Exit Sub
ErrHandler:
    mb_InternalInit = lb_InternalInitBackup
    Call ErrorHandler(Extender.Name & ".cbo_Updated")
End Sub

Private Sub cbo_Deleted(ByRef ao_Cbo As ArmCombobox, ByVal al_Code As Variant)
On Error GoTo ErrHandler
    If ao_Cbo.Count > 0 Then
        ' combobox is loaded
        Call ao_Cbo.DeleteItemKey(al_Code)
    End If
    Exit Sub
ErrHandler:
    Call ErrorHandler(Extender.Name & ".cbo_Updated")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnExit()
On Error GoTo ErrHandler
    Call X_OnExit("SPA_PG_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnExit")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnItemAdd(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)

    If X_OnItemAdd("SPA_PG_MKT", av_Key, as_SrzFields & "SPG_DefaultOld" & SEP1 & lo_dataSrc.Item("SPG_Default") & SEP) Then
        ' insert one more line
        
        If lo_dataSrc.Item("SPGAM_ID_ALT") <> 0 Then
            Dim ll_MainConfig As Long
            ll_MainConfig = FindMainConfigByName("SPA_PG_MKT")
            
            ' type of add is 2 new items
            Debug.Assert (lo_dataSrc.Item("isActive") = "")
            lo_dataSrc.Item("isActive") = "X"
            lo_dataSrc.Item("SPGAM_Id") = lo_dataSrc.Item("SPGAM_ID_ALT")
            lo_dataSrc.Item("VDate_End") = lo_dataSrc.Item("VDate_End_ALT")
            Call AddLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc)
        End If
        
        Set lo_dataSrc = Nothing
    End If
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnItemAdd")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnItemDelete(ByVal av_Key As Variant, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
    Dim ll_MainConfig As Long
    ll_MainConfig = FindMainConfigByName("SPA_PG_MKT")
    
    If as_SrzFields <> "" Then
    Dim lo_dataSrc As New Dictionary
    lo_dataSrc.CompareMode = TextCompare
    
    Call FillDataSrcArray(lo_dataSrc, as_SrzFields)

    Call UpdateLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc, Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), COLOR_DELLINE)
    
    Set lo_dataSrc = Nothing
    Else
        Call DeleteLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), av_Key)
        Call grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex).DeselectRow
    End If
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnItemDelete")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnItemNext()
On Error GoTo ErrHandler
    Call X_OnItemNext("SPA_PG_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnItemNext")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnItemPrevious()
On Error GoTo ErrHandler
    Call X_OnItemPrevious("SPA_PG_MKT")
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnItemPrevious")
End Sub

Private Sub mo_SPA_Admin_PG_MKT_OnItemUpdate(ByVal av_newKey As Variant, ByVal ab_removeOld As Boolean, ByVal as_SrzFields As String)
On Error GoTo ErrHandler
        Dim ll_MainConfig As Long
    Dim lb_opSucc As Boolean
        Dim lo_dataSrc As New Dictionary
        lo_dataSrc.CompareMode = TextCompare
        
        Call FillDataSrcArray(lo_dataSrc, as_SrzFields)
        
    ll_MainConfig = FindMainConfigByName("SPA_PG_MKT")
    If ab_removeOld Then
        Call DeleteLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), Array(GetGridKeyColumnFieldName(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex))), Array(lo_dataSrc.Item("SPGAM_Id")))
        Call grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex).DeselectRow
        lb_opSucc = True
    Else
        lb_opSucc = X_OnItemUpdate("SPA_PG_MKT", Array(lo_dataSrc.Item("SPGAM_Id")), as_SrzFields)
    End If
    
    If lb_opSucc Then
        ' do the Insert Part
        lo_dataSrc.Item("SPGAM_Id") = av_newKey(0)
        lo_dataSrc.Item("isActive") = IIf(SqlDate(lo_dataSrc.Item("VDate_Start")) > SqlDate(Date), "", "X")
'        lo_dataSrc.Item("isActive") = IIf(lo_dataSrc.Item("isActive") = "X" Or lo_dataSrc.Item("SPGAM_ID_ALT") <> "0", "", "X")
        lo_dataSrc.Item("VDate_End") = ""
        lo_dataSrc.Item("SPG_DefaultOld") = lo_dataSrc.Item("SPG_Default")
        
        
        Call AddLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc)
        
        ' insert alternate if exists
        If lo_dataSrc.Item("SPGAM_ID_ALT") <> 0 Then
            Debug.Assert (lo_dataSrc.Item("isActive") = "")
            lo_dataSrc.Item("isActive") = "X"
            lo_dataSrc.Item("SPGAM_Id") = lo_dataSrc.Item("SPGAM_ID_ALT")
            lo_dataSrc.Item("VDate_End") = lo_dataSrc.Item("VDate_End_ALT")
            Call AddLineToGrid(grd_Main(mt_MainConfig(ll_MainConfig).FrameIndex), lo_dataSrc)
        End If
        
    End If
    
    Set lo_dataSrc = Nothing
    Exit Sub
ErrHandler:
    Call ErrorMessage(Extender.Name & ".mo_SPA_Admin_PG_MKT_OnItemUpdate")
End Sub

'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK CONTROL EVENTS
' please DO NOT change anything in this part of code
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Private Sub tlb_main_action(Index As Integer, ByVal as_Role As String, as_Language As String)
On Error GoTo ErrHandler
    
    Dim ll_MainConfigIndex As Long, ll_MainFrameIndex As Long, ll_frameIndex As Long
    Dim ll_errCode As ArmCusErr
    
    If Not tlb_Main(Index).Enabled Then Exit Sub
    
    Call LockScreen(True)
    
    ll_MainConfigIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    ll_frameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
    ll_MainFrameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
    If Not tlb_Main_CustomAction(Index, as_Role, as_Language) Then
        Select Case as_Role
            Case "A"
                ' Want to Add
                Call InitDetailControl(Index)
                ' load detail
                If Not mt_MainConfig(Index).ActiveDetailControl Is Nothing Then
                    Call mt_MainConfig(Index).ActiveDetailControl.Run(SPA_Mode.emAdd, Array(""))
                    mt_MainConfig(Index).ActiveDetailControl.Visible = True
                End If
            Case "B"
                ll_errCode = Item_CanUpdateCustom(tbs_Main.SelectedItem.Tag)
                If ll_errCode = NoError Then
                    ' Want to Update
                    Call InitDetailControl(Index)
                    ' load detail
                    If Not mt_MainConfig(Index).ActiveDetailControl Is Nothing Then
                        Call mt_MainConfig(Index).ActiveDetailControl.Run(SPA_Mode.emUpdate, grd_Main(ll_frameIndex).CurrentKey)
                        mt_MainConfig(Index).ActiveDetailControl.Visible = True
                    End If
                Else
                    MsgBox MsgText(ll_errCode, ms_Language_Code, "#Cannot Update."), vbInformation + vbOKOnly, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
                End If
            Case "C"
                ll_errCode = Item_CanDeleteCustom(tbs_Main.SelectedItem.Tag)
                If ll_errCode = NoError Then
                    ' Want to delete
                    Call InitDetailControl(Index)
                    ' load detail
                    If Not mt_MainConfig(Index).ActiveDetailControl Is Nothing Then
                        Call mt_MainConfig(Index).ActiveDetailControl.Run(SPA_Mode.emDelete, grd_Main(ll_frameIndex).CurrentKey)
                        mt_MainConfig(Index).ActiveDetailControl.Visible = True
                    End If
                Else
                    MsgBox MsgText(ll_errCode, ms_Language_Code, "#Cannot Delete."), vbInformation + vbOKOnly, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
                End If
            Case "D" 'print
                If grd_Main(ll_frameIndex).SelectedCount > 0 Then
'                    Call GenerateTemplate(grd_Main(ll_frameIndex).CurrentKey(0))
                End If
            Case "L"
            ' Want to reload treeview and refresh the grid
                Call ReloadMainGrid
            Case "F"
                ' Want to reload grid according to treeview selection
                Call ReloadMainTreeview
                Call ReloadMainFilterGrid
            Case "N"
                ' search on grid
                Call LockScreen(False)
                Exit Sub
            Case "Q"
                Call cbo_View_ComboItemSelected(Index)
            Case "T"
                RaiseEvent quit
            Case Else
                Err.Raise ArmErr.InvalidArgument, "tlb_Main_action(" & Index & ")", "Unknown main toolbar role as_Role=" & as_Role
        End Select
    End If
    Call LockScreen(False)
    
    Exit Sub
ErrHandler:
    Call UpdateError(True)
    Call LockScreen(False)

    Select Case Err.Number
    Case 202
        MsgBox MsgText(666, ms_Language_Code, "#The item you have added/updated couldn't be displayed with the current criteria set."), vbInformation + vbOKOnly, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    Case ArmErr.SQLBadRowExpectedCount
        MsgBox MsgText(666, ms_Language_Code, "#The record you try to open has been deleted by an other user. Please refresh the grid."), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    Case ArmErr.SQLBadRowAffectedCount
        MsgBox MsgText(666, ms_Language_Code, "#This record has been, modified by an other.Please exit from this screen and refresh the grid."), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    Case Else
        Call LogMessage("tlb_list_action")
        ' user interface can be inconsistent, better to close application
        Call UpdateError(False)
        Call MsgBox("Error occured, please contact IT. Application will now shutdown." & vbCrLf & Err.Source & vbCrLf & "Description: " & Err.Description, , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
        End
    End Select
End Sub

Private Sub tbs_Main_Click()
On Error GoTo ErrHandler

Dim ll_Index As Long
Dim ll_FraIndex As Long
Dim lo_Control As Object

    If tbs_Main.SelectedItem Is Nothing Then Exit Sub
    
    ll_Index = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    Call InitMainFrame(ll_Index)
    
    ll_FraIndex = mt_MainConfig(ll_Index).FrameIndex
    For Each lo_Control In fra_MainItem
        lo_Control.Visible = (ll_FraIndex = lo_Control.Index)
    Next
    
    Exit Sub
ErrHandler:
    Call ErrorMessage("tbs_Main_Click")
End Sub

Private Sub cbo_View_ComboItemSelected(Index As Integer)
On Error GoTo ErrHandler

Dim ll_Index As Long

    Call LockScreen(True)
    
     If Not cbo_View(Index).SelectedItem Is Nothing Then
        ll_Index = FindMainConfigByFrameIndex(Index)
        Call LoadTreeView(ll_Index, tvw_Main(Index), GetTreeViewInfo(mt_MainConfig(ll_Index).mTreeViewInfos, mt_MainConfig(ll_Index).ViewCode, cbo_View(Index).SelectedItem.Key))
        If tvw_Main(Index).Count > 0 Then
            Set tvw_Main(Index).SelectedItem = tvw_Main(Index).Nodes(1)
            Call tvw_Main_NodeClick(Index, tvw_Main(Index).SelectedItem)
        Else
            Call tvw_Main_NodeClick(Index, Nothing)
        End If
        Call SetTreeDelayedMode(Index, False)
    End If
    
CleanUp:
    Call LockScreen(False)
    Exit Sub
    
ErrHandler:
    Call LogMessage("cbo_Views_ComboItemSelected")
    Call LockScreen(False)
    MsgBox MsgText(666, ms_Language_Code, "#Unable to load the combo " & " type of view."), vbInformation + vbOKOnly, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
End Sub

Private Sub cbo_filterMKT_ComboItemSelected()
On Error GoTo ErrHandler
    
    If mb_InternalInit Then Exit Sub
    
    Call ReloadMainFilterGrid
    Exit Sub
ErrHandler:
    Call ErrorMessage("cbo_filterMKT_ComboItemSelected")
End Sub

Private Sub cbo_filterPG_ComboItemSelected()
On Error GoTo ErrHandler
    
    If mb_InternalInit Then Exit Sub

    Call ReloadMainFilterGrid
    Exit Sub
ErrHandler:
    Call ErrorMessage("cbo_filterPG_ComboItemSelected")
End Sub

Private Sub pic_filtersReset_Click(Index As Integer)
On Error GoTo ErrHandler
    Call LockScreen(True)
    
    ' reset filters
    Dim ll_frameIndex As Long
    ll_frameIndex = mt_MainConfig(Index).FrameIndex

    Select Case mt_MainConfig(Index).NameFrame
        Case "SPA_MKT_USER"
            Call cbo_View(ll_frameIndex).SearchItem("X", "TV_Default", 0)
            chk_onlyExisting.Value = Checked
        Case "SPA_PG"
        Case "SPA_MKT"
        Case "SPA_PG_MKT"
            Set cbo_filterMKT.SelectedItem = Nothing
            Set cbo_filterPG.SelectedItem = Nothing
            Call ReloadMainFilterGrid
'        Case "SPA_PG_MKT_BI"
'            Set cbo_filterMKT2.SelectedItem = Nothing
'            Call ReloadMainFilterGrid
        Case "SPA_PG_MKT_BI2"
            Call cbo_View(ll_frameIndex).SearchItem("X", "TV_Default", 0)
            chk_onlyExisting.Value = Checked
        Case Else
            Debug.Assert (False)
    End Select
    
    Call LockScreen(False)
    Exit Sub
ErrHandler:
    Call LockScreen(False)
    Call ErrorMessage("pic_filtersReset_Click")
End Sub

Private Sub cmd_TVReLoad_Click(Index As Integer)
On Error GoTo ErrHandler
    
    Call cbo_View_ComboItemSelected(Index)
    Exit Sub
ErrHandler:
    Call ErrorMessage("cmd_TVReLoad_Click")
End Sub

Private Sub tvw_Main_NodeClick(Index As Integer, ByVal Node As MSComctlLib.Node)
On Error GoTo ErrHandler
    
    Dim ll_DetailIndex As Long, ll_MainIndex As Long
    
    If mb_InternalInit Then Exit Sub
    
    Call LockScreen(True)
    
    Dim lv_Requests As Variant, lb_DelayedLoad As Boolean
    
    ll_MainIndex = FindMainConfigByFrameIndex(Index)
    
    If tvw_Main(Index).Checkboxes = True Then
        lv_Requests = ApplyTVFilters(ll_MainIndex, tvw_Main(Index).CheckedNodesRequests)
    Else
    lv_Requests = ApplyTVFilters(ll_MainIndex, tvw_Main(Index).SelectedNodeRequest)
    End If
    
    If Not (Node Is Nothing) Then
        If (tvw_Main(Index).NodeInfo(Node).ml_Level = tvw_Main(Index).Levels - 1) Then
            mt_MainConfig(ll_MainIndex).CurrentTvwSelMethod = eTvwSelMethod.etmNode
        Else
            mt_MainConfig(ll_MainIndex).CurrentTvwSelMethod = eTvwSelMethod.etmBranch
        End If
    Else
        mt_MainConfig(ll_MainIndex).CurrentTvwSelMethod = etmNone
    End If
    
    Select Case mt_MainConfig(ll_MainIndex).GridDelayMethod
    Case egmDelayedAlways
        lb_DelayedLoad = True
    Case egmDelayedExceptLastLevel
        If Node Is Nothing Then
            lb_DelayedLoad = True
        Else
            lb_DelayedLoad = (tvw_Main(Index).NodeInfo(Node).ml_Level < tvw_Main(Index).Levels - 1)
        End If
    Case egmLoadAlways
        lb_DelayedLoad = False
    Case Else
        lb_DelayedLoad = True
    End Select
    
    If grd_Main(Index).Cols = 0 Then
        
        If Not grd_Main(Index).SetColumns(mt_MainConfig(ll_MainIndex).MainGridColumns) Then
            Err.Raise ArmErr.CompFncFailed, "grd_Main", "Method SetColumns failed."
        End If
        Call LoadLabels(mo_Db, fra_MainItem(Index), SCREEN_NAME, ms_Language_Code)
    End If
    
    mt_MainConfig(ll_MainIndex).GridDelayed = lb_DelayedLoad
    
    If Not grd_Main(Index).Load(lv_Requests, False, , , lb_DelayedLoad) Then
        Err.Raise ArmErr.CompFncFailed, "grd_Main", "Method Load failed: " & lv_Requests(0)
    End If
    Call UpdateMainToolbarCustom(ll_MainIndex)
    Call LockScreen(False)
    Exit Sub

ErrHandler:
    Call LogMessage("tvw_Main_NodeClick")
    Call LockScreen(False)
    MsgBox MsgText(666, ms_Language_Code, "#There is a problem while loading data."), vbInformation + vbOKOnly, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
End Sub

Private Sub tbs_MainTabFilter_Click(Index As Integer)
On Error GoTo ErrHandler
    
    Call SetTreeDelayedMode(Index, True)
    Exit Sub
ErrHandler:
    Call ErrorMessage("tbs_MainTabFilter_Click")
End Sub


Private Sub grd_Main_ItemSelected(Index As Integer)
On Error GoTo ErrHandler
    
    Dim ll_MainIndex As Long
    Dim lb_Locked As Boolean
    
    If grd_Main(Index).SelectedCount < 1 Then Exit Sub
    
    Call LockScreen(True)
    lb_Locked = True
    
    If grd_Main_CustomAction(Index, eControlAction.caDoubleClick) Then
        Call LockScreen(False)
        lb_Locked = False
        Exit Sub
    End If
    
    ll_MainIndex = FindMainConfigByFrameIndex(Index)
    'Call Item_ViewInit(ll_DetailIndex, grd_Main(Index).CurrentKey)
    Call LockScreen(False)
    lb_Locked = False
    Exit Sub
ErrHandler:
    If lb_Locked Then Call LockScreen(False)
    Select Case Err.Number
        Case ArmErr.SQLBadRowExpectedCount
            MsgBox MsgText(666, ms_Language_Code, "#The record you try to open has been deleted by an other user. Please refresh the grid."), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
        Case Else
            Call LogMessage("grd_Main_ItemSelected")
            MsgBox MsgText(666, ms_Language_Code, "#There is a problem while doing this action. Please double check your entry."), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End Select
End Sub

Private Sub grd_Main_RowColChange(Index As Integer)
On Error GoTo ErrHandler
Dim ll_MainIndex As Long

    ll_MainIndex = FindMainConfigByFrameIndex(Index)
    mt_MainConfig(ll_MainIndex).GridDelayed = False
    Call UpdateMainToolbarCustom(ll_MainIndex)
    Exit Sub
ErrHandler:
    Call ErrorMessage("grd_Main_RowColChange")
End Sub


'**********************************************************************************************************************************
'**********************************************************************************************************************************
' FRAMEWORK METHODS
' please DO NOT change anything in this part of code
'**********************************************************************************************************************************
'**********************************************************************************************************************************

Public Function Load_A_COM() As Boolean

Dim ll_Index As Long
Dim lo_Control As Object

On Error GoTo ErrHandler
    
    Load_A_COM = False
    
    If Initialized Then Call Err.Raise(ArmErr.CPTAlreadyInitialized)
    If mo_Db Is Nothing Then Call Err.Raise(ArmErr.PropertyNotSet, "", "mo_Db")
    If Len(ms_Language_Code) < 1 Then Call Err.Raise(ArmErr.PropertyNotSet, "", "ms_Language_Code")
    
    mb_InternalInit = False
    ms_DecimalSeparator = Format(0, ".")
    Dim sBuffer As String
    Dim nBufferLen As Long
    nBufferLen = 255
    sBuffer = String$(nBufferLen, vbNullChar)
    nBufferLen = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, sBuffer, nBufferLen)
    If nBufferLen > 0 Then
        ms_ThousandSeparator = Left$(sBuffer, nBufferLen - 1)
    End If
    
    For Each lo_Control In UserControl.Controls
        Select Case UCase(TypeName(lo_Control))
        Case "ARMCOMBOBOX"
            Set lo_Control.ArmDb = mo_Db
            Call lo_Control.Load_A_COM
        Case "ARMPICKER"
            Set lo_Control.ArmDb = mo_Db
            Call lo_Control.Load_A_COM
        Case "TOOLBARCONTROL"
            lo_Control.Language = ms_Language_Code
            lo_Control.HideTips = True
            lo_Control.Load_A_COM
        Case "ARMGRID"
            Set lo_Control.ArmDb = mo_Db
            Call lo_Control.Load_A_COM
        Case "ARMTREEVIEW"
            Set lo_Control.ArmDb = mo_Db
            lo_Control.Language = ms_Language_Code
            Call lo_Control.Load_A_COM
        Case "ARMCHECKVIEW"
            Set lo_Control.ArmDb = mo_Db
            Call lo_Control.Load_A_COM
        Case "A_CALOCX"
            lo_Control.Language = ms_Language_Code
            Call lo_Control.reinit_cal
        End Select
    Next
    
    Set mo_FSO = CreateObject("Scripting.FileSystemObject")
    
    If Init_control Then
        Load_A_COM = True
        mb_Initialized = True
    End If
    
    Exit Function
ErrHandler:
    Call ErrorMessage("Load_A_COM")
End Function

Public Function Unload_A_COM() As Boolean
    
On Error GoTo ErrHandler
    
    Dim lo_Control As Object
    Dim ll_Index As Long
    
    If mc_ScreenLabels <> 0 Then mo_Db.Close (mc_ScreenLabels)
    mc_ScreenLabels = 0
    If mc_Toolbars <> 0 Then mo_Db.Close (mc_Toolbars)
    mc_Toolbars = 0
    
    For Each lo_Control In UserControl.Controls
        Select Case UCase(TypeName(lo_Control))
        Case "ARMCOMBOBOX", "TOOLBARCONTROL", "ARMGRID", "ARMTREEVIEW", "ARMCHECKVIEW", "ARMPICKER", "SRM_TASK"
            Call lo_Control.Unload_A_COM
        End Select
    Next
        
    If Not mo_SPA_Admin_MKT_USER Is Nothing Then
        mo_SPA_Admin_MKT_USER.Unload_A_COM
        Set mo_SPA_Admin_MKT_USER = Nothing
    End If
        
 '   Debug.Assert (mo_Db.CursorCount = 0)
    
    Set mo_Db = Nothing
    Set mo_FSO = Nothing
    mb_Initialized = False
    Unload_A_COM = True
    Exit Function
ErrHandler:
    Unload_A_COM = False
    Call ErrorMessage("Unload_A_Com")
End Function

Public Sub Resize()
On Error GoTo ErrHandler

Dim ll_Index As Long

    If Not Resize_Custom Then
        For ll_Index = 0 To UBound(mt_MainConfig)
            Call ResizeMain(ll_Index)
        Next
    End If
    Exit Sub
ErrHandler:
    Call ErrorMessage("Resize")
End Sub

Private Sub ResizeMain(ByVal al_MainIndex As Long)
On Error GoTo ErrHandler

Dim ll_frameIndex As Long

    If Width < 0 Or Height < 0 Then Exit Sub
    
    ll_frameIndex = mt_MainConfig(al_MainIndex).FrameIndex
    Call tbs_Main.Move(0, 0, Width)
    
    Call fra_MainItem(ll_frameIndex).Move(0, tbs_Main.Height, Width, Height - (tbs_Main.Height))
    
    If mt_MainConfig(al_MainIndex).HasFilters Then
        Call tlb_Main(ll_frameIndex).Move(fra_MainFilter(ll_frameIndex).Left + fra_MainFilter(ll_frameIndex).Width + FRM_SPACE_HOR, 2 * FRM_SPACE_VER)
        Call grd_Main(ll_frameIndex).Move(fra_MainFilter(ll_frameIndex).Left + fra_MainFilter(ll_frameIndex).Width + FRM_SPACE_HOR, tlb_Main(ll_frameIndex).Top + tlb_Main(ll_frameIndex).Height + FRM_SPACE_VER)
        Call pic_filtersReset(ll_frameIndex).Move(0, 90)
        If mt_MainConfig(al_MainIndex).HasTreeview Then
            If fra_MainItem(ll_frameIndex).Height - (cbo_View(ll_frameIndex).Top + cbo_View(ll_frameIndex).Height + 3 * FRM_SPACE_VER) > 0 Then
                tvw_Main(ll_frameIndex).Height = fra_MainItem(ll_frameIndex).Height - (cbo_View(ll_frameIndex).Top + cbo_View(ll_frameIndex).Height + 3 * FRM_SPACE_VER)
            End If
            If ll_frameIndex = 5 Then
                fra_MainFilter(ll_frameIndex).Height = fra_MainItem(ll_frameIndex).Height - fra_MainFilter(ll_frameIndex).Top - 1 * FRM_SPACE_VER
                tvw_Main(ll_frameIndex).Height = tvw_Main(ll_frameIndex).Height - 1 * FRM_SPACE_VER
            End If
            Call cmd_TVReLoad(ll_frameIndex).Move(tvw_Main(ll_frameIndex).Left, tvw_Main(ll_frameIndex).Top)
        End If
    Else
        ' without filters frame
        Call tlb_Main(ll_frameIndex).Move(FRM_SPACE_HOR, 2 * FRM_SPACE_VER)
        Call grd_Main(ll_frameIndex).Move(FRM_SPACE_HOR, tlb_Main(ll_frameIndex).Top + tlb_Main(ll_frameIndex).Height + FRM_SPACE_VER)
    End If
    tlb_Main(ll_frameIndex).Width = Width - tlb_Main(ll_frameIndex).Left - FRM_SPACE_VER
    
    If fra_MainItem(ll_frameIndex).Height - grd_Main(ll_frameIndex).Top - FRM_SPACE_VER > 0 Then
        grd_Main(ll_frameIndex).Height = fra_MainItem(ll_frameIndex).Height - grd_Main(ll_frameIndex).Top - FRM_SPACE_VER
    End If
    If fra_MainItem(ll_frameIndex).Width - grd_Main(ll_frameIndex).Left - FRM_SPACE_HOR > 0 Then
        grd_Main(ll_frameIndex).Width = fra_MainItem(ll_frameIndex).Width - grd_Main(ll_frameIndex).Left - FRM_SPACE_HOR
    End If
    Exit Sub
ErrHandler:
    Call ErrorHandler("ResizeMain")
End Sub
Public Function Init_control() As Boolean
Dim ll_Index As Long

On Error GoTo ErrHandler

    Init_control = False
    mb_InternalInit = True
    Call Load_ConfigInfo
    
    ' init controls
    ms_UserName = LoadUserInfo(mo_Db, ml_U_Code)
    
    'SPA module = 2422
    ms_ToolbarRequest = "exec A_ToolbarDef_sel NULL,2422,NULL,NULL"
    
    If Not InitUserRights(ms_LoginName) Then
        Exit Function
    End If
    
    Call AddNewTab(tbs_Main, "SPA_MKT_USER", "SPA_MKT_USER", "#Market - Users Link")
    Call AddNewTab(tbs_Main, "SPA_PG", "SPA_PG", "#Product Groups")
    Call AddNewTab(tbs_Main, "SPA_MKT", "SPA_MKT", "#Authorization Market")
    Call AddNewTab(tbs_Main, "SPA_PG_MKT", "SPA_PG_MKT", "#Product Group - Market Link")
'    Call AddNewTab(tbs_Main, "SPA_PG_MKT_BI", "SPA_PG_MKT_BI", "#Market - Products Link")
    Call AddNewTab(tbs_Main, "SPA_PG_MKT_BI2", "SPA_PG_MKT_BI2", "#Products linked")
    
    Call ChangeCharset(UserControl.Controls, GetCodePageFromLanguage(mo_Db, ms_Language_Code))
    Call LoadLabels(mo_Db, Me, SCREEN_NAME, ms_Language_Code)
    
    'init combo boxes
    cbo_filterMKT.FirstBlankItem = True
    cbo_filterMKT.Request = ReplaceCommonPlaceholders(REQ_FILTER_MKT_CBO)

    cbo_filterMKT2.FirstBlankItem = True
    cbo_filterMKT2.Request = ReplaceCommonPlaceholders(REQ_FILTER_MKT_CBO)

    cbo_filterPG.FirstBlankItem = True
    cbo_filterPG.Request = ReplaceCommonPlaceholders(REQ_FILTER_PG_CBO)
    
    If tbs_Main.Tabs.Count > 1 Then
        Call tbs_Main.Move(0, 0, Width)
        tbs_Main.Visible = True
    End If
    mb_InternalInit = False
    
    Set tbs_Main.SelectedItem = tbs_Main.Tabs(1)
    
    Init_control = True
    Exit Function
ErrHandler:
    mb_InternalInit = False
    Call ErrorMessage("Init_control")
    Resume
End Function

Private Sub InitDetailControl(ByVal Index As Long)
On Error GoTo ErrHandler
    Dim ll_frameIndex As Long
    ll_frameIndex = mt_MainConfig(Index).FrameIndex
    
    Select Case mt_MainConfig(Index).NameFrame
        Case "SPA_MKT_USER"
            If mo_SPA_Admin_MKT_USER Is Nothing Then
                Set mo_SPA_Admin_MKT_USER = UserControl.Controls.Add(C_ProgID & ".SPA_Admin_MKT_USER", "mo_SPA_Admin_MKT_USER", fra_MainItem(ll_frameIndex))
                mo_SPA_Admin_MKT_USER.Visible = False
                Call mo_SPA_Admin_MKT_USER.Move(0, 0, fra_MainItem(ll_frameIndex).Width, fra_MainItem(ll_frameIndex).Height)
                
                mo_SPA_Admin_MKT_USER.Language_Code = ms_Language_Code
                mo_SPA_Admin_MKT_USER.U_Code = ml_U_Code
                mo_SPA_Admin_MKT_USER.LoginName = ms_LoginName
                Set mo_SPA_Admin_MKT_USER.DB = mo_Db
                
                Call mo_SPA_Admin_MKT_USER.Load_A_COM
                If Not mo_SPA_Admin_MKT_USER.Initialized Then
                    Call Err.Raise(ArmErr.CompFncFailed, "mo_SPA_Admin_MKT_USER.Initialized", "SPA_Admin_MKT_USER cannot was not initialised")
                End If
                mo_SPA_Admin_MKT_USER.Zorder
                mo_SPA_Admin_MKT_USER.UserReplacementFrameVisible = False

            End If
            Set mt_MainConfig(Index).ActiveDetailControl = mo_SPA_Admin_MKT_USER
        Case "SPA_PG"
            If mo_SPA_Admin_PG Is Nothing Then
                Set mo_SPA_Admin_PG = UserControl.Controls.Add(C_ProgID & ".SPA_Admin_PG", "mo_SPA_Admin_PG", fra_MainItem(ll_frameIndex))
                mo_SPA_Admin_PG.Visible = False
                Call mo_SPA_Admin_PG.Move(0, 0, fra_MainItem(ll_frameIndex).Width, fra_MainItem(ll_frameIndex).Height)
                
                mo_SPA_Admin_PG.Language_Code = ms_Language_Code
                mo_SPA_Admin_PG.U_Code = ml_U_Code
                mo_SPA_Admin_PG.LoginName = ms_LoginName
                Set mo_SPA_Admin_PG.DB = mo_Db
                
                Call mo_SPA_Admin_PG.Load_A_COM
                If Not mo_SPA_Admin_PG.Initialized Then
                    Call Err.Raise(ArmErr.CompFncFailed, "mo_SPA_Admin_PG.Initialized", "SPA_Admin_PG cannot was not initialised")
                End If
                mo_SPA_Admin_PG.Zorder
            End If
            Set mt_MainConfig(Index).ActiveDetailControl = mo_SPA_Admin_PG
        Case "SPA_MKT"
            If mo_SPA_Admin_MKT Is Nothing Then
                Set mo_SPA_Admin_MKT = UserControl.Controls.Add(C_ProgID & ".SPA_Admin_MKT", "mo_SPA_Admin_MKT", fra_MainItem(ll_frameIndex))
                mo_SPA_Admin_MKT.Visible = False
                Call mo_SPA_Admin_MKT.Move(0, 0, fra_MainItem(ll_frameIndex).Width, fra_MainItem(ll_frameIndex).Height)
                
                mo_SPA_Admin_MKT.Language_Code = ms_Language_Code
                mo_SPA_Admin_MKT.U_Code = ml_U_Code
                mo_SPA_Admin_MKT.LoginName = ms_LoginName
                Set mo_SPA_Admin_MKT.DB = mo_Db
                
                Call mo_SPA_Admin_MKT.Load_A_COM
                If Not mo_SPA_Admin_MKT.Initialized Then
                    Call Err.Raise(ArmErr.CompFncFailed, "mo_SPA_Admin_MKT.Initialized", "SPA_Admin_MKT cannot was not initialised")
                End If
                mo_SPA_Admin_MKT.Zorder
            End If
            Set mt_MainConfig(Index).ActiveDetailControl = mo_SPA_Admin_MKT
        Case "SPA_PG_MKT"
            If mo_SPA_Admin_PG_MKT Is Nothing Then
                Set mo_SPA_Admin_PG_MKT = UserControl.Controls.Add(C_ProgID & ".SPA_Admin_PG_MKT", "mo_SPA_Admin_PG_MKT", fra_MainItem(ll_frameIndex))
                mo_SPA_Admin_PG_MKT.Visible = False
                Call mo_SPA_Admin_PG_MKT.Move(0, 0, fra_MainItem(ll_frameIndex).Width, fra_MainItem(ll_frameIndex).Height)
                
                mo_SPA_Admin_PG_MKT.Language_Code = ms_Language_Code
                mo_SPA_Admin_PG_MKT.U_Code = ml_U_Code
                mo_SPA_Admin_PG_MKT.LoginName = ms_LoginName
                Set mo_SPA_Admin_PG_MKT.DB = mo_Db
                
                Call mo_SPA_Admin_PG_MKT.Load_A_COM
                If Not mo_SPA_Admin_PG_MKT.Initialized Then
                    Call Err.Raise(ArmErr.CompFncFailed, "mo_SPA_Admin_PG_MKT.Initialized", "SPA_Admin_PG_MKT cannot was not initialised")
                End If
                mo_SPA_Admin_PG_MKT.Zorder
            End If
            Set mt_MainConfig(Index).ActiveDetailControl = mo_SPA_Admin_PG_MKT
        Case Else
    End Select
    Exit Sub
ErrHandler:
    Call ErrorHandler(Extender.Name & ".InitDetailControl")
End Sub

Private Sub InitMainFrame(ByVal al_ConfigIndex As Long)
On Error GoTo ErrHandler

Const VIEW_REQUEST = "exec TreeView_View_t_lst $ViewCode$,$Language_Code$"

Dim ll_frameIndex As Long
Dim ls_Request As String, ls_ToolbarInfo As String

    If al_ConfigIndex < 0 Then Exit Sub
    If mt_MainConfig(al_ConfigIndex).Initialized Then Exit Sub
    
    ll_frameIndex = mt_MainConfig(al_ConfigIndex).FrameIndex
    
    Call ResizeMain(al_ConfigIndex)
    
    Call LoadToolbar(tlb_Main(ll_frameIndex), mt_MainConfig(al_ConfigIndex).ToolbarID)
    Call tlb_Main(ll_frameIndex).DisplayFace(mt_MainConfig(al_ConfigIndex).ToolbarFace)
    
    ls_Request = ReplacePlaceHolder(VIEW_REQUEST, "$ViewCode$", SQLStr(mt_MainConfig(al_ConfigIndex).ViewCode))
    ls_Request = ReplacePlaceHolder(ls_Request, "$Language_Code$", SQLStr(ms_Language_Code))
    
    If mt_MainConfig(al_ConfigIndex).HasTreeview Then
        cbo_View(ll_frameIndex).Request = ls_Request
        Call cbo_View(ll_frameIndex).Load
        
        If cbo_View(ll_frameIndex).Count = 0 Then
            cbo_View(ll_frameIndex).Visible = False
        Else
            Dim ll_Idx As Long, ll_Count As Long
            ll_Count = cbo_View(ll_frameIndex).Count - 1
            ReDim mt_MainConfig(al_ConfigIndex).mTreeViewInfos(ll_Count)
            For ll_Idx = 0 To ll_Count
                mt_MainConfig(al_ConfigIndex).mTreeViewInfos(ll_Idx).Loaded = False
                mt_MainConfig(al_ConfigIndex).mTreeViewInfos(ll_Idx).TreeViewCode = cbo_View(ll_frameIndex).ComboItems(ll_Idx + 1).Key
            Next
            
            Call cbo_View(ll_frameIndex).SearchItem("X", "TV_Default", 0)
        End If
    Else
        Call ReloadMainFilterGrid
    End If
    mt_MainConfig(al_ConfigIndex).Initialized = True
    Exit Sub
ErrHandler:
    Call ErrorMessage("InitMainFrame")
End Sub

Private Sub InitFrameControls(ByRef av_InitControls As Variant)
On Error GoTo ErrHandler

Dim lo_Control As Control
Dim ll_Index As Long
Dim ls_Request As String

    If Not IsArray(av_InitControls) Then Exit Sub
    mb_InternalInit = True
    For ll_Index = 0 To UBound(av_InitControls)
        Set lo_Control = av_InitControls(ll_Index)(0)
        
        lo_Control.Tag = av_InitControls(ll_Index)(1)
        lo_Control.Visible = av_InitControls(ll_Index)(2)
        Select Case UCase(TypeName(lo_Control))
            Case "ARMCOMBOBOX"
                If UBound(av_InitControls(ll_Index)) >= 3 Then
                    ls_Request = av_InitControls(ll_Index)(3)
                    ls_Request = ReplaceCommonPlaceholders(ls_Request)
                    lo_Control.Request = ls_Request
                End If
            Case "TEXTBOX", "ARMPICKER"
                If UBound(av_InitControls(ll_Index)) >= 4 Then
                    lo_Control.MaxLength = av_InitControls(ll_Index)(4)
                End If
            Case "A_CALOCX"
            Case "LABEL", "CHECKBOX"
                lo_Control.Caption = "#" & lo_Control.Tag
        End Select
    Next
    mb_InternalInit = False
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("InitFrameControls")
End Sub

Private Sub InitMandatoryLabels(ByRef av_ListFieldsMandatory As Variant)
On Error GoTo ErrHandler

Dim ll_Index As Long
Dim lo_Label As Label

    For ll_Index = 0 To UBound(av_ListFieldsMandatory)
        If av_ListFieldsMandatory(ll_Index)(1) >= 0 Then
            Set lo_Label = lbl_Label(av_ListFieldsMandatory(ll_Index)(1))
            lo_Label.FontBold = True
        End If
    Next
    Exit Sub
ErrHandler:
    Call ErrorHandler("InitMandatoryLabels")
End Sub

Private Function GetSelectedRootNode(ByRef ao_Tree As ArmTreeView) As MSComctlLib.Node
On Error GoTo ErrHandler

Dim lo_Node  As Object

    Set GetSelectedRootNode = Nothing
    Set lo_Node = ao_Tree.SelectedItem
    If Not (lo_Node Is Nothing) Then
        While Not (lo_Node.Parent Is Nothing)
            Set lo_Node = lo_Node.Parent
        Wend
    End If
    Set GetSelectedRootNode = lo_Node
    Exit Function
ErrHandler:
    Call ErrorHandler("GetSelectedRootNode")
End Function

Private Sub SetMode(ByVal ae_Mode As eMode)
On Error GoTo ErrHandler

    Exit Sub
ErrHandler:
    Call ErrorHandler("SetMode")
End Sub

Private Sub ResetFrameControls(ByRef ao_Frame As Frame)
On Error GoTo ErrHandler

Dim lo_Control As Control

    mb_InternalInit = True
    For Each lo_Control In UserControl.Controls
    
        If HasContainer(lo_Control, ao_Frame) Then
            If StrComp(lo_Control.Name, "chk_Repositioning", vbTextCompare) <> 0 Then
                Select Case UCase(TypeName(lo_Control))
                    Case "ARMCOMBOBOX"
                        Call lo_Control.Clear
                        lo_Control.Tag = ""
                        lo_Control.Request = ""
                        lo_Control.Visible = False
                    Case "ARMPICKER"
                        Call lo_Control.Clear
                        lo_Control.Tag = ""
                        lo_Control.Visible = False
                    Case "CHECKBOX"
                        lo_Control.Value = Unchecked
                        lo_Control.Tag = ""
                        lo_Control.Caption = ""
                        lo_Control.Visible = False
                    Case "TEXTBOX"
                        lo_Control.Tag = ""
                        lo_Control.Text = ""
                        lo_Control.Visible = False
                    Case "A_CALOCX"
                        Call lo_Control.reinit_cal
                        lo_Control.Tag = ""
                        lo_Control.Visible = False
                    Case "LABEL"
                        lo_Control.Tag = ""
                        lo_Control.Caption = ""
                        lo_Control.FontBold = False
                        lo_Control.Visible = False
                End Select
            End If
        End If
    Next
    mb_InternalInit = False
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("ResetFrameControls")
End Sub

Private Sub LoadToolbar(ByRef ao_Toolbar As Object, ByVal al_Id As Long)
On Error GoTo ErrHandler

Dim ls_Request As String
Dim ls_ToolbarInfo As String

    ' no toolbar definition ID, do not load anything
    If (al_Id = 0) Or (ms_ToolbarRequest = "") Then Exit Sub
    'load all definition strings only once and keep it in cursor
    If mc_Toolbars = 0 Then
        ls_Request = ReplacePlaceHolder(ms_ToolbarRequest, "$Module$", SQLStr(SCREEN_NAME))
        mc_Toolbars = OpenSQLSafe(mo_Db, ls_Request)
    End If
    
    If mo_Db.Find(mc_Toolbars, "Id", al_Id) < 0 Then
        Err.Raise ArmErr.InvalidValue, ao_Toolbar.Name, "Toolbar not found in toolbars_definitions ID:" & al_Id
    End If
    
    ls_ToolbarInfo = mo_Db.GetFields(mc_Toolbars, "info")
    If Not ao_Toolbar.SetToolbarInfoStringParameters(ls_ToolbarInfo, Left(ls_ToolbarInfo, 3)) Then
        Err.Raise ArmErr.InvalidValue, ao_Toolbar.Name, "SetToolbarInfoStringParameters failed for toolbar ID:" & al_Id
    End If
    Call ao_Toolbar.DisplayFace("0")
    Exit Sub
ErrHandler:
    Call ErrorHandler("LoadToolbar")
End Sub

Private Function FindMainConfigByFrameIndex(ByVal al_FrameIndex As Long) As Long
On Error GoTo ErrHandler

Dim ll_Index As Long

    FindMainConfigByFrameIndex = -1
    For ll_Index = 0 To UBound(mt_MainConfig)
        If mt_MainConfig(ll_Index).FrameIndex = al_FrameIndex Then
            FindMainConfigByFrameIndex = ll_Index
            Exit Function
        End If
    Next
    Exit Function
ErrHandler:
    Call ErrorHandler("FindMainConfigByFrameIndex")
End Function

Private Function FindMainConfigByName(ByVal as_Name As String) As Long
On Error GoTo ErrHandler

Dim ll_Index As Long

    FindMainConfigByName = -1
    For ll_Index = 0 To UBound(mt_MainConfig)
        If StrComp(mt_MainConfig(ll_Index).NameFrame, as_Name, vbTextCompare) = 0 Then
            FindMainConfigByName = ll_Index
            Exit Function
        End If
    Next
    Exit Function
ErrHandler:
    Call ErrorHandler("FindMainConfigByName")
End Function

'to check if our current position in treeview will allow us to display added/updated item in grid
Private Function IsItemSelectedInTree(ByVal al_DetailIndex As Long, ByRef ao_Tree As ArmTreeView, ByVal av_PathData As Variant) As Boolean
On Error GoTo ErrHandler
    
Dim ll_SelLevel As Long, ll_IdxLvl As Long
Dim lo_Node As Object
Dim lb_CheckDone As Boolean


    IsItemSelectedInTree = IsItemSelectedInTreeCustom(al_DetailIndex, ao_Tree, av_PathData, lb_CheckDone)
    If lb_CheckDone Then Exit Function
    
    IsItemSelectedInTree = False
    
    Set lo_Node = ao_Tree.SelectedItem
    If lo_Node Is Nothing Then Exit Function
    If Not IsArray(av_PathData) Then Exit Function
    
    ll_SelLevel = lo_Node.Tag.ml_Level
    
    If ll_SelLevel > UBound(av_PathData) Then
        IsItemSelectedInTree = False
        Exit Function
    End If
    
    For ll_IdxLvl = ll_SelLevel To 0 Step -1
        If lo_Node Is Nothing Then Exit Function
        If Not IsArray(av_PathData(ll_IdxLvl)) Then
            Err.Raise ArmErr.InvalidValue, "av_PathData(ll_IdxLvl)", "Path data element is not an array: " & ll_IdxLvl
        End If
        If StrComp(lo_Node.Tag.IDValue, av_PathData(ll_IdxLvl)(0), vbTextCompare) <> 0 Then
            Exit Function
        End If
        Set lo_Node = lo_Node.Parent
    Next
    IsItemSelectedInTree = True
    Exit Function
ErrHandler:
    Call ErrorHandler("IsItemSelectedInTree")
End Function

' Return true if have created the node
' TODO : Manage the third parameter...
Private Function FindInTreeView(ByRef ao_Tree As ArmTreeView, ByVal av_PathData As Variant, ByVal ab_AutoCreate As Boolean, ByVal ab_Expand As Boolean) As Node
On Error GoTo ErrHandler

Dim lb_Internal As Boolean
Dim lo_Node As Object
Dim ll_LvlIdx As Long, ll_DataIdx As Long
Dim ls_Key As String, ls_Desc As String
    
    Set FindInTreeView = Nothing
    lb_Internal = mb_InternalInit
    mb_InternalInit = True
    Set lo_Node = Nothing
    For ll_LvlIdx = 0 To UBound(av_PathData)
        If Not IsArray(av_PathData(ll_LvlIdx)) Then
            Err.Raise ArmErr.InvalidValue, "av_PathData(ll_LvlIdx)", "Path data element is not an array"
        End If
        
        If UBound(av_PathData(ll_LvlIdx)) = 1 Then
            ls_Key = av_PathData(ll_LvlIdx)(0)
            ls_Desc = av_PathData(ll_LvlIdx)(1)
        ElseIf UBound(av_PathData(ll_LvlIdx)) > 1 Then
            ls_Key = av_PathData(ll_LvlIdx)(0)
            ls_Desc = av_PathData(ll_LvlIdx)(2)
        Else
            Err.Raise ArmErr.InvalidValue, "av_PathData(ll_LvlIdx)", "Invalid count of path data elements"
        End If
        
        If ao_Tree.Find(ls_Key, 0, lo_Node, ll_LvlIdx) Then
            Set lo_Node = ao_Tree.SelectedItem
        Else
            If ab_AutoCreate Then
                'TODO add additional data from detail tree into main tree data
                Set lo_Node = ao_Tree.AddNode(lo_Node, ls_Key, ls_Desc, 1, 2, LoadTypeChildsDemand)
                If lo_Node Is Nothing Then
                    Err.Raise ArmErr.CompFncFailed, "ao_Tree.AddNode", "Function failed to create node"
                End If
                For ll_DataIdx = 1 To UBound(av_PathData(ll_LvlIdx))
                    Call lo_Node.Tag.SetData(ll_DataIdx, av_PathData(ll_LvlIdx)(ll_DataIdx))
                Next
                lo_Node.Selected = True
            Else
                GoTo CleanUp
            End If
        End If
        If (Not lo_Node.Expanded) And (ll_LvlIdx <> UBound(av_PathData)) Then
            If Not ab_Expand Then GoTo CleanUp
            Call ao_Tree.ExpandNode(lo_Node)
        End If
    Next
    
    Set FindInTreeView = lo_Node
        
CleanUp:
    Set lo_Node = Nothing
    mb_InternalInit = lb_Internal
    Exit Function
ErrHandler:
    Set lo_Node = Nothing
    mb_InternalInit = lb_Internal
    Call ErrorHandler("FindInTreeView")
End Function

Private Function GetCurrentPathData(ByRef ao_data As Dictionary, ByVal as_Path As String) As Variant
On Error GoTo ErrHandler

    Dim las_Paths() As String, lv_pathData As Variant
    Dim ll_IdxPath As Long
    Dim lsa_Pattern As Variant
    Dim ll_i As Long
        
        las_Paths = Split(as_Path, SEP)
        ReDim lv_pathData(LBound(las_Paths) To UBound(las_Paths))
        
        For ll_IdxPath = LBound(las_Paths) To UBound(las_Paths)
            lsa_Pattern = Split(las_Paths(ll_IdxPath), SEP1)
            
            For ll_i = LBound(lsa_Pattern) To UBound(lsa_Pattern)
                If ao_data.Exists(lsa_Pattern(ll_i)) Then
                    lsa_Pattern(ll_i) = ao_data.Item(lsa_Pattern(ll_i))
                Else
                    lsa_Pattern(ll_i) = "MISSING DATA:"
                End If
            Next ll_i
            lv_pathData(ll_IdxPath) = lsa_Pattern
        Next ll_IdxPath
        
        GetCurrentPathData = lv_pathData
    Exit Function

ErrHandler:
    Call ErrorHandler("GetCurrentPathData")

End Function

Private Function DeleteNode(ByRef ao_TreeView As ArmTreeView, ByRef ao_Node As Node) As Node
On Error GoTo ErrHandler

    Dim lo_Node As Node, lo_parentNode As Node, lo_PreviousNode As Node

    Set lo_Node = ao_Node
    
    While Not lo_Node Is Nothing
        Call lo_Node.Tag.SetData(3, Val(lo_Node.Tag.GetData(3)) - 1)
        Set lo_Node = lo_Node.Parent
    Wend
    
    Set lo_Node = ao_Node
    Do While (lo_Node.Tag.GetData(3) = 0)
        Set lo_parentNode = lo_Node.Parent
        Set lo_PreviousNode = lo_Node.Previous
        Call ao_TreeView.RemoveNode(lo_Node)
        Set lo_Node = lo_parentNode
        If lo_Node Is Nothing Then Exit Do
    Loop
    Set ao_Node = Nothing

    Set DeleteNode = IIf(lo_parentNode Is Nothing, lo_PreviousNode, lo_parentNode)
    Exit Function
    
ErrHandler:
    If (Not lo_Node Is Nothing) Then Set lo_Node = Nothing
    If (Not lo_parentNode Is Nothing) Then Set lo_parentNode = Nothing
    If (Not lo_PreviousNode Is Nothing) Then Set lo_PreviousNode = Nothing
    Call ErrorHandler("DeleteNode")

End Function

'to check if updated or added item conform filter
'(there is no filter at this time but it is prepared)
Private Function IsItemInFilter(ByRef ao_data As Dictionary, ByVal al_MainConfig As Long) As Boolean
On Error GoTo ErrHandler

Dim lb_CheckDone As Boolean

    IsItemInFilter = IsItemInFilterCustom(ao_data, al_MainConfig, lb_CheckDone)
    If lb_CheckDone Then Exit Function
    
    IsItemInFilter = True
    Exit Function
ErrHandler:
    Call ErrorHandler("IsItemInFilter")
End Function

Private Sub GotoPreviousItem(ByVal al_DetailIndex As Long, ByRef ao_grid As ArmGrid)
On Error GoTo ErrHandler
    
    If ao_grid.PreviousItem Then
        Call UpdateDetailToolbarCustom(al_DetailIndex)
    Else
        Call MsgBox(MsgText(666, ms_Language_Code, "#No more previous item"), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
    End If
    Exit Sub
ErrHandler:
    Call ErrorHandler("GotoPreviousItem")
End Sub

Private Sub GotoNextItem(ByVal al_DetailIndex As Long, ByRef ao_grid As ArmGrid)
On Error GoTo ErrHandler

    If ao_grid.NextItem Then
        Call UpdateDetailToolbarCustom(al_DetailIndex)
    Else
        Call MsgBox(MsgText(666, ms_Language_Code, "#No more next item"), vbInformation, App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
    End If
    Exit Sub
ErrHandler:
    Call ErrorHandler("GotoNextItem")
End Sub

Private Sub Controls_LoadDefaultValue(ByRef av_ListFieldsDefaultValue As Variant)
On Error GoTo ErrHandler

    Dim ll_Idx As Long, ll_Count As Long
    Dim lv_Params As Variant
    Dim lo_Control As Object
    Dim ls_value As String

    ll_Count = UBound(av_ListFieldsDefaultValue)

    For ll_Idx = 0 To ll_Count
            Set lo_Control = av_ListFieldsDefaultValue(ll_Idx)(0)
            Select Case UCase(TypeName(lo_Control))
                Case "FRAME", "LABEL", "MSFLEXGRID", "TOOLBARCONTROL"
                    ' Do nothing !
                Case "TEXTBOX"
                    lo_Control.Text = av_ListFieldsDefaultValue(ll_Idx)(1)
                Case "A_CALOCX"
                    ls_value = av_ListFieldsDefaultValue(ll_Idx)(1)
                    If StrComp(ls_value, "Date") = 0 Then
                        lo_Control.date_courte = Format(Date, "dd\/mm\/yyyy")
                    ElseIf StrComp(Left(ls_value, 5), "Date+") = 0 Then
                        lo_Control.date_courte = Format(Date + CLng(Mid(ls_value, 6)), "dd\/mm\/yyyy")
                    ElseIf StrComp(Left(ls_value, 5), "Date-") = 0 Then
                        lo_Control.date_courte = Format(Date - CLng(Mid(ls_value, 6)), "dd\/mm\/yyyy")
                    Else
                        lo_Control.date_courte = ls_value
                    End If
                Case "ARMGRID", "ARMCHECKVIEW", "COMMANDBUTTON", "ARMTREEVIEW", "LISTBOX", "PICTUREBOX", "TABSTRIP"
                
                Case "OPTIONBUTTON", "CHECKBOX"
                    lo_Control.Value = av_ListFieldsDefaultValue(ll_Idx)(1)
                Case "ARMCOMBOBOX"
                    lv_Params = Split(av_ListFieldsDefaultValue(ll_Idx)(1), SEP)
                    If Not lo_Control.SearchItem(lv_Params(0)) Then
                        If UBound(lv_Params) >= 1 Then
                            Call lo_Control.AddItem(Array(lv_Params(0), lv_Params(1)))
                        Else
                            Call lo_Control.Load ' load only once and remember found default value. Do not use any hardcoded default value
                            If lo_Control.SearchItem(lv_Params(0)) Then
                                av_ListFieldsDefaultValue(ll_Idx)(1) = lv_Params(0) & SEP & lo_Control.Text
                            End If
                        End If
                    End If
                Case "ARMPICKER"
                    lv_Params = Split(av_ListFieldsDefaultValue(ll_Idx)(1), SEP)
                    lo_Control.ItemCode = lv_Params(0)
                    If UBound(lv_Params) >= 1 Then
                        lo_Control.ItemDescription = lv_Params(1)
                    End If
                                    
                Case Else
                    Debug.Print "Controls_LoadDefaultValue " & UCase(TypeName(lo_Control))
            End Select
    Next
    Set lo_Control = Nothing
    Exit Sub
ErrHandler:
    Call ErrorHandler("Controls_LoadDefaultValue")
End Sub

Private Function GetTreeViewInfo(ByRef aTVInfos() As TTreeViewInfo, ByVal AScreenName As String, ByVal aTVCode As String) As TTreeViewInfo
On Error GoTo ErrHandler
    Dim lIdx As Long, lCount As Long
    Dim lTreeView As TTreeViewInfo, lFound As Boolean
    
    ' Search in the array
    lCount = UBound(aTVInfos)
    lFound = False
    For lIdx = 0 To lCount
        If aTVInfos(lIdx).TreeViewCode = aTVCode Then
            If Not aTVInfos(lIdx).Loaded Then
                aTVInfos(lIdx) = GetTreeViewInfoFromDB(AScreenName, aTVCode)
            End If
            lTreeView = aTVInfos(lIdx)
            lFound = True
            Exit For
        End If
    Next
    
    If Not lFound Then
        Call Err.Raise(ArmErr.InvalidArgument, "TreeviewInfo", "TreeViewInfo not found. AScreenName=" & AScreenName & " aTVCode=" & aTVCode)
    End If
    
    GetTreeViewInfo = lTreeView
    Exit Function
ErrHandler:
    Call ErrorHandler("GetTreeViewInfo")

End Function

Private Function ApplyTVFilters(ByVal al_MainIndex As Long, ByVal av_Request As Variant) As Variant
On Error GoTo ErrHandler
    Dim lv_Requests As Variant
    
    If IsArray(av_Request) Then
        ReDim lv_Requests(UBound(av_Request))
        Dim ll_Idx As Long, ll_Count As Long
        ll_Count = UBound(lv_Requests)
        For ll_Idx = 0 To ll_Count
            lv_Requests(ll_Idx) = ReplaceTVFiltersHolders(al_MainIndex, av_Request(ll_Idx))
            lv_Requests(ll_Idx) = ReplaceLanguagePlaceholderFromToolbar(lv_Requests(ll_Idx))
            lv_Requests(ll_Idx) = ReplaceCommonPlaceholders(lv_Requests(ll_Idx))
        Next
    Else
        ReDim lv_Requests(0)
        lv_Requests(0) = ReplaceTVFiltersHolders(al_MainIndex, av_Request)
        lv_Requests(0) = ReplaceLanguagePlaceholderFromToolbar(lv_Requests(0))
        lv_Requests(0) = ReplaceCommonPlaceholders(lv_Requests(0))
    End If

    ApplyTVFilters = lv_Requests
    Exit Function
ErrHandler:
    Call ErrorHandler("ApplyTVFilters")
End Function

Private Function ReplaceTVFiltersHolders(ByVal al_MainIndex As Long, ByVal as_Request As String) As String
On Error GoTo ErrHandler

    Dim ls_Request As String
    Dim ll_frameIndex As Long

    ll_frameIndex = mt_MainConfig(al_MainIndex).FrameIndex
    ls_Request = ReplaceRequestByFrameData(as_Request, fra_MainFilter(ll_frameIndex))
    ReplaceTVFiltersHolders = ls_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceTVFiltersHolders")
End Function

Private Function ReplaceTVHolders(ByVal as_Request As String) As String
On Error GoTo ErrHandler
    Dim ls_Buffer As String
    
    ls_Buffer = ReplacePlaceHolder(as_Request, "$language_code$", SQLStr(ms_Language_Code))
    ls_Buffer = ReplacePlaceHolder(ls_Buffer, "$u_code$", ml_U_Code)
    ReplaceTVHolders = ls_Buffer
    
CleanUp:
    Exit Function

ErrHandler:
    Call ErrorHandler("ReplaceTVHolders")
End Function

Private Sub ReloadMainGrid()
On Error GoTo ErrHandler

Dim ll_frameIndex As Long, ll_MainConfigIndex As Long

    ll_MainConfigIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    ll_frameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
    
    If tvw_Main(ll_frameIndex).Checkboxes = True Then
        grd_Main(ll_frameIndex).Requests = ApplyTVFilters(ll_MainConfigIndex, tvw_Main(ll_frameIndex).CheckedNodesRequests)
    Else
        grd_Main(ll_frameIndex).Requests = ApplyTVFilters(ll_MainConfigIndex, tvw_Main(ll_frameIndex).SelectedNodeRequest)
    End If
    
    If Not grd_Main(ll_frameIndex).Load(grd_Main(ll_frameIndex).Requests, False, , , True) Then
        Err.Raise ArmErr.CompFncFailed, "grd_Main(" & ll_frameIndex & ").Execute", "Load grid failed"
    End If
    
    mt_MainConfig(ll_MainConfigIndex).CurrentTvwSelMethod = IIf(tvw_Main(ll_frameIndex).Checkboxes, eTvwSelMethod.etmCheckBoxes, eTvwSelMethod.etmBranch)
    Call UpdateMainToolbarCustom(ll_MainConfigIndex)
    Exit Sub
ErrHandler:
    Call ErrorHandler("ReloadMainGrid")
End Sub

Private Sub ReloadMainTreeview()
On Error GoTo ErrHandler
    
    mb_InternalInit = True
    Dim lb_Grid As Boolean
    Dim ll_frameIndex As Long, ll_MainConfigIndex As Long

    ll_MainConfigIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    If mt_MainConfig(ll_MainConfigIndex).HasTreeview Then
        ll_frameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
        tvw_Main(ll_frameIndex).Refresh
        Call ReloadMainGrid
    End If
    
    mb_InternalInit = False
    
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("ReloadMainTreeview")
End Sub

Private Sub ReloadMainFilterGrid()
On Error GoTo ErrHandler
    
    mb_InternalInit = True
    Dim lb_Grid As Boolean
    Dim ll_frameIndex As Long, ll_MainConfigIndex As Long
    Dim ls_Request As String

    ll_MainConfigIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    ll_frameIndex = mt_MainConfig(ll_MainConfigIndex).FrameIndex
   
    If grd_Main(ll_frameIndex).Cols = 0 Then
        If Not grd_Main(ll_frameIndex).SetColumns(mt_MainConfig(ll_MainConfigIndex).MainGridColumns) Then
            Err.Raise ArmErr.CompFncFailed, "grd_Main", "Method SetColumns failed."
        End If
        Call LoadLabels(mo_Db, fra_MainItem(ll_frameIndex), SCREEN_NAME, ms_Language_Code)
    End If
    
    If Not mt_MainConfig(ll_MainConfigIndex).HasTreeview Then
        ' JN grid is not driven by treeview
    ls_Request = mt_MainConfig(ll_MainConfigIndex).GridRequest
    ls_Request = ReplaceRequestByFrameData(ls_Request, fra_MainFilter(ll_frameIndex))
    ls_Request = ReplaceLanguagePlaceholderFromToolbar(ls_Request)
    ls_Request = ReplaceCommonPlaceholders(ls_Request)
'    ls_Request = ReplacePlaceHolder(ls_Request, "$BI_SAP_CODE$", "NULL")
    

    If Not grd_Main(ll_frameIndex).Load(ls_Request, False, , , True) Then
        Err.Raise ArmErr.CompFncFailed, "grd_Main(" & ll_frameIndex & ").Load", "Load grid failed: " & ls_Request
    End If
    End If
    mb_InternalInit = False
    
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("ReloadMainTreeview")
End Sub


Public Sub AddDroppedCheckItems(ByRef ao_chkview As ArmCheckView)
On Error GoTo ErrHandler

Dim ll_Index As Long
Dim ll_Count As Long
Dim lo_ItemInfo As ArmItemInfo

    ll_Count = ao_chkview.RoleList("VIEW").Count
    For ll_Index = 1 To ll_Count
        If ao_chkview.RoleList("EDIT").GetItem(ao_chkview.RoleList("VIEW").GetKey(ll_Index)) Is Nothing Then
            Set lo_ItemInfo = ao_chkview.RoleList("VIEW").Items(ll_Index)
            Call ao_chkview.RoleList("EDIT").AddItemInfo(Array(lo_ItemInfo.GetData(0), lo_ItemInfo.GetData(1), 1), True, True)
        End If
    Next
    Call ao_chkview.RoleList("EDIT").DisplayList
    Exit Sub
ErrHandler:
    Call ErrorHandler("AddDroppedCheckItems")
End Sub

Public Sub RemoveDroppedCheckItems(ByRef ao_chkview As ArmCheckView)
On Error GoTo ErrHandler

Dim ll_Index As Long
Dim ll_Count As Long
Dim lo_ItemInfo As ArmItemInfo

    ll_Count = ao_chkview.RoleList("EDIT").Count
    For ll_Index = ll_Count To 1 Step -1
        Set lo_ItemInfo = ao_chkview.RoleList("EDIT").Items(ll_Index)
        If UBound(lo_ItemInfo.Data) > 1 Then
            Call ao_chkview.RoleList("EDIT").Items.Remove(ll_Index)
        End If
        Set lo_ItemInfo = Nothing
    Next
    Call ao_chkview.RoleList("EDIT").DisplayList
    Exit Sub
ErrHandler:
    Call ErrorHandler("RemoveDroppedCheckItems")
End Sub

Private Sub LoadListView(ByVal ao_ListView As MSComctlLib.ListView, ByVal as_Request As String)
On Error GoTo ErrHandler

Dim ll_cursor As Long
Dim lo_item As MSComctlLib.ListItem
Dim lo_SubItem As MSComctlLib.ListSubItem
Dim ll_Index As Long

    Call ao_ListView.ListItems.Clear
    ll_cursor = mo_Db.OpenSQL(as_Request)
    If ll_cursor > 0 Then
        While Not mo_Db.EOF(ll_cursor)
            Set lo_item = ao_ListView.ListItems.Add(, "KEY" & mo_Db.GetFields(ll_cursor, 0), mo_Db.GetFields(ll_cursor, 1))
            If mo_Db.FieldCount(ll_cursor) > 2 Then
                For ll_Index = 2 To mo_Db.FieldCount(ll_cursor) - 1
                    Set lo_SubItem = lo_item.ListSubItems.Add(, , mo_Db.GetFields(ll_cursor, ll_Index))
                Next
            End If
            Call mo_Db.Next(ll_cursor)
        Wend
        Call mo_Db.Close(ll_cursor)
    End If
    Exit Sub
ErrHandler:
    Call ErrorHandler("LoadListView")
End Sub

Private Sub CheckListView(ByVal ao_ListView As MSComctlLib.ListView, ByVal as_Request As String)
On Error GoTo ErrHandler

Dim ll_cursor As Long
Dim lo_item As MSComctlLib.ListItem
Dim lo_NewItem As MSComctlLib.ListItem
Dim ls_ItemKey As String, ls_ItemText As String

    For Each lo_item In ao_ListView.ListItems
        lo_item.Checked = False
        lo_item.Tag = ""
    Next lo_item
    ll_cursor = mo_Db.OpenSQL(as_Request)
    If ll_cursor > 0 Then
        While Not mo_Db.EOF(ll_cursor)
            For Each lo_item In ao_ListView.ListItems
                If StrComp(lo_item.Key, "KEY" & mo_Db.GetFields(ll_cursor, 0), vbTextCompare) = 0 Then
                    ls_ItemText = lo_item.Text
                    ls_ItemKey = lo_item.Key
                    Call ao_ListView.ListItems.Remove(lo_item.Index)
                    Set lo_NewItem = ao_ListView.ListItems.Add(1, ls_ItemKey, ls_ItemText)
                    lo_NewItem.Checked = True
                    lo_NewItem.Tag = "X"
                    Exit For
                End If
            Next lo_item
            Call mo_Db.Next(ll_cursor)
        Wend
        Call mo_Db.Close(ll_cursor)
    End If
    Call ao_ListView.Refresh
    Exit Sub
ErrHandler:
    Call ErrorHandler("CheckListView")
End Sub

Private Sub ClearCollection(ByVal ao_Collection As Collection)
On Error GoTo ErrHandler

    While ao_Collection.Count > 0
        Call ao_Collection.Remove(1)
    Wend
    Exit Sub
ErrHandler:
    Call ErrorHandler("ClearCollection")
End Sub


Private Function SqlInt(ByVal av_Data As Variant) As String
On Error GoTo ErrHandler

    SqlInt = "NULL"
    If IsNull(av_Data) Then av_Data = ""
    If Trim(CStr(av_Data)) <> "" Then
        SqlInt = CStr(av_Data)
    End If
    Exit Function
ErrHandler:
    Call ErrorHandler("SqlInt")
End Function

Private Function SqlDbl(ByVal av_Data As Variant) As String
On Error GoTo ErrHandler

    SqlDbl = "NULL"
    If IsNull(av_Data) Then av_Data = ""
    If Trim(CStr(av_Data)) <> "" Then
        SqlDbl = Str(av_Data)
    End If
    Exit Function
ErrHandler:
    Call ErrorHandler("SqlDbl")
End Function

Private Function SqlDate(ByVal av_Data As Variant) As String
On Error GoTo ErrHandler

    SqlDate = "NULL"
    If IsNull(av_Data) Then av_Data = ""
    If (Trim(CStr(av_Data)) <> "") And (CStr(av_Data) <> "0") Then
        SqlDate = "'" & Format(av_Data, "yyyy-mm-dd") & "'"
    End If
    Exit Function
ErrHandler:
    Call ErrorHandler("SqlDate")
End Function


Private Function SQLStr(ByVal as_Data As String) As String
On Error GoTo ErrHandler

    SQLStr = "'" & Replace(as_Data, "'", "''") & "'"
    Exit Function
ErrHandler:
    Call ErrorHandler("SqlStr")
End Function

Private Function GetComboKey(ByVal ao_Combo As ArmCombobox) As String
On Error GoTo ErrHandler

    GetComboKey = ""
    If Not (ao_Combo.SelectedItem Is Nothing) Then
        GetComboKey = Trim(CStr(ao_Combo.SelectedItem.Key))
    End If
    Exit Function
ErrHandler:
    Call ErrorHandler("GetComboKey")
End Function

Private Function CustomReplacePlaceholder(ByRef as_Request As String, ByVal as_PlaceHolder As String, ByVal as_DefaultValue As String) As Boolean
On Error GoTo ErrHandler

    If (StrComp(as_PlaceHolder, "$FRI_Language_Code$", vbTextCompare) = 0) And (as_DefaultValue = "''") Then
        as_Request = Replace(as_Request, as_PlaceHolder, "NULL", , , vbTextCompare)
        CustomReplacePlaceholder = True
    ElseIf (StrComp(as_PlaceHolder, "$DHG_Language_Code$", vbTextCompare) = 0) And (as_DefaultValue = "''") Then
        as_Request = Replace(as_Request, as_PlaceHolder, "NULL", , , vbTextCompare)
        CustomReplacePlaceholder = True
    End If
    CustomReplacePlaceholder = False
    Exit Function
ErrHandler:
    Call ErrorHandler("CustomReplacePlaceholder")
End Function

Private Function ReplacePlaceHolder(ByVal as_Request As String, ByVal as_PlaceHolder As String, ByVal as_DefaultValue As String) As String
On Error GoTo ErrHandler
    
    If Not CustomReplacePlaceholder(as_Request, as_PlaceHolder, as_DefaultValue) Then
        as_Request = Replace(as_Request, as_PlaceHolder, as_DefaultValue, , , vbTextCompare)
    End If
    ReplacePlaceHolder = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplacePlaceholder")
End Function

Private Function ReplaceKeyPlaceholders(ByVal as_Request As String, ByVal av_Key As Variant) As String
On Error GoTo ErrHandler

Dim ll_Index As Long

    If Not IsArray(av_Key) Then av_Key = Array(av_Key)
    
    For ll_Index = 0 To UBound(av_Key)
        as_Request = ReplacePlaceHolder(as_Request, "$Key" & (ll_Index + 1) & "$", SQLStr(av_Key(ll_Index)))
    Next
    ReplaceKeyPlaceholders = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceKeyPlaceholders")
End Function

Private Function ReplaceLanguagePlaceholderFromToolbar(ByVal as_Request As String) As String
On Error GoTo ErrHandler
Dim ll_frameIndex As Long, ll_MainIndex As Long

    ll_MainIndex = FindMainConfigByName(tbs_Main.SelectedItem.Key)
    ll_frameIndex = mt_MainConfig(ll_MainIndex).FrameIndex
    ReplaceLanguagePlaceholderFromToolbar = ReplacePlaceHolder(as_Request, "$toolbar_language_code$", SQLStr(tlb_Main(ll_frameIndex).Language))
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceLanguagePlaceholderFromToolbar")
End Function

Private Function ReplaceCommonPlaceholders(ByVal as_Request As String) As String
On Error GoTo ErrHandler

    as_Request = ReplacePlaceHolder(as_Request, "$language_code$", SQLStr(ms_Language_Code))
    as_Request = ReplacePlaceHolder(as_Request, "$Z_Creator$", SqlInt(ml_U_Code))
    as_Request = ReplacePlaceHolder(as_Request, "$U_Code$", SqlInt(ml_U_Code))
    as_Request = ReplacePlaceHolder(as_Request, "$Z_Last_Upd_User$", SqlInt(ml_U_Code))
    ReplaceCommonPlaceholders = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceCommonPlaceholders")
End Function

Private Function ReplacePlaceholderByControlValue(ByVal as_Request As String, ByRef ao_Control As Object) As String
On Error GoTo ErrHandler

Dim lsa_Columns() As String

    If Trim(ao_Control.Tag) = "" Then
        ReplacePlaceholderByControlValue = as_Request
        Exit Function
    End If
    
    Select Case UCase(TypeName(ao_Control))
        Case "ARMCOMBOBOX"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            
            If UBound(lsa_Columns) >= 0 Then
                If GetComboKey(ao_Control) = "" Then
                    as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", "NULL")
                Else
                    as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(GetComboKey(ao_Control)))
                End If
            End If
            If UBound(lsa_Columns) >= 1 Then
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(1) & "$", SQLStr(ao_Control.Text))
            End If
        Case "ARMPICKER"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            
            If UBound(lsa_Columns) >= 0 Then
                If (Trim(CStr(ao_Control.ItemCode)) = "") Or (CStr(ao_Control.ItemCode) = "0") Then
                    as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", "NULL")
                Else
                    as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(Trim(CStr(ao_Control.ItemCode))))
                End If
            End If
            If UBound(lsa_Columns) >= 1 Then
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(1) & "$", SQLStr(Trim(ao_Control.ItemDescription)))
            End If
        Case "OPTIONBUTTON"
            If ao_Control.Value = True Then
                lsa_Columns = Split(ao_Control.Tag, SEP)
                If UBound(lsa_Columns) > 0 Then
                    Select Case UCase(lsa_Columns(1))
                    Case "N"
                        as_Request = ReplacePlaceHolder(as_Request, "$" & ao_Control.Name & "$", ao_Control.Index)
                    Case Else
                        as_Request = ReplacePlaceHolder(as_Request, "$" & ao_Control.Name & "$", SQLStr(lsa_Columns(0)))
                    End Select
                Else
                    as_Request = ReplacePlaceHolder(as_Request, "$" & ao_Control.Name & "$", SQLStr(lsa_Columns(0)))
                End If
            End If
        Case "CHECKBOX"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            If ao_Control.Value = vbChecked Then
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr("X"))
            Else
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(""))
            End If
        Case "TEXTBOX"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            If UBound(lsa_Columns) > 0 Then
                Select Case UCase(lsa_Columns(1))
                Case "N"
                    If ao_Control.Text = "" Then
                       as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", "NULL")
                    Else
                       as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", ao_Control.Text)
                    End If
                Case Else
                    as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(ao_Control.Text))
                End Select
            Else
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(ao_Control.Text))
            End If
        Case "A_CALOCX"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SqlDate(ao_Control.date_dt))
        Case "TABSTRIP"
            lsa_Columns = Split(ao_Control.Tag, SEP)
            If ao_Control.SelectedItem Is Nothing Then
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", "NULL")
            Else
                as_Request = ReplacePlaceHolder(as_Request, "$" & lsa_Columns(0) & "$", SQLStr(ao_Control.SelectedItem.Key))
            End If
    End Select
    ReplacePlaceholderByControlValue = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplacePlaceholderByControlValue")
End Function

Private Function HasContainer(ByVal lo_Control As Control, ByRef lo_Container As Object) As Boolean
    Dim ll_Index As Long
    Dim lo_Object As Object

    On Error GoTo CleanUp   'not all controls support Container property
    HasContainer = False
    While Not (lo_Control Is Nothing)
        If lo_Control.Container Is lo_Container Then
            HasContainer = True
            Exit Function
        End If
        Set lo_Control = lo_Control.Container
    Wend

CleanUp:

End Function


Private Function ReplaceRequestByFrameData(ByVal as_Request As String, ByVal ao_Frame As Frame)
On Error GoTo ErrHandler

Dim lo_Control As Control
   
    For Each lo_Control In UserControl.Controls
        If HasContainer(lo_Control, ao_Frame) Then
            as_Request = ReplacePlaceholderByControlValue(as_Request, lo_Control)
        End If
    Next
    ReplaceRequestByFrameData = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceRequestByFrameData")
End Function

Private Function ReplaceRequestByGridData(ByVal ao_grid As ArmGrid, ByVal as_Request As String, ByVal al_Row As Long, ByVal as_Table As String) As String
On Error GoTo ErrHandler

Dim ll_ColIndex As Long
Dim ls_Data As String
    
    For ll_ColIndex = 0 To ao_grid.Cols - 1
'        If ao_Grid.Columns(ll_ColIndex).Key And (as_Table <> "") And (ao_Grid.Data(al_Row, STATUS_COLUMN) = "A") Then
'            ls_Data = SqlInt(ao_Grid.Data(al_Row, ll_ColIndex))
'            If (ls_Data = "0") Or (ls_Data = "NULL") And (as_Table <> "") Then
'                ls_Data = mo_Db.SQLNextID(as_Table)
'                If ls_Data = "" Then
'                    Err.Raise ArmErr.CompFncFailed, "mo_Db.SQLNextID", "SQLNextID failed for: " & as_Table
'                End If
'            End If
'        Else
        Select Case ao_grid.Columns(ll_ColIndex).FieldType
        Case DBTYPE_I4
            ls_Data = SqlInt(ao_grid.Data(al_Row, ll_ColIndex))
        Case DBTYPE_R4, DBTYPE_R8
            ls_Data = SqlDbl(ao_grid.Data(al_Row, ll_ColIndex))
        Case DBTYPE_DATE
            ls_Data = SqlDate(ao_grid.Data(al_Row, ll_ColIndex))
        Case DBTYPE_BMP
            Select Case UCase(ao_grid.Data(al_Row, ll_ColIndex))
            Case "CHECK"
                ls_Data = SQLStr("X")
            Case "UNCHECK"
                ls_Data = SQLStr("")
            End Select
        Case Else
            ls_Data = SQLStr(ao_grid.Data(al_Row, ll_ColIndex))
        End Select
        as_Request = ReplacePlaceHolder(as_Request, "$" & ao_grid.Columns(ll_ColIndex).Name & "$", ls_Data)
    Next
    ReplaceRequestByGridData = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceRequestByGridData")
End Function

Private Function ReplaceRequestByGridStoredData(ByVal ao_grid As ArmGrid, ByVal ao_Collection As Collection, ByVal as_Request As String, ByVal al_Row As Long, ByVal as_Table As String) As String
On Error GoTo ErrHandler

Dim ll_ColIndex As Long
Dim ls_Data As String
    
    For ll_ColIndex = 0 To ao_grid.Cols - 1
        Select Case ao_grid.Columns(ll_ColIndex).FieldType
        Case DBTYPE_I4
            ls_Data = SqlInt(ao_Collection(al_Row)(ll_ColIndex))
        Case DBTYPE_R4, DBTYPE_R8
            ls_Data = SqlDbl(ao_Collection(al_Row)(ll_ColIndex))
        Case DBTYPE_DATE
            ls_Data = SqlDate(ao_Collection(al_Row)(ll_ColIndex))
        Case DBTYPE_BMP
            Select Case UCase(ao_Collection(al_Row)(ll_ColIndex))
            Case "CHECK"
                ls_Data = SQLStr("X")
            Case "UNCHECK"
                ls_Data = SQLStr("")
            End Select
        Case Else
            ls_Data = SQLStr(ao_Collection(al_Row)(ll_ColIndex))
        End Select
        as_Request = ReplacePlaceHolder(as_Request, "$" & ao_grid.Columns(ll_ColIndex).Name & "$", ls_Data)
    Next
    ReplaceRequestByGridStoredData = as_Request
    Exit Function
ErrHandler:
    Call ErrorHandler("ReplaceRequestByGridStoredData")
End Function

Private Sub LoadFrameDataFromCursor(ByVal ao_DB As ArmDb, ByVal al_cursor As Long, ByVal ao_Frame As Frame)
On Error GoTo ErrHandler

Dim lo_Control As Control
Dim lsa_Columns() As String
Dim lv_ComboData As Variant
Dim ll_Index As Long


   mb_InternalInit = True
    For Each lo_Control In UserControl.Controls
    
        If HasContainer(lo_Control, ao_Frame) Then
            Select Case UCase(TypeName(lo_Control))
                Case "ARMCOMBOBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        If (StrComp(mo_Db.GetFields(al_cursor, lsa_Columns(0)), "", vbTextCompare) <> 0) And _
                            (StrComp(mo_Db.GetFields(al_cursor, lsa_Columns(0)), "0", vbTextCompare) <> 0) Then
                            If UBound(lsa_Columns) >= 1 Then
                                If Not lo_Control.SearchItem(mo_Db.GetFields(al_cursor, lsa_Columns(0))) Then
                                    ReDim lv_ComboData(UBound(lsa_Columns))
                                    For ll_Index = 0 To UBound(lsa_Columns)
                                        lv_ComboData(ll_Index) = mo_Db.GetFields(al_cursor, lsa_Columns(ll_Index))
                                    Next
                                    If lo_Control.AddItem(lv_ComboData, True) Is Nothing Then
                                        Err.Raise ArmErr.CompFncFailed, lo_Control.Name, "Function AddItem failed"
                                    End If
                                End If
                            Else
                                Call lo_Control.SearchItem(mo_Db.GetFields(al_cursor, lsa_Columns(0)))
                            End If
                        End If
                    End If
                Case "ARMPICKER"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        If (StrComp(mo_Db.GetFields(al_cursor, lsa_Columns(0)), "", vbTextCompare) <> 0) And _
                            (StrComp(mo_Db.GetFields(al_cursor, lsa_Columns(0)), "0", vbTextCompare) <> 0) Then
                            If UBound(lsa_Columns) >= 1 Then
                                lo_Control.ItemCode = mo_Db.GetFields(al_cursor, lsa_Columns(0))
                                lo_Control.ItemDescription = mo_Db.GetFields(al_cursor, lsa_Columns(1))
                            End If
                        End If
                    End If
                Case "CHECKBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        If UCase(mo_Db.GetFields(al_cursor, lsa_Columns(0))) = "X" Then
                            lo_Control.Value = vbChecked
                        Else
                            lo_Control.Value = vbUnchecked
                        End If
                    End If
                Case "TEXTBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        lo_Control.Text = mo_Db.GetFields(al_cursor, lsa_Columns(0))
                    End If
                Case "A_CALOCX"
                    If Trim(lo_Control.Tag) <> "" Then
                        If CDbl(mo_Db.GetFields(al_cursor, lo_Control.Tag)) = 0 Then
                            Call lo_Control.reinit_cal
                        Else
                            lo_Control.date_courte = Format(mo_Db.GetFields(al_cursor, lo_Control.Tag), "dd\/mm\/yyyy")
                        End If
                    End If
            End Select
        End If
    Next
    mb_InternalInit = False
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("LoadFrameDataFromCursor")
End Sub

Private Sub LoadFrameDataFromGrid(ByVal ao_grid As ArmGrid, ByVal ao_Frame As Frame)
On Error GoTo ErrHandler

Dim lo_Control As Control
Dim lsa_Columns() As String
Dim lv_ComboData As Variant
Dim ll_Index As Long
   
   mb_InternalInit = True
    If ao_grid.SelectedCount <> 1 Then
        Debug.Assert True
        mb_InternalInit = False
        Exit Sub
    End If
    
    For Each lo_Control In UserControl.Controls
    
        If HasContainer(lo_Control, ao_Frame) Then
            Select Case UCase(TypeName(lo_Control))
                Case "ARMCOMBOBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        If UBound(lsa_Columns) >= 1 Then
                            If Not lo_Control.SearchItem(ao_grid.CurrentLine(lsa_Columns(0))) Then
                                ReDim lv_ComboData(UBound(lsa_Columns))
                                For ll_Index = 0 To UBound(lsa_Columns)
                                    lv_ComboData(ll_Index) = ao_grid.CurrentLine(lsa_Columns(ll_Index))
                                Next
                                If lo_Control.AddItem(lv_ComboData, True) Is Nothing Then
                                    Err.Raise ArmErr.CompFncFailed, lo_Control.Name, "Function AddItem failed"
                                End If
                            End If
                        Else
                            Call lo_Control.SearchItem(ao_grid.CurrentLine(lsa_Columns(0)))
                        End If
                    End If
                Case "ARMPICKER"
                    If Trim(lo_Control.Tag) <> "" Then
                        lsa_Columns = Split(lo_Control.Tag, SEP)
                        If UBound(lsa_Columns) >= 1 Then
                            lo_Control.ItemCode = ao_grid.CurrentLine(lsa_Columns(0))
                            lo_Control.ItemDescription = ao_grid.CurrentLine(lsa_Columns(1))
                        End If
                    End If
                Case "CHECKBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        If (StrComp(ao_grid.CurrentLine(lo_Control.Tag), "X", vbTextCompare) = 0) Or _
                           (StrComp(ao_grid.CurrentLine(lo_Control.Tag), "CHECK", vbTextCompare) = 0) Then
                            lo_Control.Value = vbChecked
                        Else
                            lo_Control.Value = vbUnchecked
                        End If
                    End If
                Case "TEXTBOX"
                    If Trim(lo_Control.Tag) <> "" Then
                        lo_Control.Text = ao_grid.CurrentLine(lo_Control.Tag)
                    End If
                Case "A_CALOCX"
                    If Trim(lo_Control.Tag) <> "" Then
                        If CDbl(ao_grid.CurrentLine(lo_Control.Tag)) = 0 Then
                            Call lo_Control.reinit_cal
                        Else
                            lo_Control.date_courte = Format(ao_grid.CurrentLine(lo_Control.Tag), "dd\/mm\/yyyy")
                        End If
                    End If
            End Select
        End If
    Next
    mb_InternalInit = False
    Exit Sub
ErrHandler:
    mb_InternalInit = False
    Call ErrorHandler("LoadFrameDataFromGrid")
End Sub

Private Function SelectValue(ByVal as_Request As String) As Variant
On Error GoTo ErrHandler
Dim ll_cursor As Long

  ll_cursor = OpenSQLSafe(mo_Db, as_Request)
  If ll_cursor > 0 Then
    If mo_Db.RowCount(ll_cursor) = 1 Then
      SelectValue = mo_Db.GetFields(ll_cursor, 0)
    End If
    Call mo_Db.Close(ll_cursor)
  End If
  Exit Function
ErrHandler:
  Call mo_Db.Close(ll_cursor)
  Call ErrorHandler("SelectValue as_Request=" & as_Request)
End Function

Private Sub UpdateLocalComboboxes(ByVal as_Key As String, ByVal av_Value As Variant, ByVal ae_Mode As eMode)
On Error GoTo ErrHandler

Dim lo_Control As Object
Dim lsa_Fields() As String

    If as_Key = "" Then Exit Sub
    For Each lo_Control In UserControl.Controls
    
        If StrComp(TypeName(lo_Control), "ArmCombobox", vbTextCompare) = 0 Then
            If lo_Control.Tag <> "" Then
                lsa_Fields = Split(lo_Control.Tag, SEP)
                If StrComp(lsa_Fields(0), as_Key, vbTextCompare) = 0 Then
                    Call lo_Control.Clear
                End If
            End If
        End If
    Next
    Exit Sub
ErrHandler:
    Call ErrorHandler("UpdateLocalComboboxes")
End Sub

Private Function SearchGrid(ByRef ao_grid As ArmGrid, ByVal av_columns As Variant, ByVal av_Data As Variant, ByVal ab_Select As Boolean) As Boolean
On Error GoTo ErrHandler

Dim ll_RowIdx As Long, ll_ColIdx As Long
Dim lb_Found As Boolean

    lb_Found = False
    For ll_RowIdx = 0 To ao_grid.Rows - 1
        lb_Found = True
        For ll_ColIdx = 0 To UBound(av_columns)
            If StrComp(av_Data(ll_ColIdx), ao_grid.Data(ll_RowIdx, av_columns(ll_ColIdx)), vbTextCompare) <> 0 Then
                lb_Found = False
                Exit For
            End If
        Next
        If lb_Found Then Exit For
    Next
    If lb_Found And ab_Select Then
        ao_grid.Row = ll_RowIdx
    End If
    SearchGrid = lb_Found
    Exit Function
ErrHandler:
    Call ErrorHandler("SearchGrid")
End Function

Private Function GetColIndex(ByRef ao_grid As ArmGrid, ByVal as_ColumnName As String) As Long
On Error GoTo ErrHandler

Dim ll_ColIdx As Long

    For ll_ColIdx = 0 To ao_grid.Cols - 1
        If StrComp(as_ColumnName, ao_grid.Columns(ll_ColIdx).FieldName, vbTextCompare) = 0 Then
            GetColIndex = ll_ColIdx
            Exit Function
        End If
    Next
    GetColIndex = -1
    Exit Function
ErrHandler:
    Call ErrorHandler("GetColIndex")
End Function

Private Function GetTreeViewPath(ByVal ao_Tree As ArmTreeView, ByVal al_dataIndex As Long, ByVal as_Separator As String) As String
On Error GoTo ErrHandler

Dim as_Path As String
Dim lo_Node As MSComctlLib.Node
    
    as_Path = ""
    Set lo_Node = ao_Tree.SelectedItem
    While Not (lo_Node Is Nothing)
    
        If as_Path <> "" Then as_Path = as_Separator & as_Path
        as_Path = lo_Node.Tag.GetData(al_dataIndex) & as_Path
        Set lo_Node = lo_Node.Parent
    Wend
    GetTreeViewPath = as_Path
    Exit Function
ErrHandler:
    Call ErrorHandler("GetTreeViewPath")
End Function

Private Sub ClearFrame(ByRef ao_Controls As Object, ByVal ao_Frame As Frame)
On Error GoTo ErrHandler

Dim ll_Idx As Long, ll_Count As Long, lo_Control As Object

   mb_InternalInit = True
    ll_Count = ao_Controls.Count - 1
    For ll_Idx = 0 To ll_Count
        Set lo_Control = ao_Controls.Item(ll_Idx)
        
        If StrComp(lo_Control.Name, "chk_Repositioning", vbTextCompare) <> 0 Then
        
            If HasContainer(lo_Control, ao_Frame) Then
                Select Case UCase(TypeName(lo_Control))
                    Case "TEXTBOX"
                        lo_Control.Text = ""
                    Case "ARMCOMBOBOX"
                        Set lo_Control.SelectedItem = Nothing
                    Case "ARMPICKER"
                        Call lo_Control.Clear
                    Case "A_CALOCX"
                        lo_Control.reinit_cal
                    Case "CHECKBOX"
                        lo_Control.Value = vbUnchecked
                    Case "ARMCHECKVIEW"
                        Call lo_Control.Init
                        Call RemoveDroppedCheckItems(lo_Control)
                    Case "FRAME", "LABEL", "TOOLBARCONTROL", "PICTUREBOX", "COMMANDBUTTON", _
                         "TABSTRIP", "DRIVELISTBOX", "DIRLISTBOX", "FILELISTBOX", "LISTVIEW"
                        'do nothing
                    Case "ARMGRID"
                        lo_Control.ClearGrid
                        lo_Control.Requests = ""
                    Case "LISTBOX"
                        lo_Control.ListIndex = -1
                    Case "OPTIONBUTTON"
                        Dim lv_Values As Variant
                        lv_Values = Split(lo_Control.Tag, SEP)
                        If UBound(lv_Values) >= 1 Then
                            lo_Control.Value = lv_Values(1)
                        Else
                            lo_Control.Value = False
                        End If
                    Case "ARMTREEVIEW"
                        Call lo_Control.Clear
                    Case Else
                        Debug.Print "ClearFrame " & UCase(TypeName(lo_Control))
                End Select
            End If
        End If
    Next
    Set lo_Control = Nothing
    mb_InternalInit = False
    Exit Sub
ErrHandler:
    Set lo_Control = Nothing
    mb_InternalInit = False
    Call ErrorHandler("ClearFrame")
End Sub

Private Sub EnableFrame(ByRef aControls As Variant, ByRef aContainer As Object, ByVal ab_Enabled As Boolean)
On Error GoTo ErrHandler
    
    Dim lIdx As Long, lCount As Long
    Dim lControl As Control
    
    lCount = aControls.Count - 1
    
    For lIdx = 0 To lCount
        Set lControl = aControls.Item(lIdx)
        If HasContainer(lControl, aContainer) Then
            Select Case UCase(TypeName(lControl))
                Case "TOOLBARCONTROL"
                    'lControl.Visible = ab_Enabled
                
                Case "FRAME", "LABEL", "MSFLEXGRID"
                    ' Do nothing !
                
                Case "TEXTBOX"
                    lControl.Locked = Not ab_Enabled
                    lControl.BackColor = IIf(ab_Enabled, CL_COLOR_ENABLED, CL_COLOR_DISABLED)
                
                Case "ARMGRID", "TABSTRIP"
                
                Case "ARMCHECKVIEW"
                    If ab_Enabled Then
                        Call lControl.SetVisibleList("EDIT")
                    Else
                        Call lControl.SetVisibleList("VIEW")
                    End If
                    
                Case "DIRLISTBOX", "DRIVELISTBOX", "FILELISTBOX"
                    lControl.Enabled = ab_Enabled
                    lControl.BackColor = IIf(ab_Enabled, CL_COLOR_ENABLED, CL_COLOR_DISABLED)

                Case "LISTVIEW", "COMMANDBUTTON", "ARMCOMBOBOX", "ARMPICKER", "A_CALOCX", "OPTIONBUTTON", "ARMTREEVIEW", "LISTBOX", "PICTUREBOX", "CHECKBOX"
                    lControl.Enabled = ab_Enabled
                Case Else
                    lControl.Enabled = ab_Enabled
                    Debug.Print "EnableFrame " & UCase(TypeName(lControl))
            End Select
        End If
        Set lControl = Nothing
    Next
    Exit Sub
ErrHandler:
    If Not lControl Is Nothing Then Set lControl = Nothing
    Call ErrorHandler("EnableFrame")
End Sub

Private Sub DisableFrameParts(ByVal av_ListFieldsToDisable As Variant)
On Error GoTo ErrHandler
    
    Dim lIdx As Long, lCount As Long
    Dim lParams As Variant
    
    If Not IsArray(av_ListFieldsToDisable) Then Exit Sub
    lCount = UBound(av_ListFieldsToDisable)
    
    For lIdx = 0 To lCount
            Select Case UCase(TypeName(av_ListFieldsToDisable(lIdx)))
                Case "FRAME", "LABEL", "MSFLEXGRID", "TOOLBARCONTROL"
                    ' Do nothing !
                
                Case "TEXTBOX"
                        av_ListFieldsToDisable(lIdx).Locked = True
                        av_ListFieldsToDisable(lIdx).BackColor = CL_COLOR_DISABLED
                        
                Case "ARMGRID", "ARMCHECKVIEW"
                                    
                Case "OPTIONBUTTON", "COMMANDBUTTON", "ARMCOMBOBOX", "ARMPICKER", "A_CALOCX", "ARMTREEVIEW", "LISTBOX", "PICTUREBOX", "TABSTRIP", "CHECKBOX"
                    av_ListFieldsToDisable(lIdx).Enabled = False
                    
                Case Else
                    Debug.Print "DisableFrameParts " & UCase(TypeName(av_ListFieldsToDisable(lIdx)))
            End Select
    Next
    Exit Sub
ErrHandler:
    Call ErrorHandler("DisableFrameParts")
End Sub

Private Sub SetTreeDelayedMode(ByVal al_FrameIndex As Long, ByVal ab_Delayed As Boolean)
On Error GoTo ErrHandler
Dim ll_Index As Long
    
    ll_Index = FindMainConfigByFrameIndex(al_FrameIndex)
    tvw_Main(al_FrameIndex).Visible = Not ab_Delayed
    cmd_TVReLoad(al_FrameIndex).Visible = ab_Delayed
    mt_MainConfig(ll_Index).TreeDelayed = ab_Delayed
    grd_Main(al_FrameIndex).Visible = Not ab_Delayed
    Exit Sub
ErrHandler:
    Call ErrorHandler("SetTreeDelayedMode")
End Sub

Private Function GetModeFromRole(ByVal as_Role As String) As eMode
On Error GoTo ErrHandler

    GetModeFromRole = emView
    
    Select Case as_Role
    Case "A"
        GetModeFromRole = emAdd
    Case "B"
        GetModeFromRole = emUpdate
    Case "C"
        GetModeFromRole = emDelete
    End Select
    Exit Function
ErrHandler:
    Call ErrorHandler("GetModeFromRole")
End Function

Private Function LoadTreeView(ByVal al_MainIndex As Long, ByRef aTV As ArmTreeView, ByRef aTreeViewInfo As TTreeViewInfo) As Boolean
On Error GoTo ErrorHandler
    
    Call aTV.Clear
    
    If aTreeViewInfo.Levels > 0 Then
      aTV.Levels = aTreeViewInfo.Levels
      aTV.StartDemandLevel = 1
      aTV.SelectedImages = aTreeViewInfo.SelectedImages
      aTV.Images = aTreeViewInfo.Images
      aTV.NodeRequests = ApplyTVFilters(al_MainIndex, aTreeViewInfo.NodeRequest)
      aTV.FindRequests = ApplyTVFilters(al_MainIndex, aTreeViewInfo.FindRequest)
      aTV.GridRequests = aTreeViewInfo.GridRequest
      
      If Not aTV.LoadTree(LoadTypeChildsDemand) Then
          Call Err.Raise(ArmErr.CompFncFailed, "aTV.LoadTree", "")
      End If
    End If
    Exit Function
ErrorHandler:
    Call ErrorHandler("LoadTreeView")
End Function

Private Function GetTreeViewInfoFromDB(ByVal AScreenName As String, ByVal aTVCode As String) As TTreeViewInfo
On Error GoTo ErrHandler

    Dim lTreeView As TTreeViewInfo
    Dim lRequest As String
    Dim lCurs As Long, lIdx As Long, lCount As Long
    
    ' Get the data from the DB
    lRequest = "EXEC Treeview_Parameters_lst '" & AScreenName & "', '" & aTVCode & "'"
    lCurs = OpenSQLSafe(mo_Db, lRequest)
    
    lCount = mo_Db.RowCount(lCurs) - 1
    
    If lCount < 0 Then
        Call Err.Raise(ArmErr.InvalidValue, lRequest, "AScreenName=" & AScreenName & " lCount=" & lCount)
    End If
    
    ReDim lTreeView.NodeRequest(lCount)
    ReDim lTreeView.GridRequest(lCount)
    ReDim lTreeView.ExcelRequest(lCount)
    ReDim lTreeView.FindRequest(lCount)
    ReDim lTreeView.CountRequest(lCount)
    ReDim lTreeView.Images(lCount)
    ReDim lTreeView.SelectedImages(lCount)
    
    Dim lLevel As Long
    For lIdx = 0 To lCount
        lLevel = mo_Db.GetFields(lCurs, "TV_Level")
        lTreeView.NodeRequest(lLevel) = ReplaceCommonPlaceholders(mo_Db.GetFields(lCurs, "TV_NodeRequest"))
        lTreeView.GridRequest(lLevel) = mo_Db.GetFields(lCurs, "TV_GridRequest")
        lTreeView.FindRequest(lLevel) = ReplaceCommonPlaceholders(mo_Db.GetFields(lCurs, "TV_FindRequest"))
        lTreeView.Images(lLevel) = mo_Db.GetFields(lCurs, "TV_Images")
        lTreeView.SelectedImages(lLevel) = mo_Db.GetFields(lCurs, "TV_SelectedImages")
        mo_Db.Next (lCurs)
    Next
    
    lTreeView.TreeViewCode = aTVCode
    lTreeView.Levels = lCount + 1
    lTreeView.Loaded = True
    GetTreeViewInfoFromDB = lTreeView
    
    Call mo_Db.Close(lCurs)
    Exit Function
ErrHandler:
    Call mo_Db.Close(lCurs)
    Call ErrorHandler("GetTreeViewInfoFromDB")
End Function

' ************************************************************************************
' FRAMEWORK DB-ACCESS FUNCTIONS
' please do not change this code
' ************************************************************************************

' Return the result of a SQL request
' Convert SQL runtime errors and process errors to VB Error
#If LIVE = 1 Then
Private Function OpenSQLSafe(ByVal ao_DB As Object, ByVal as_Request As String, Optional ByVal al_RowExpectedCount = -1) As Long
#Else
Private Function OpenSQLSafe(ByVal ao_DB As ARMSYSCOMLib.ArmDb, ByVal as_Request As String, Optional ByVal al_RowExpectedCount = -1) As Long
#End If

On Error GoTo ErrHandler

    Dim lc_Data As Long
    lc_Data = ao_DB.OpenSQL(as_Request)
    
    If lc_Data = 0 Then
        Err.Raise ArmErr.SQLFailure, "SQL : " & as_Request, Join(ao_DB.SQLErrorCodes, SEP2) & SEP1 & Join(ao_DB.SQLErrorMessages, SEP2)
    End If
    
    If al_RowExpectedCount <> -1 Then
        ' Then check the rowcount
        If ao_DB.RowCount(lc_Data) <> al_RowExpectedCount Then
            Err.Raise ArmErr.SQLBadRowExpectedCount, "SQL : " & as_Request, al_RowExpectedCount & "<>" & ao_DB.RowCount(lc_Data)
        End If
    End If

    OpenSQLSafe = lc_Data

    Exit Function

ErrHandler:

    Call ErrorHandler("OpenSQLSafe")

End Function


' Execute a SQL request returning no data
' Convert SQL runtime errors and process errors to VB Error
' Params:
' ao_Db (Object)
' as_Request (String)
' al_RowAffectedCount (String)
#If LIVE = 1 Then
Private Sub ExecuteSQLSafe(ByVal ao_DB As Object, ByVal as_Request As String, Optional ByVal al_RowAffectedCount = -1, Optional ab_DuplicityCheck As Boolean = False)
#Else
Private Sub ExecuteSQLSafe(ByVal ao_DB As ARMSYSCOMLib.ArmDb, ByVal as_Request As String, Optional ByVal al_RowAffectedCount = -1, Optional ab_DuplicityCheck As Boolean = False)
#End If
On Error GoTo ErrHandler

    ' First execute the request
    If Not ao_DB.ExecuteSQL(as_Request) Then
        Err.Raise ArmErr.SQLFailure, "SQL : " & as_Request, Join(ao_DB.SQLErrorCodes, SEP2) & SEP1 & Join(ao_DB.SQLErrorMessages, SEP2)
    End If

    If al_RowAffectedCount <> -1 Then
        ' Then check the rowcount
        If ao_DB.SQLRowsAffected <> al_RowAffectedCount Then
            
            If ab_DuplicityCheck Then
                Err.Raise ArmCusErr.DuplicityDetected, "SQL : " & as_Request, al_RowAffectedCount & "<>" & ao_DB.SQLRowsAffected
            Else
                Err.Raise ArmErr.SQLBadRowAffectedCount, "SQL : " & as_Request, al_RowAffectedCount & "<>" & ao_DB.SQLRowsAffected
            End If
        End If
    End If

    Exit Sub

ErrHandler:
    Call ErrorHandler("ExecuteSQLSafe")
End Sub

Private Function GetDbError(ByVal lo_Db As ARMSYSCOMLib.ArmDb) As String
On Error GoTo ErrHandler
    
    If IsArray(lo_Db.SQLErrorMessages) Then
        Debug.Assert (IsArray(mo_Db.SQLErrorCodes))
        ' Display errors msgBox
        GetDbError = Join(lo_Db.SQLErrorCodes, ",") & vbCrLf & Join(lo_Db.SQLErrorMessages, vbCrLf)
    Else
        ' ExecuteSQL failed but no error message?
        GetDbError = "Unknown error"
    End If
    Exit Function
ErrHandler:
    Call ErrorHandler("GetDbError()")
End Function
' Standard error handler
Private Sub ErrorHandler(ByVal as_Fct As String)
  
    Call Err.Raise(Err.Number, as_Fct & SEP1 & Err.Source, Err.Description)
End Sub

' display standard error message
Private Sub ErrorMessage(ByVal as_Fct As String)
    Dim ls_ErrSource As String
    Dim ls_errDescription As String
    ls_ErrSource = as_Fct & SEP1 & Err.Source
    ls_errDescription = Err.Description
    
    Call LogMessage(SCREEN_NAME & " exception raised. Err.Number:" & Err.Number & ", Err.Source:" & ls_ErrSource & ", Err.Description " & ls_errDescription & ".", "E", False)
    Call MsgBox("Error occured, please contact IT. Application will now shutdown." & vbCrLf & ls_ErrSource & vbCrLf & "Description: " & ls_errDescription, , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
    End
End Sub

' logs message to database
Private Sub LogMessage(ByVal as_logMsg As String, Optional ByVal as_logType As String = "E", Optional ab_ExitOnException As Boolean = False)
    Dim ll_errNumber As Long
    Dim ls_errDescription As String, ls_ErrSource As String
    
    ll_errNumber = Err.Number
    ls_errDescription = Err.Description
    ls_ErrSource = Err.Source

On Error GoTo ErrHandler

Const LOG_REQUEST As String = "EXEC A_log_ins $UCODE$,$LOGTYPE$,$MSG$,$APP$"
    Dim ls_req As String
    Dim ll_cursor As Long
    Dim ls_Source As String, ls_Msg As String
    
    ls_Source = SCREEN_NAME & " " & App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    ls_Msg = as_logMsg & SEP1 & ll_errNumber & " : " & ls_errDescription & " - " & ls_ErrSource
    
    ls_req = ReplacePlaceHolder(LOG_REQUEST, "$UCODE$", CStr(ml_U_Code))
    ls_req = ReplacePlaceHolder(ls_req, "$LOGTYPE$", SQLStr(as_logType))
    ls_req = ReplacePlaceHolder(ls_req, "$MSG$", Left(Trim(SQLStr(ls_Msg)), 4000))
    ls_req = ReplacePlaceHolder(ls_req, "$APP$", Left(Trim(SQLStr(ls_Source)), 50))
    
    Call ExecuteSQLSafe(mo_Db, ls_req)
    
    Err.Number = ll_errNumber
    Err.Description = ls_errDescription
    Err.Source = ls_ErrSource
    Exit Sub
    
ErrHandler:
    If ab_ExitOnException Then
        Call MsgBox("A fatal error occured. Unable to log error into database, the application will be close. Please report the following message to your IT support: " & vbCrLf & _
            "Number:" & Err.Number & vbCrLf & "Description:" & Err.Description, , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
        End
    End If
    Err.Number = ll_errNumber
    Err.Description = ls_errDescription
    Err.Source = ls_ErrSource
End Sub


' procedure save/restore err object
Private Sub UpdateError(Optional ab_saveError As Boolean = False)
Static ls_ErrDesc As String
Static ls_ErrSource As String
Static ll_errnum As Long
    
    If ab_saveError Then
        ls_ErrDesc = Err.Description
        ls_ErrSource = Err.Source
        ll_errnum = Err.Number
    Else
        Err.Description = ls_ErrDesc
        Err.Source = ls_ErrSource
        Err.Number = ll_errnum
    End If
End Sub

Private Sub LockScreen(ByVal ab_lock As Boolean)

    Dim ll_errNumber As Long, ls_ErrSrc As String, ls_ErrDesc As String
    ll_errNumber = Err.Number
    ls_ErrSrc = Err.Source
    ls_ErrDesc = Err.Description

On Error GoTo ErrHandler
    Static ll_Count As Long
    Static ll_Mousepointer As Long
    Static lb_Locked As Boolean
      
      
    ll_Count = ll_Count + IIf(ab_lock, 1, -1)
    Debug.Assert (ll_Count >= 0)
    
    ' First lock
    If Not lb_Locked And ab_lock Then
        ll_Mousepointer = Screen.MousePointer
        Screen.MousePointer = vbHourglass
        LockWindowUpdate UserControl.hwnd
        lb_Locked = True
    End If
    
    ' Unlock
    If ll_Count = 0 Then
        DoEvents ' Flush events
        LockWindowUpdate 0
        UserControl.Refresh ' Repaint immediately
        Screen.MousePointer = ll_Mousepointer
        lb_Locked = False
    End If
    
    Err.Number = ll_errNumber
    Err.Source = ls_ErrSrc
    Err.Description = ls_ErrDesc
    Exit Sub
ErrHandler:
    Call ErrorHandler("LockScreen")
End Sub

Private Function BeginTran(as_Tran As String) As Boolean

On Error GoTo ErrHandler
    BeginTran = False
    ExecuteSQLSafe mo_Db, "BEGIN TRANSACTION " & as_Tran

    BeginTran = True
    Exit Function
    
ErrHandler:
    'try to log error
    Call LogMessage("BeginTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".BeginTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End
End Function

Private Function CommitTran(as_Tran As String) As Boolean

On Error GoTo ErrHandler
    CommitTran = False
    ExecuteSQLSafe mo_Db, "COMMIT TRANSACTION " & as_Tran

    CommitTran = True
    Exit Function
    
ErrHandler:
    'try to log error
    Call LogMessage("CommitTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".CommitTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End

End Function

Private Function RollbackTran(as_Tran As String) As Boolean
    
    Dim ll_errNumber As Long, ls_ErrSource As String, ls_ErrDesc As String
    ll_errNumber = Err.Number
    ls_ErrSource = Err.Source
    ls_ErrDesc = Err.Description

On Error GoTo ErrHandler
    RollbackTran = False
    
    ExecuteSQLSafe mo_Db, "ROLLBACK TRANSACTION " & as_Tran


    Err.Number = ll_errNumber
    Err.Source = ls_ErrSource
    Err.Description = ls_ErrDesc

    RollbackTran = True
    Exit Function
    
ErrHandler:
    'try to log error
    Call LogMessage("RollbackTran: " & as_Tran)
    Call mo_Db.Disconnect
    Set mo_Db = Nothing
    MsgBox "A Fatal error occured in " & SCREEN_NAME & ".RollbackTran, your application will be close. Please contact your IT support", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision
    End
End Function

' ************************************************************************************
' *************************** INTERNATIONAL FUNCTIONS ********************************
' ************************************************************************************

Private Function GetCodePageFromLanguage(ByRef ao_Armdb As Object, ByVal as_Language As String) As Long
On Error GoTo ErrHandler
Const C_REQ As String = "SELECT Code_Page FROM Language WHERE Language_Code = '$Language_Code$'"
    Dim ls_req As String
    Dim ll_cursor As Long
    Dim ll_codePage As Long
    
    ls_req = ReplacePlaceHolder(C_REQ, "$Language_Code$", as_Language)

    ll_cursor = OpenSQLSafe(ao_Armdb, ls_req)
    Debug.Assert (ll_cursor <> 0)
    
    ll_codePage = CLng(ao_Armdb.GetFields(ll_cursor, "Code_Page"))
    Call ao_Armdb.Close(ll_cursor)
    GetCodePageFromLanguage = ll_codePage
    Exit Function
    
ErrHandler:
    If ll_cursor <> 0 Then Call ao_Armdb.Close(ll_cursor)
    Call ErrorHandler("GetCodePageFromLanguage()")
End Function

'convert code page into charset integer
Private Function GetCharSetFromCodePage(ByVal al_CodePage As Long) As Long

On Error GoTo ErrHandler

    Select Case CStr(al_CodePage)
        Case 932 ' Japanese
            GetCharSetFromCodePage = 128
        Case 936 ' Simplified Chinese
            GetCharSetFromCodePage = 134
        Case 949 ' Korean
            GetCharSetFromCodePage = 129
        Case 950 ' Traditional Chinese
            GetCharSetFromCodePage = 136
        Case 1250 ' Eastern Europe
            GetCharSetFromCodePage = 238
        Case 1251 ' Russian
            GetCharSetFromCodePage = 204
        Case 1252 ' Western European Languages
            GetCharSetFromCodePage = 0
        Case 1253 ' Greek
            GetCharSetFromCodePage = 161
        Case 1254 ' Turkish
            GetCharSetFromCodePage = 162
        Case 1255 ' Hebrew
            GetCharSetFromCodePage = 177
        Case 1256 ' Arabic
            GetCharSetFromCodePage = 178
        Case 1257 ' Baltic
            GetCharSetFromCodePage = 186
        Case Else
            GetCharSetFromCodePage = 0
    End Select
    
    Exit Function
    
ErrHandler:
    Call ErrorHandler("GetCharSetFromCodePage()")
End Function

Private Sub ChangeCharset(ByRef ao_Container As Object, Optional ByVal aCodePage As Long)

On Error GoTo ErrHandler
   
    Dim lc_Control As Control
    Dim ll_Charset As Long
    
    On Error Resume Next
    ll_Charset = GetCharSetFromCodePage(aCodePage)
    
    For Each lc_Control In ao_Container
        Select Case UCase(TypeName(lc_Control))
        Case "TABSTRIP", "TEXTBOX", "LABEL", "FRAME", "COMMANDBUTTON", _
              "LISTVIEW", "CHECKBOX", "OPTIONBUTTON", _
              "ARMCHECKVIEW", "ARMTREEVIEW", "ARMGRID", "ARMCOMBOBOX", "ARMCHECKVIEW0", "ARMPICKER"
            lc_Control.Font.Name = "Arial"
            lc_Control.Font.Charset = ll_Charset
        Case "A_SEEK", "A_SRCHTXT"
            lc_Control.Charset = ll_Charset
        End Select
    Next
    
    Exit Sub
ErrHandler:
    Call ErrorHandler("ChangeCharset")
End Sub

' Load the labels of a containers
Private Sub LoadLabels(ByRef ao_Armdb As ArmDb, ByRef ao_Container As Object, ByVal as_ScreenName As String, ByVal as_Language As String)
Dim lo_Control As Control   ' A control of the container
Dim li_Idx As Integer, li_Count As Integer
Dim li_Label As Integer      ' A label idx
Dim ls_Request As String
Dim lc_Labels As Long
Dim lsa_ControlTag() As String
    
    On Error GoTo Trace_Err

    If mc_ScreenLabels = 0 Then
        ls_Request = "exec screen_csts '" & as_ScreenName & "','" & as_Language & "'"
        mc_ScreenLabels = OpenSQLSafe(ao_Armdb, ls_Request)
    End If
    lc_Labels = mc_ScreenLabels
    
    If lc_Labels = 0 Then
        Exit Sub
    End If
    
    On Error GoTo WithoutTag
    If ao_Container.Tag <> "" Then
        li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", ao_Container.Tag, , 1)
        If li_Label >= 0 Then
            ao_Container.Caption = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
        End If
    End If
WithoutTag:
    
    On Error GoTo Trace_Err
    
    ' Iterate the container for loading the label of each element which has defined a tag
    For Each lo_Control In UserControl.Controls
        If HasContainer(lo_Control, ao_Container) Then
            Select Case UCase(TypeName(lo_Control))
                Case UCase("TabStrip") ' Component is a tabstrip, we load the caption of each tab defined
                    Dim lo_Tbs
                    Set lo_Tbs = lo_Control ' Cast for use of intellisense
                    li_Count = lo_Tbs.Tabs.Count
                    For li_Idx = 1 To li_Count
                        If lo_Tbs.Tabs(li_Idx).Tag <> "" Then
                            li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lo_Tbs.Tabs(li_Idx).Tag, , 1)
                            If li_Label >= 0 Then
                                lo_Tbs.Tabs(li_Idx).Caption = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                            End If
                        End If
                    Next
                    Set lo_Tbs = Nothing
                
                Case UCase("ListView") ' Component is a listview, we load the caption of each columns
                    Dim lo_ListView As ListView
                    Set lo_ListView = lo_Control
                    li_Count = lo_ListView.ColumnHeaders.Count
                    For li_Idx = 1 To li_Count
                        If lo_ListView.ColumnHeaders(li_Idx).Tag <> "" Then
                            li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lo_ListView.ColumnHeaders(li_Idx).Tag, , 1)
                            If li_Label >= 0 Then
                                lo_ListView.ColumnHeaders(li_Idx).Text = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                            End If
                        End If
                    Next
                    Set lo_ListView = Nothing
            
                Case UCase("TextBox")  ' Component is a textbox
                    Dim lo_TextBox As TextBox
                    Set lo_TextBox = lo_Control
                    If lo_TextBox.Tag <> "" Then
                        lsa_ControlTag = Split(lo_Control.Tag, SEP)
                        li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lsa_ControlTag(0), , 1)
                        If li_Label >= 0 Then
                            lo_TextBox.Text = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                        End If
                    End If
                    Set lo_TextBox = Nothing
                
                Case UCase("Label"), UCase("Frame"), UCase("CommandButton"), UCase("CheckBox"), UCase("OptionButton")
                    If lo_Control.Tag <> "" Then
                        lsa_ControlTag = Split(lo_Control.Tag, SEP)
                        li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lsa_ControlTag(0), , 1)
                        If li_Label >= 0 Then
                            lo_Control.Caption = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                        End If
                    End If
                Case UCase("ArmGrid")
                    li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lo_Control.Tag, , 1)
                    If li_Label >= 0 Then
                      Call lo_Control.LoadConstants(ptStatic, ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT"), ctColumns)
                    End If
                    li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lo_Control.Tag & "_Title", , 1)
                    If li_Label >= 0 Then
                      lo_Control.Title = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                    End If
                Case UCase("Menu")
                    If lo_Control.Name <> "" Then
                        li_Label = ao_Armdb.Find(lc_Labels, "FIELD_NAME", lo_Control.Name, , 1)
                        If li_Label >= 0 Then
                            lo_Control.Caption = ao_Armdb.GetFields(lc_Labels, "LOCAL_TEXT")
                        End If
                    End If
            End Select
        End If
    Next
        
Trace_End:
    Exit Sub
    
Trace_Err:
      
End Sub

Function MsgText(ByVal aID As Long, ByVal aLang As String, ByVal aDefault As String, Optional ByVal aInfo As Variant) As String
On Error GoTo ErrHandler

Const DB_REQ As String = "SELECT message_text FROM error_message WHERE msgid = $id$ AND Language_code = '$lang$'"

    MsgText = ""
    
    Dim lRequest As String
    lRequest = ReplacePlaceHolder(DB_REQ, "$id$", aID)
    lRequest = ReplacePlaceHolder(lRequest, "$lang$", aLang)
    Dim lData As Long
    
    lData = OpenSQLSafe(mo_Db, lRequest)
    
    Dim lBuffer As String
    lBuffer = mo_Db.GetFields(lData, "message_text")
    mo_Db.Close (lData)
    If lBuffer = "" Then lBuffer = aDefault
    
    Dim li_Idx As Integer
    If Not IsMissing(aInfo) Then
        For li_Idx = 0 To UBound(aInfo)
            lBuffer = Replace(lBuffer, aInfo(li_Idx, 0), aInfo(li_Idx, 1), , , vbTextCompare)
        Next li_Idx
    End If
    
    
    MsgText = lBuffer
    Exit Function
ErrHandler:
    mo_Db.Close (lData)
    Call MsgBox("Connection failure accessing message information.", , App.Title & " " & App.Major & "." & App.Minor & "." & App.Revision)
    MsgText = aDefault
End Function

Private Function LoadIconFromA_Icons(ai_IconIndex As Integer) As Picture
Dim hIcon As Long
Dim hInst As Long
Dim oNewPic As Picture
Dim tPicConv As PictDesc
Dim IGuid As Guid

On Error GoTo ErrHandler
  
    hInst = LoadLibrary("c:\arm_apps\dll\A_icons.dll")
    If hInst = 0 Then
      Set LoadIconFromA_Icons = Nothing
      Exit Function
    End If
    
    hIcon = LoadIconFromDLL(hInst, ai_IconIndex)
    If hIcon = 0 Then
      Set LoadIconFromA_Icons = Nothing
      Exit Function
    End If
      
    With tPicConv
      .cbSizeofStruct = Len(tPicConv)
      .picType = vbPicTypeIcon
      .hImage = hIcon
    End With
     
    ' Fill in magic IPicture GUID {7BF80980-BF32-101A-8BBB-00AA00300CAB}
    With IGuid
          .Data1 = &H7BF80980
          .Data2 = &HBF32
          .Data3 = &H101A
          .Data4(0) = &H8B
          .Data4(1) = &HBB
          .Data4(2) = &H0
          .Data4(3) = &HAA
          .Data4(4) = &H0
          .Data4(5) = &H30
          .Data4(6) = &HC
          .Data4(7) = &HAB
    End With
    OleCreatePictureIndirect tPicConv, IGuid, True, oNewPic
      
    Set LoadIconFromA_Icons = oNewPic
    Call FreeLibrary(hInst)
    Exit Function
ErrHandler:
    Call FreeLibrary(hInst)
    Call ErrorHandler("LoadIconFromFile")
End Function

' ************************************************************************************

' ************************************************************************************
' **************************** REDIM FUNCTION ****************************************
' ************************************************************************************
Sub SafeRedimString(ByRef as_Array() As String, al_NumElements As Long)

On Error GoTo ErrHandler

  If al_NumElements = 0 Then
          ReDim as_Array(-1 To -1)
  Else
          'MS REDIMM
          Call SafeRedimPreserve(as_Array, al_NumElements - 1)
  End If
  Exit Sub
ErrHandler:
    Call ErrorHandler(Extender.Name & ".SafeRedimString()")
End Sub

Private Function GetTempDir() As String
Dim ls_Buff As String, ll_Count As Long

On Error GoTo ErrHandler
    ls_Buff = Space(4096)
    ll_Count = GetTempPath(4096, ls_Buff)
    
    ls_Buff = Left(ls_Buff, ll_Count)
    'this function can return path with trailing "\" character - strip it
    If ll_Count > 0 Then
      If right(ls_Buff, 1) = "\" Then
       ls_Buff = Left(ls_Buff, ll_Count - 1)
      End If
    End If
    GetTempDir = ls_Buff
  Exit Function
ErrHandler:
  Call ErrorHandler("GetTempDir")
End Function

Private Function LoadUserInfo(ByRef ao_Armdb As Object, ByVal al_U_Code As Long) As String
On Error GoTo ErrHandler
Const C_REQ As String = _
    "SELECT GPL.P_Name + ' '+ GPL.P_First_Name as User_Name " & _
    "FROM GEN_Systems_Users GSU " & _
    "INNER JOIN GEN_People GPL ON (GSU.P_Code=GPL.P_Code) " & _
    "WHERE GSU.U_Code=$U_Code$"

Dim ls_req As String
Dim ll_cursor As Long
    
    ls_req = ReplacePlaceHolder(C_REQ, "$U_Code$", al_U_Code)
    ll_cursor = OpenSQLSafe(ao_Armdb, ls_req, 1)
    LoadUserInfo = ao_Armdb.GetFields(ll_cursor, "User_Name")
    Call ao_Armdb.Close(ll_cursor)
    Exit Function
    
ErrHandler:
    If ll_cursor <> 0 Then Call ao_Armdb.Close(ll_cursor)
    Call ErrorHandler("LoadUserInfo()")
End Function


Private Function InitUserRights(ByVal as_LoginName As String) As Boolean
On Error GoTo ErrHandler
    Const C_REQ As String = "SELECT Alias FROM Security_Alias WHERE Alias='SPA_ADMIN' AND Login_Name='$LOGIN_NAME$'"
    Dim ls_req As String
    Dim ll_cursor As Long
    InitUserRights = False
    
    ls_req = ReplacePlaceHolder(C_REQ, "$LOGIN_NAME$", as_LoginName)
    ll_cursor = OpenSQLSafe(mo_Db, ls_req)
    If mo_Db.RowCount(ll_cursor) > 0 Then
        InitUserRights = True
    End If
    Call mo_Db.Close(ll_cursor)
    
    Exit Function
ErrHandler:
    If ll_cursor > 0 Then
        Call mo_Db.Close(ll_cursor)
        ll_cursor = 0
    End If
    
    Call ErrorHandler("InitUserRights()")
End Function

Private Sub UserControl_Terminate()
    'Call ScanControls(Me)                   ' JN: parameter 'Me' when teminating the control produce error in debug
    'Call ScanControls(mo_SPA_Admin_MKT)
    
    'Call ScanControls(mo_SPA_Admin_PG)
    'Call ScanControls(mo_SPA_Admin_PG_MKT)
    'Call ScanControls(mo_SPA_Admin_PG_MKT_BI)
    
End Sub



Private Function ScanControls(ByRef ao_uc As Object) As Boolean
On Error GoTo ErrHandler
    Dim lc_Control As Control
    Dim li_Counter As Integer
    Dim ls_StringBuilder As String
    Dim ll_Index As Long
    
    For Each lc_Control In ao_uc.Controls
        'label
        If TypeOf lc_Control Is Label Then
            ll_Index = -1
            On Error Resume Next
            ll_Index = lc_Control.Index
            If ll_Index = -1 Then
                Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & lc_Control.Caption)
            Else
                Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & lc_Control.Caption)
            End If
        End If
        'check box
        If TypeOf lc_Control Is CheckBox Then
            Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & lc_Control.Caption)
        End If
        'tabstrip
        If TypeOf lc_Control Is TabStrip Then
            For li_Counter = 1 To lc_Control.Tabs.Count
                Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & lc_Control.Tabs.Item(li_Counter))
            Next
        End If
        'option button
        If TypeOf lc_Control Is OptionButton Then
            Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & lc_Control.Caption)
        End If
        'grid
        If TypeOf lc_Control Is ArmGrid Then
            Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & "_Title;E;E;;" & lc_Control.Title)
            If Not lc_Control.Cols = 0 Then
                ls_StringBuilder = ""
                For li_Counter = 0 To lc_Control.Cols - 1
                    If li_Counter = lc_Control.Cols - 1 Then
                        ls_StringBuilder = ls_StringBuilder & lc_Control.Columns(li_Counter).Title
                    Else
                        ls_StringBuilder = ls_StringBuilder & lc_Control.Columns(li_Counter).Title & SEP
                    End If
                Next
                Debug.Print (ao_uc.Name & ";" & lc_Control.Tag & ";E;E;;" & ls_StringBuilder)
            End If
        End If
    Next
    ScanControls = True
    
    Exit Function
ErrHandler:
    ScanControls = False
    Call ErrorHandler("ScanControls")
End Function


Public Property Get Controls() As Object
    Set Controls = UserControl.Controls
End Property

' 0 meas everything ok
Private Function Item_CanUpdateCustom(ByVal as_configName As String) As ArmCusErr
On Error GoTo ErrHandler
    Item_CanUpdateCustom = NoError
    Dim ll_MainConfig As Long, ll_frameIndex As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    ll_frameIndex = mt_MainConfig(ll_MainConfig).FrameIndex
    
    If grd_Main(ll_frameIndex).SelectedCount = 0 Then
        Item_CanUpdateCustom = WarMsgSelectRow
        Exit Function
    End If
    
    Select Case as_configName
    Case "SPA_PG_MKT"
    
'        If grd_Main(ll_frameIndex).CurrentLine("VDate_End") <> 0 And grd_Main(ll_frameIndex).CurrentLine("VDate_End") < Date Then
        If grd_Main(ll_frameIndex).CurrentLine("VDate_End") <> 0 Then
            Item_CanUpdateCustom = ErrMsg_M610                          ' item cannot be updated because it is closed
            Exit Function
        End If
        
'        If grd_Main(ll_frameIndex).CurrentLine("isActive") <> "X" Then
'            Item_CanUpdateCustom = ErrMsg_M610                          ' item cannot be updated because it is not active
'        End If

    End Select
    
    Exit Function
ErrHandler:
    Call ErrorHandler(Extender.Name & ".Item_CanUpdateCustom")
End Function

' 0 meas everything ok
Private Function Item_CanDeleteCustom(ByVal as_configName As String) As ArmCusErr
On Error GoTo ErrHandler
    Item_CanDeleteCustom = NoError
    Dim ll_MainConfig As Long, ll_frameIndex As Long
    ll_MainConfig = FindMainConfigByName(as_configName)
    ll_frameIndex = mt_MainConfig(ll_MainConfig).FrameIndex
    
    If grd_Main(ll_frameIndex).SelectedCount = 0 Then
        Item_CanDeleteCustom = WarMsgSelectRow
        Exit Function
    End If
    
    Select Case as_configName
   Case "SPA_MKT_USER"
    
        If grd_Main(ll_frameIndex).CurrentLine("SPR_Code") = 0 And grd_Main(ll_frameIndex).CurrentLine("MarketCount") = 0 Then
            Item_CanDeleteCustom = ErrMsg_M700                       ' item cannot be deleted because does not exist in spa
            Exit Function
        End If
        
    Case "SPA_PG_MKT"
    
        If grd_Main(ll_frameIndex).CurrentLine("VDate_End") <> 0 And grd_Main(ll_frameIndex).CurrentLine("VDate_End") < Date Then
'        If grd_Main(ll_frameIndex).CurrentLine("VDate_End") <> 0 Then
            Item_CanDeleteCustom = ErrMsg_M610                          ' item cannot be updated because it is closed
            Exit Function
        End If
        
'        If grd_Main(ll_frameIndex).CurrentLine("isActive") <> "X" Then
'            Item_CanDeleteCustom = ErrMsg_M610                          ' item cannot be deleted because it is not active
'        End If

    End Select
    
    Exit Function
ErrHandler:
    Call ErrorHandler(Extender.Name & ".Item_CanDeleteCustom")
End Function


