Imports System.ComponentModel
Imports System.Globalization
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Imports DevExpress.LookAndFeel
Imports DevExpress.Utils
Imports DevExpress.XtraBars.Ribbon
Imports DevExpress.XtraEditors
Imports DevExpress.XtraExport.Helpers
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Columns
Imports DevExpress.XtraGrid.Views.BandedGrid
Imports DevExpress.XtraGrid.Views.Base
Imports DevExpress.XtraGrid.Views.Grid
Imports DevExpress.XtraGrid.Views.Grid.ViewInfo
Imports DevExpress.XtraNavBar
Imports DevExpress.XtraPrinting
Imports DevExpress.XtraSplashScreen
Imports DevExpress.XtraTreeList
Imports DigitalData.GUIs.Common
Imports DigitalData.Modules.Base
Imports DigitalData.Modules.EDMI.API.Constants
Imports DigitalData.Modules.EDMI.API.DatabaseWithFallback
Imports DigitalData.Modules.Windream
Imports DigitalData.Modules.ZooFlow
Imports GdPicture.Internal.CAD.DWG.Entities
Imports System.Runtime.InteropServices

Public Class frmMain
    Private Property FormHelper As FormHelper

    Private UserLoggedin As Integer = 0
    Private CURR_DT_VWPM_PROFILE_ACTIVE As DataTable
    Private CURR_DT_VWPM_PROFILE_AH_WORKFLOW As DataTable
    Private DT_CURR_WF_ITEMS As DataTable
    Private _treeNodeCounts As New Dictionary(Of Integer, Integer)

    Private OVERVIEW_ADDED_WHEN As String
    Private OVERVIEW_CHANGED_WHEN As String
    Private OVERVIEW_COUNT As Integer = 0
    Private RedDocuments As Integer = 0
    Private YellowDocuments As Integer = 0
    Private GreenDocuments As Integer = 0
    Private GridViewItem_Clicked = Nothing
    Private GridCursorLocation As System.Drawing.Point
    Private GRID_LOAD_TYPE As String = "OVERVIEW"
    Private GRID_INV_COL_REMOVED As Boolean = False
    Private NO_WORKFLOW_ITEMS As Boolean = False
    Private InResetlayout As Boolean = False
    Private RefreshHelper As RefreshHelper
    Private _FormValidator As frmValidator
    Private FormOpenClose As Boolean = False
    Private FormShown As Boolean = False
    Private GridIsLoaded As Boolean = False
    Private OverviewOrDEtail As String = "OVERVIEW"
    Private GridBuilder As GridBuilder

    Private allgFunk As New ClassAllgemeineFunktionen
    Private _Init As New ClassInit
    'Private CurrNavBarGroup As NavBarGroup
    'Private DataASorDB As ClassDataASorDB

    Private DT_CHECKUSER_MODULE As DataTable
    Private NOTIFICATIONS_DT As DataTable
    Private IsFilterMode As Boolean
    Private DetailLinkActive As Boolean = False
    Private FRONTEND_ACTION As String = "NONE"
    Private Ev_Filter_Panel_Closed As Boolean = False
    Private _overlayActive As Boolean = False

    Dim omsgOpenWorkflow As String
    Dim omsgTitleWarning As String
    Dim omsgTitleAttention As String

    Private Const FullFilepatColName = "FULL_FILE_PATH"
    Private Const FA_NONE = "NONE"
    Public Const NAVBAR_CLICKED = "NAVBAR LINK CLICKED"

    Private CUSTOM_OVERVIEW_SQL As String = String.Empty
    Private _lastUsedOverviewSQL As String = String.Empty  ' ← NEU: persistente Kopie
    Private COCKPIT_PROFILE_SQL As String = String.Empty
    Private COCKPIT_CONFIG_ID As Integer = 0



    Private Class S
        Inherits My.Resources.frmMain_Strings
    End Class


    Private Function GET_LAST_ADDED(pDatatable As DataTable) As String
        Dim oADDED As String
        Try
            If IsNothing(pDatatable) Then
                oADDED = "NOTHING"
            ElseIf LAST_ADDED_COLUMN = FA_NONE Then
                oADDED = Now.ToShortTimeString.ToString
            Else
                Dim result As Object
                result = pDatatable.Compute($"MAX({LAST_ADDED_COLUMN})", "")
                oADDED = result
            End If

        Catch ex As Exception
            oADDED = "Exception"
        End Try
        Return oADDED
    End Function
    Private Function GET_LAST_CHANGED(pDatatable As DataTable) As String
        Dim oCHANGED As String
        Try
            If IsNothing(pDatatable) Then
                oCHANGED = "NOTHING"
            ElseIf LAST_EDITED_COLUMN = FA_NONE Then
                oCHANGED = Now.ToShortTimeString.ToString
            Else
                Dim result As Object
                result = pDatatable.Compute($"MAX({LAST_EDITED_COLUMN})", "")
                oCHANGED = result
            End If

        Catch ex As Exception
            oCHANGED = "Exception"
        End Try
        Return oCHANGED
    End Function
    Public Sub SaveInheritanceConfirmationsToDatabase()
        Try
            LOGGER.Debug("Saving inheritance confirmations to database for user {0}", USER_ID.ToString)

            Dim entries = UserInheritance_ConfirmationByColumn
            If entries Is Nothing OrElse entries.Count = 0 Then
                LOGGER.Debug("No confirmation entries to save")
                Return
            End If

            For Each entry As UserInheritanceConfirmation In entries
                Dim keyName As String = $"INHERITANCE_CONFIRM_{entry.ColumnName.ToUpperInvariant()}"
                Dim valueText As String = entry.Count.ToString()

                SaveOrUpdateKeyValuePair(keyName, valueText)
            Next

            LOGGER.Debug("Successfully saved {0} confirmation entries", entries.Count)

        Catch ex As Exception
            LOGGER.Error("Error saving inheritance confirmations to database")
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Sub SaveOrUpdateKeyValuePair(keyName As String, valueText As String)
        Try
            ' Prüfen ob der Eintrag bereits existiert
            Dim oSQL As String = String.Format("DECLARE @Out_PK_ID bigint
                EXECUTE [dbo].[PRDD_TBDD_USER_KEY_VALUE_PAIR_Upsert] 
                        {0}
                        ,'{1}'
                        ,'{2}'
                        ,{3}
                        ,@Out_PK_ID OUTPUT;", USER_ID, keyName, valueText, USER_MODULE_ID)

            If DatabaseFallback.ExecuteNonQueryECM(oSQL) Then
                LOGGER.Debug("Saved/Updated key-value pair: {0} = {1}", keyName, valueText)
            End If

        Catch ex As Exception
            LOGGER.Error("Error saving key-value pair for key {0}", keyName)
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Sub frmMain_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
        Try
            FormOpenClose = True
            ' Position und Größe speichern
            My.Settings.frmMainSize = Me.Size
            My.Settings.frmMainPosition = Me.Location
            My.Settings.Save()
            CONFIG.Config.MainTreeList_Width = TreeList_Cockpit.Width
            CONFIG.Save()
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Error in Save FormLayout: " & ex.Message)
        End Try
        SaveInheritanceConfirmationsToDatabase()

        If IDB_ACTIVE = False Then
            Try
                If WINDREAM?.oSession?.aLoggedin = True Then
                    WINDREAM.Stop_WMCC_andCo()
                End If
            Catch ex As Exception

            End Try

        End If


        If INACTIVITYRecognized Then
            Exit Sub
        End If
        Try
            ClassAllgemeineFunktionen.LoginOut("LOGOUT")
            LOGGER.Info("taskFLOW closed - " & Now, False)
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Sub frmMain_KeyUp(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
        Select Case e.KeyCode
            Case Keys.F12
                frmLicense.ShowDialog()
        End Select
    End Sub

    Private Sub frmMain_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        FormOpenClose = True
        LOGGER.Debug("Initializing MainForm....")

        GridBuilder = New GridBuilder(GridViewWorkflows)
        GridBuilder.WithFontSizeDelta(CONFIG.Config.GridFontSizeDelta)

        Dim oFontSettings = New List(Of FontSetting) From {
            New FontSetting With {.Title = S.Kleiner, .Value = -2},
            New FontSetting With {.Title = S.Normal, .Value = 0},
            New FontSetting With {.Title = S.Größer, .Value = 2}
        }

        cmbGridFontSize.Items.Clear()
        cmbGridFontSize.Items.AddRange(oFontSettings)
        barItemGridFontSize.EditValue = oFontSettings.
                Where(Function(item) item.Value = CONFIG.Config.GridFontSizeDelta).
                FirstOrDefault()

        ' Create helper to save/load expanded GroupColumns at runtime
        RefreshHelper = New RefreshHelper(LOGCONFIG, GridViewWorkflows, "GUID")

        omsgOpenWorkflow = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("WorkflowIsActive1")
        omsgTitleWarning = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("MsgboxTitleWarning")
        omsgTitleAttention = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("MsgboxTitleAttention")


        Dim oVErsion = My.Application.Info.Version.ToString 'String.Format("{0}.{1}.{2}", My.Application.Info.Version.Major, My.Application.Info.Version.Minor, My.Application.Info.Version.Build)
        BSIVERSION1.Caption = oVErsion
        If ERROR_STATE = "NO DB-CONNECTION" Or ERROR_STATE = "FAILED DBCONNECTION" Then
            MsgBox(S.Bitte_konfigurieren_Sie_eine_Datenbankverbindung_, MsgBoxStyle.Critical, "Fehlende Konfiguration:")
            frmKonfig.ShowDialog()
        End If
        Try
            If CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName = "eng" Then
                LOGGER.Info("## CurrentUICulture.Name: " & CultureInfo.CurrentUICulture.Name, False)
                INDEX_DMS_ERSTELLT = "DMS Created"
                INDEX_DMS_ERSTELLT_ZEIT = "DMS Created Time"
                My.Settings.Save()
            End If
            Try
                Dim oCultureInfo As System.Globalization.CultureInfo
                oCultureInfo = New System.Globalization.CultureInfo(USER_LANGUAGE)
                oCultureInfo.DateTimeFormat.ShortDatePattern = USER_DATE_FORMAT
                Thread.CurrentThread.CurrentCulture = oCultureInfo
                Thread.CurrentThread.CurrentUICulture = oCultureInfo
                CultureInfo.DefaultThreadCurrentCulture = oCultureInfo
                CultureInfo.DefaultThreadCurrentUICulture = oCultureInfo

            Catch ex As Exception

            End Try
        Catch ex As Exception
            LOGGER.Error(ex)
            MessageBox.Show("Error loading CurrentUICulture-Info!", "Attention:", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
        End Try

        Try
            'DataASorDB = New ClassDataASorDB
            If User.IsAdmin = True Then
                'Dim oCaption As String = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("NumberLicenses")
                'bsiLicenses.Caption = $"{oCaption} {LICENSE_COUNT}"
                Dim oCaption As String = String.Format(S.Anzahl_Lizenzen___0_, LICENSE_COUNT)
                bsiLicenses.Caption = oCaption

                bsiLicenses.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
            Else
                bsiLicenses.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
            End If

            LOGGER.Debug("Initializing MainForm....")

            If ERROR_STATE = "NO USER" Then
                Dim oDT As DataTable = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("No Userconfig")
                MsgBox(oDT.Rows(0).Item("STRING1") & vbNewLine & oDT.Rows(0).Item("STRING2"), MsgBoxStyle.Critical, "Exception")
                Me.Close()
            ElseIf USER_IN_MODULE = False Then
                If USER_IS_ADMIN = False Then
                    Dim oDT As DataTable = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("No Module Configuration")
                    MsgBox(oDT.Rows(0).Item("STRING1") & vbNewLine & oDT.Rows(0).Item("STRING2"), MsgBoxStyle.Critical, "Exception")
                    Me.Close()
                End If
            ElseIf SYS_LOCKED_MAINTENANCE = True Then
                Dim msg = $"Wegen Wartungsarbeiten ist der Zugriff auf den Workflow aktuell gesperrt!" & vbNewLine & "Vielen Dank für Ihre Geduld!"
                If USER_LANGUAGE <> "de-DE" Then
                    msg = $"Due to maintenance work, access to the workflow is currently blocked!" & vbNewLine & "Thank You for Your patience!"
                End If
                MsgBox(msg, MsgBoxStyle.Exclamation, ADDITIONAL_TITLE)
                Me.Close()
            Else
                LOGGER.Info("Username: " & USER_USERNAME, False)
                'Wenn license abgelaufen und der User nicht admin ist!
                If LICENSE_EXPIRED = True Then
                    If USER_IS_ADMIN = False Then
                        MsgBox("License expired or invalid!" & vbNewLine & "Please contact the AdminTeam!", MsgBoxStyle.Critical, "Attention:")
                        Me.Close()
                    End If
                End If
                If USER_IS_ADMIN = True Then
                    RibbonPageGroup3.Visible = True
                    'Anzahl der eingeloggten User

                    bsiUserLoggedIn.Visibility = DevExpress.XtraBars.BarItemVisibility.Always

                    'Dim oCaption As String = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("NumberUserLoggedIn")
                    'bsiUserLoggedIn.Caption = $"{oCaption} {USERCOUNT_LOGGED_IN}"

                    Dim oCaption As String = String.Format(S.Anzahl_angemeldete_Benutzer___0_, USERCOUNT_LOGGED_IN)
                    bsiUserLoggedIn.Caption = oCaption

                    If GHOSTMODE_ACTIVE = True Then
                        bbtnitmGhostMode.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                    Else
                        bbtnitmGhostMode.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
                    End If

                Else
                    RibbonPageGroup3.Visible = False
                    bsiUserLoggedIn.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
                    bbtnitmGhostMode.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
                End If
                Try
                    If SEARCH1 <> String.Empty Then
                        Dim oindex = SEARCH1.IndexOf("~")

                        Dim oCaption = SEARCH1.Substring(0, oindex)

                        Dim oCommand = SEARCH1.Replace(oCaption + "~", "")
                        SearchItem1.Caption = oCaption
                        SearchItem1.Tag = oCommand
                        SearchItem1.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                        RibbonPageGroup4.Visible = True
                    End If
                Catch ex As Exception

                End Try
                Try
                    If SEARCH2 <> String.Empty Then
                        Dim oindex = SEARCH2.IndexOf("~")

                        Dim oCaption = SEARCH2.Substring(0, oindex)

                        Dim oCommand = SEARCH2.Replace(oCaption + "~", "")
                        SearchItem2.Caption = oCaption
                        SearchItem2.Tag = oCommand
                        SearchItem2.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                        RibbonPageGroup4.Visible = True
                    End If
                Catch ex As Exception

                End Try
                If START_CW = True Then
                    Dim oPath
                    Select Case START_CW_LOC_VARIANT
                        Case "-1"
                            oPath = Directory.GetParent(Application.StartupPath).ToString
                        Case "0"
                            oPath = Application.StartupPath.ToString
                    End Select

                    oPath &= "\easyFLOW\easyFLOW.exe"
                    If File.Exists(oPath) Then
                        bbtniCW.Caption = START_CW_CAPTION
                        bbtniCW.Tag = oPath
                        bbtniCW.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                        RibbonPageGroup4.Visible = True
                    Else
                        LOGGER.Warn($"Error in CW-Button init: Could not find CW.Exe {oPath}")
                    End If


                End If

            End If
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox(ex.Message, MsgBoxStyle.Exclamation, "Error in User Check:")
        End Try
        bsiUser.Caption = USER_USERNAME
        GetBaseData("Load")


        Try
            If TimerRefresh.Enabled = False Then
                TimerRefresh.Start()
            End If
            Timer5Mins.Start()
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox("Unexpected Error in LoadForm - Step 4: " & vbNewLine & ex.Message, MsgBoxStyle.Critical, "Attention:")
        End Try
        Load_Treeview()

        ' LoadNavBar()
        ' AddHandler NavBarControl1.LinkClicked, AddressOf navBar_LinkClicked
        If Not IsNothing(CURR_DT_VWPM_PROFILE_AH_WORKFLOW) Then
            If CURR_DT_VWPM_PROFILE_AH_WORKFLOW.Rows.Count > 0 And LIC_MODULES.Contains("MOD_AdhocWorkflow_BlindFile") Then
                RibbonPageGroupAHW.Visible = True
                Dim OCounter As Integer = 1
                For Each oRow As DataRow In CURR_DT_VWPM_PROFILE_AH_WORKFLOW.Rows
                    Select Case OCounter
                        Case 1
                            BbtnitmAHWF1.Caption = oRow.Item("TITLE")
                            BbtnitmAHWF1.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                            BbtnitmAHWF1.Tag = oRow.Item("GUID")

                        Case 2
                            BbtnitmAHWF2.Caption = oRow.Item("TITLE")
                            BbtnitmAHWF2.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                            BbtnitmAHWF2.Tag = oRow.Item("GUID")
                        Case 3
                            BbtnitmAHWF3.Caption = oRow.Item("TITLE")
                            BbtnitmAHWF3.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                            BbtnitmAHWF3.Tag = oRow.Item("GUID")
                        Case 4
                    End Select
                    OCounter += 1
                Next
            Else
                LOGGER.Info($"NO ADHOC-WFs Blindfiles ({CURR_DT_VWPM_PROFILE_AH_WORKFLOW.Rows.Count}) or License AHWF_NoBlindFile not integrated...")
            End If
        Else
            LOGGER.Debug("NO ADHOC-WFs Blindfiles (Nothing)...")
        End If
        Check_Timer_Notification()
        Timer_Inactivity_Reset_Disable("FormLoad")

        'Restore_Form_Position()
        Dim oSavedPosition As System.Drawing.Point = My.Settings.frmMainPosition

        ' Prüfen, ob die Position sichtbar ist
        If IsPositionVisible(oSavedPosition) Then
            ' Position ist sichtbar, das Formular wird dort angezeigt
            ScreenEx.RestoreFormPosition(Me, My.Settings.frmMainPosition)
            ScreenEx.RestoreFormState(Me, My.Settings.frmMainWindowState)
            ScreenEx.RestoreFormSize(Me, My.Settings.frmMainSize)
        Else
            ' Position ist unsichtbar, Standardposition verwenden
            Me.StartPosition = FormStartPosition.CenterScreen

        End If



        If IDB_ACTIVE = False And ERROR_STATE = "" Then
            Try
                If Init_windream() = True Then
                    WINDREAM.Start_WMCC_andCo()
                    BarButtonItemFileLink.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                    If Not IsNothing(WINDREAM.oSession) Then
                        If WINDREAM.oSession.aLoggedin = False Then
                            LOGGER.Warn("⚠️ You could not be logged in to windream")
                            MsgBox(S.Es_ist_keine_Windream_Session_vorhanden__Bitte_überprüfen_Sie_das_Log_, MsgBoxStyle.Critical)
                        End If
                    Else
                        LOGGER.Warn("⚠️ Login on windream was not possible.")
                        MsgBox(S.Es_ist_keine_Windream_Session_vorhanden__Bitte_überprüfen_Sie_das_Log_, MsgBoxStyle.Critical)
                    End If
                End If


            Catch ex As Exception
                LOGGER.Error(ex)
                MsgBox("Unexpected Error in windream-login - Step 5: " & vbNewLine & ex.Message, MsgBoxStyle.Critical, "Attention:")
            End Try
        Else
            BarButtonItemFileLink.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
            SOURCE_INIT = Init_IDB()
            If SOURCE_INIT = True Then
                Dim oSQL = $"SELECT SQL_COMMAND FROM TBDD_SQL_COMMANDS WITH (NOLOCK) WHERE TITLE = 'PM_IDB_DOC_DATA'"

                Dim DTIDB_DOC_DATA_SQL = DatabaseFallback.GetDatatable("TBDD_SQL_COMMANDS", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
                    .FilterExpression = "TITLE = 'PM_IDB_DOC_DATA'"
                })

                IDB_DOC_DATA_SQL = DTIDB_DOC_DATA_SQL.Rows(0).Item("SQL_COMMAND")
                LOGGER.Debug($"Got the IDB_DOC_DATA_SQL..{IDB_DOC_DATA_SQL}")
            End If

            bsiGeneralInfo.Caption = S.IDB_Aktiv

        End If
        If EDMIAppServerActive = True Then
            BarStaticItemAppServer.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        Else
            BarStaticItemAppServer.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        End If
        If BASIC_CONF_VISIBLE = False Then
            RibbonPageGroupBasicConf.Visible = False
            barbtnitmsaveLogfiles.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        Else
            RibbonPageGroupBasicConf.Visible = True
        End If
        If MAINFORM_CREATE_LOG_FILES = True Then
            barbtnitmsaveLogfiles.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        End If
        If EXCEL_OVERVIEW = True Then
            BarButtonItemExportExcel.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        Else
            BarButtonItemExportExcel.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        End If
        If BASEDATA_DT_LANGUAGE.Rows.Count > 1 Then
            bbtnitmLanguage_Change.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        Else
            bbtnitmLanguage_Change.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        End If
        ' ===== CHECKBOX AUS CONFIG INITIALISIEREN (VOR Decide_Load) =====
        ' Ohne diesen Block ist Checked immer False nach Neustart, unabhängig vom gespeicherten Config-Wert
        Try
            Bchkitm_load_empty_wf.Checked = CONFIG.Config.Hide_Empty_Workflows
            LOGGER.Debug($"frmMain_Shown: Bchkitm_load_empty_wf.Checked initialized from config: [{CONFIG.Config.Hide_Empty_Workflows}]")
        Catch ex As Exception
            LOGGER.Warn($"frmMain_Shown: Could not initialize Bchkitm_load_empty_wf.Checked - {ex.Message}")
        End Try
        LoadCURRENT_DT_PROFILES()
        LoadVWPM_CONTROL_INDEX()

        LOGGER.Debug("MainForm initialized!")

        FormOpenClose = False
    End Sub
    Private Sub Load_Treeview()
        Try
            Me.Cursor = Cursors.WaitCursor
            Dim oSQL = $"SELECT * FROM [dbo].[FNTF_GET_COCKPIT_DEFINITION] ({USER_ID},'{USER_LANGUAGE}')"
            Dim oDT_STRUCTURE_NODES As DataTable = DatabaseFallback.GetDatatableECM(oSQL)
            If oDT_STRUCTURE_NODES Is Nothing OrElse oDT_STRUCTURE_NODES.Rows.Count = 0 Then
                Dim oMsg As String
                Dim oTitle As String
                Select Case USER_LANGUAGE
                    Case "fr-FR", "fr-BE", "fr-CH"
                        oMsg = "Aucune configuration de cockpit n'a pu être lue. Veuillez contacter votre équipe d'administration!"
                        oTitle = "Erreur de configuration"
                    Case "es-ES", "es-MX", "es-AR"
                        oMsg = "No se pudo leer ninguna configuración de cockpit. ¡Póngase en contacto con su equipo de administración!"
                        oTitle = "Error de configuración"
                    Case "de-DE", "de-AT", "de-CH"
                        oMsg = "Es konnte keine Cockpit-Konfiguration ausgelesen werden. Kontaktieren Sie Ihr Administrationsteam!"
                        oTitle = "Konfigurationsfehler"
                    Case Else ' en-US, en-GB und alle weiteren
                        oMsg = "No cockpit configuration could be read. Please contact your administration team!"
                        oTitle = "Configuration Error"
                End Select
                LOGGER.Warn($"Load_Treeview: No node configuration found for USER_ID [{USER_ID}] - USER_LANGUAGE [{USER_LANGUAGE}]")
                MsgBox(oMsg, MsgBoxStyle.Critical, oTitle)
                Exit Sub
            End If

            ' ===== NUR AKTIVE KNOTEN BEHALTEN =====
            If oDT_STRUCTURE_NODES.Columns.Contains("ACTIVE") Then
                Dim oInactiveRows As DataRow() = oDT_STRUCTURE_NODES.Select("ACTIVE = 0 OR ACTIVE IS NULL")
                If oInactiveRows.Length > 0 Then
                    LOGGER.Debug($"Load_Treeview: Removing [{oInactiveRows.Length}] inactive node(s) (ACTIVE=0 or NULL)")
                    For Each oRow As DataRow In oInactiveRows
                        oRow.Delete()
                    Next
                    oDT_STRUCTURE_NODES.AcceptChanges()
                End If
            Else
                LOGGER.Warn("Load_Treeview: ACTIVE column not found in FNTF_GET_COCKPIT_DEFINITION result")
            End If

            ' ===== ANZAHL DER OVERVIEW-KNOTEN ERMITTELN (VOR WEITEREN FILTERN) =====
            Dim oOverviewRows As DataRow() = oDT_STRUCTURE_NODES.Select("TYPE_ID = 0")
            LOGGER.Debug($"Load_Treeview: Found [{oOverviewRows.Length}] node(s) with TYPE_ID=0 (Overview)")

            ' ===== MONITOR-KNOTEN ENTFERNEN WENN KEIN RECHT =====
            If MONITORING_ACTIVE = False AndAlso oDT_STRUCTURE_NODES.Columns.Contains("TYPE_ID") Then
                Dim oMonitorRows As DataRow() = oDT_STRUCTURE_NODES.Select("TYPE_ID = 2")
                If oMonitorRows.Length > 0 Then
                    LOGGER.Debug($"Load_Treeview: MONITORING_ACTIVE=False - removing [{oMonitorRows.Length}] monitor node(s) from TreeList datasource")
                    For Each oRow As DataRow In oMonitorRows
                        oRow.Delete()
                    Next
                    oDT_STRUCTURE_NODES.AcceptChanges()
                End If
            End If

            ' ===== CHART-KNOTEN ENTFERNEN WENN KEIN RECHT =====
            If SHOW_CHARTS = False AndAlso oDT_STRUCTURE_NODES.Columns.Contains("TYPE_ID") Then
                Dim oChartRows As DataRow() = oDT_STRUCTURE_NODES.Select("TYPE_ID = 3")
                If oChartRows.Length > 0 Then
                    LOGGER.Debug($"Load_Treeview: SHOW_CHARTS=False - removing [{oChartRows.Length}] chart node(s) from TreeList datasource")
                    For Each oRow As DataRow In oChartRows
                        oRow.Delete()
                    Next
                    oDT_STRUCTURE_NODES.AcceptChanges()
                End If
            End If

            TreeList_Cockpit.BeginUpdate()
            Try
                TreeList_Cockpit.DataSource = oDT_STRUCTURE_NODES
                AddHandler TreeList_Cockpit.CustomDrawNodeCell, AddressOf TreeList_Cockpit_CustomDrawNodeCell
                TreeList_Cockpit.KeyFieldName = "PK_CFG_COCKPIT_DEFINITION_ID"
                TreeList_Cockpit.ParentFieldName = "PARENT_ID"
                TreeList_Cockpit.Columns("PK_RESULT_ID").SortOrder = SortOrder.Ascending

                ' ===== MODERNES DESIGN =====
                ' Schriftgröße und -art
                TreeList_Cockpit.Appearance.Row.Font = New Font("Segoe UI", 12, FontStyle.Regular)
                TreeList_Cockpit.Appearance.FocusedRow.Font = New Font("Segoe UI", 12, FontStyle.Bold)
                TreeList_Cockpit.Appearance.HideSelectionRow.Font = New Font("Segoe UI", 12, FontStyle.Regular)

                ' Modernes Farbschema (passend zum Office2019-Skin)
                TreeList_Cockpit.Appearance.Row.BackColor = Color.White
                TreeList_Cockpit.Appearance.Row.ForeColor = Color.FromArgb(50, 50, 50)
                TreeList_Cockpit.Appearance.FocusedRow.BackColor = Color.FromArgb(210, 230, 255)
                TreeList_Cockpit.Appearance.FocusedRow.ForeColor = Color.FromArgb(20, 20, 20)
                TreeList_Cockpit.Appearance.HideSelectionRow.BackColor = Color.FromArgb(225, 235, 250)
                TreeList_Cockpit.Appearance.HideSelectionRow.ForeColor = Color.FromArgb(50, 50, 50)

                ' Zeilenhöhe erhöhen für bessere Lesbarkeit
                TreeList_Cockpit.RowHeight = 28

                Dim oVisibleColumns As New System.Collections.Generic.HashSet(Of String)(StringComparer.OrdinalIgnoreCase) From {"NAME"}
                For Each oColumn As DevExpress.XtraTreeList.Columns.TreeListColumn In TreeList_Cockpit.Columns
                    oColumn.Visible = oVisibleColumns.Contains(oColumn.FieldName)
                Next
            Finally
                TreeList_Cockpit.EndUpdate()
            End Try

            ' ===== KNOTEN AUF-/ZUKLAPPEN BASIEREND AUF ANZAHL DER OVERVIEW-KNOTEN =====
            If oOverviewRows.Length = 1 Then
                LOGGER.Debug("Load_Treeview: Only 1 overview node found - expanding all nodes")
                For Each oNode As DevExpress.XtraTreeList.Nodes.TreeListNode In TreeList_Cockpit.Nodes
                    oNode.Expanded = True
                Next
            ElseIf oOverviewRows.Length > 1 Then
                LOGGER.Debug($"Load_Treeview: [{oOverviewRows.Length}] overview nodes found - collapsing all nodes")
                For Each oNode As DevExpress.XtraTreeList.Nodes.TreeListNode In TreeList_Cockpit.Nodes
                    oNode.Expanded = False
                Next
            Else
                LOGGER.Warn("Load_Treeview: No overview nodes (TYPE_ID=0) found - keeping default collapsed state")
            End If

            TreeList_Cockpit.Refresh()

            ' ===== ANZAHL ASYNCHRON NACHLADEN =====
            If oDT_STRUCTURE_NODES.Columns.Contains("SQL_QUERY_COUNT") Then
                AppendCountsToTreeAsync()
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
        Finally
            Me.Cursor = Cursors.Default
        End Try
    End Sub
    Private Sub TreeList_Cockpit_CustomDrawNodeCell(sender As Object, e As DevExpress.XtraTreeList.CustomDrawNodeCellEventArgs)
        Try
            Dim oPk As Object = e.Node.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")
            If oPk Is Nothing OrElse IsDBNull(oPk) Then
                Exit Sub
            End If

            Dim oPkInt As Integer = CInt(oPk)
            If Not _treeNodeCounts.ContainsKey(oPkInt) Then
                Exit Sub
            End If

            If _treeNodeCounts(oPkInt) > 0 Then
                e.Appearance.Font = New Font(e.Appearance.Font, FontStyle.Bold)
            Else
                e.Appearance.Font = New Font(e.Appearance.Font, FontStyle.Regular)
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Async Sub AppendCountsToTreeAsync()
        Try
            LOGGER.Debug("AppendCountsToTreeAsync: Starting background count queries...")

            Dim oWorkItems As New List(Of (Node As DevExpress.XtraTreeList.Nodes.TreeListNode, SQL As String, OriginalName As String))

            TreeList_Cockpit.NodesIterator.DoOperation(
            Sub(oNode As DevExpress.XtraTreeList.Nodes.TreeListNode)
                Dim oTypeId As Object = oNode.GetValue("TYPE_ID")
                Dim oProfileID As Object = oNode.GetValue("FK_PROFILE_ID")
                If oTypeId Is Nothing OrElse IsDBNull(oTypeId) Then
                    LOGGER.Debug($"AppendCountsToTreeAsync: Node [{oNode.GetValue("NAME")}] has no TYPE_ID - skipping.")
                    Exit Sub
                End If
                Dim oTypeIdInt As Integer = CInt(oTypeId)
                If oTypeIdInt <> 0 AndAlso oTypeIdInt <> 1 Then
                    Exit Sub
                End If

                Dim oSqlCount As Object = oNode.GetValue("SQL_QUERY_COUNT")
                If oSqlCount IsNot Nothing AndAlso Not IsDBNull(oSqlCount) AndAlso Not String.IsNullOrWhiteSpace(oSqlCount.ToString()) Then
                    Dim oProfileIdInt As Integer = If(oProfileID IsNot Nothing AndAlso Not IsDBNull(oProfileID), CInt(oProfileID), 0)
                    Dim oRawSQL As String = oSqlCount.ToString()
                    LOGGER.Debug($"AppendCountsToTreeAsync: Preparing SQL for node [{oNode.GetValue("NAME")}] with PROFILE_ID [{oProfileIdInt}]")
                    LOGGER.Debug($"AppendCountsToTreeAsync: Original SQL: {oRawSQL}")
                    oRawSQL = oRawSQL.Replace("@PROFILE_ID", oProfileIdInt.ToString())
                    oRawSQL = oRawSQL.Replace("@PROFIL_ID", oProfileIdInt.ToString())
                    oRawSQL = oRawSQL.Replace("{#USER#PROFILE_ID}", oProfileIdInt.ToString())
                    oRawSQL = oRawSQL.Replace("{#USER#PROFIL_ID}", oProfileIdInt.ToString())
                    Dim oPreparedSQL As String = PrepareSQLWithReplacements(oRawSQL, oProfileIdInt)

                    ' ===== COUNT-SUFFIX VOM VORHERIGEN DURCHLAUF ENTFERNEN =====
                    Dim oRawName As String = oNode.GetValue("NAME")?.ToString()
                    Dim oSuffixMatch = System.Text.RegularExpressions.Regex.Match(oRawName, "^(.*)\s+\(\d+\)$")
                    Dim oCleanName As String = If(oSuffixMatch.Success, oSuffixMatch.Groups(1).Value.Trim(), oRawName)

                    If Not String.IsNullOrWhiteSpace(oCleanName) Then
                        oWorkItems.Add((oNode, oPreparedSQL, oCleanName))
                    End If
                Else
                    LOGGER.Debug($"AppendCountsToTreeAsync: Node [{oNode.GetValue("NAME")}] has no valid SQL_QUERY_COUNT, skipping.")
                End If
            End Sub)

            If oWorkItems.Count = 0 Then
                LOGGER.Debug("AppendCountsToTreeAsync: No nodes with SQL_QUERY_COUNT found, exiting.")
                Exit Sub
            End If

            LOGGER.Debug($"AppendCountsToTreeAsync: {oWorkItems.Count} node(s) with SQL_QUERY_COUNT found")

            Dim oResults As New List(Of (Node As DevExpress.XtraTreeList.Nodes.TreeListNode, OriginalName As String, Count As String))

            Await Task.Run(Sub()
                               For Each oItem In oWorkItems
                                   Try
                                       Dim oResult As Object = DatabaseFallback.GetScalarValueECM(oItem.SQL)
                                       If oResult IsNot Nothing AndAlso Not IsDBNull(oResult) Then
                                           SyncLock oResults
                                               oResults.Add((oItem.Node, oItem.OriginalName, oResult.ToString()))
                                           End SyncLock
                                       End If
                                   Catch ex As Exception
                                       LOGGER.Warn($"AppendCountsToTreeAsync: Count query failed for node [{oItem.OriginalName}] - {ex.Message}")
                                   End Try
                               Next
                           End Sub)

            _treeNodeCounts.Clear()

            TreeList_Cockpit.BeginUpdate()
            Try
                For Each oResult In oResults
                    Dim oPk As Object = oResult.Node.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")
                    If oPk IsNot Nothing AndAlso Not IsDBNull(oPk) Then
                        Dim oCount As Integer = 0
                        Integer.TryParse(oResult.Count, oCount)
                        _treeNodeCounts(CInt(oPk)) = oCount
                    End If
                    oResult.Node.SetValue("NAME", $"{oResult.OriginalName} ({oResult.Count})")
                    LOGGER.Debug($"AppendCountsToTreeAsync: Node [{oResult.OriginalName}] → [{oResult.OriginalName} ({oResult.Count})]")
                Next
            Finally
                TreeList_Cockpit.EndUpdate()
            End Try

            TreeList_Cockpit.Refresh()
            LOGGER.Debug("AppendCountsToTreeAsync: Finished")
            Decide_Show_Empty_Workflows(Not CONFIG.Config.Hide_Empty_Workflows)
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Function IsPositionVisible(position As System.Drawing.Point) As Boolean
        For Each scr As Screen In Screen.AllScreens
            If scr.WorkingArea.Contains(position) Then
                Return True ' Punkt ist auf diesem Bildschirm sichtbar
            End If
        Next
        Return False ' Punkt ist außerhalb aller sichtbaren Bereiche
    End Function
    Public Class FontSetting
        Public Property Title As String
        Public Property Value As Integer

        Public Overrides Function ToString() As String
            Return Title
        End Function
    End Class

    Sub Check_Timer_Notification()
        Try
            If CONFIG.Config.ReminderTimer <> 0 Then
                TimerReminder.Stop()
                TimerReminder.Interval = CONFIG.Config.ReminderTimer * 60000
                TimerReminder.Start()
            Else
                TimerReminder.Enabled = False
                TimerReminder.Stop()
            End If
        Catch ex As Exception
            LOGGER.Error(ex)

        End Try

    End Sub
    Public Sub Timer_Inactivity_Reset_Disable(pTrigger As String)
        Try
            If Timer5Mins_running = True Or TimerRefresh_running = True Or FormShown = False Then
                Exit Sub
            End If
            If INACTIVITY_DURATION <> 0 Then
                TimerInactivity.Enabled = False
                TimerInactivity.Stop()
                TimerInactivity.Interval = INACTIVITY_DURATION * 60000
                TimerInactivity.Enabled = True
                TimerInactivity.Start()
                bsiInactivityCheck.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                Dim StartTime As DateTime = #12:00:00 AM#

                Dim oStarttime As DateTime = Now
                oStarttime = oStarttime.AddMinutes(INACTIVITY_DURATION)
                If LOGCONFIG.Debug = False Then
                    pTrigger = ""
                Else
                    pTrigger = $"({pTrigger})"
                End If

                bsiInactivityCheck.Caption = String.Format(S.Nächste_Aktivitätsüberprüfung___0___1_, oStarttime.ToShortTimeString, pTrigger)
            Else
                TimerInactivity.Enabled = False
                TimerInactivity.Stop()
                bsiInactivityCheck.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
            End If
        Catch ex As Exception
            LOGGER.Error(ex)

        End Try

    End Sub
    Sub Restore_Form_Position()
        Try
            'Sind Werte hinterlegt?
            If My.Settings.frmMainPosition.IsEmpty = False Then

                If My.Settings.frmMainPosition.X > 0 And My.Settings.frmMainPosition.Y > 0 Then
                    If Not My.Settings.frmMainSize.IsEmpty Then
                        If My.Settings.frmMainWindowState = "Normal" Then
                            Dim oisonscreen = IsOnScreen(My.Settings.frmMainPosition, My.Settings.frmMainSize)
                            If oisonscreen = False Then
                                Me.StartPosition = FormStartPosition.CenterScreen
                                Exit Sub
                            Else
                                ' Gespeicherte Werte verwenden
                                Me.Location = Screen.AllScreens(UBound(Screen.AllScreens)).Bounds.Location + My.Settings.frmMainPosition
                            End If
                        Else
                            Me.WindowState = FormWindowState.Maximized
                        End If
                    End If
                Else
                    LOGGER.Info("FormPosition is out of range!..Standard will be loaded!")
                    If My.Settings.frmMainWindowState = "Normal" Then
                        Me.StartPosition = FormStartPosition.CenterScreen
                    Else
                        Me.WindowState = FormWindowState.Maximized
                    End If
                End If

            End If
            'Sind Werte hinterlegt?
            'If Not My.Settings.frmMainSize.IsEmpty Then
            '    If My.Settings.frmMainWindowState = "Normal" Then
            '        Dim oisonscreen = IsOnScreen(My.Settings.frmMainPosition, My.Settings.frmMainSize)

            '        If oisonscreen = False Then
            '            Me.StartPosition = FormStartPosition.CenterScreen
            '            Exit Sub
            '        End If
            '        ' Gespeicherte Werte verwenden
            '        Try
            '            Me.Size = My.Settings.frmMainSize
            '        Catch ex As Exception

            '        End Try
            '    Else
            '        Me.WindowState = FormWindowState.Maximized
            '    End If


            'End If
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Error in Load FormLayout: " & ex.Message)
        End Try
    End Sub
    Function IsOnScreen(ByVal RecLocation As System.Drawing.Point, ByVal RecSize As System.Drawing.Size, Optional MinPercentOnScreen As Double = 0.2)
        Try
            Dim PixelsVisible As Double = 0
            Dim Rec As System.Drawing.Rectangle = New System.Drawing.Rectangle(RecLocation, RecSize)
            For Each Scrn As Screen In Screen.AllScreens
                Dim r As System.Drawing.Rectangle = System.Drawing.Rectangle.Intersect(Rec, Scrn.WorkingArea)
                'intersect rectangle with screen
                If (r.Width <> 0 And r.Height <> 0) Then
                    PixelsVisible += (r.Width * r.Height)
                    'tally visible pixels
                End If

            Next
            Return PixelsVisible >= (Rec.Width * Rec.Height) * MinPercentOnScreen
        Catch ex As Exception
            Return False
        End Try

    End Function

    Private Function GetLayoutName_GridMain()
        Dim oLoadTypeSuffix As String = GRID_LOAD_TYPE

        ' Bei mehreren Gesamtübersichten die COCKPIT_CONFIG_ID als Suffix anhängen
        If GRID_LOAD_TYPE = "OVERVIEW" AndAlso COCKPIT_CONFIG_ID > 0 Then
            oLoadTypeSuffix = $"OVERVIEW_{COCKPIT_CONFIG_ID}"
        End If

        Dim Filename As String = String.Format("DevExpressGridViewOverview_UserLayout_{0}_{1}.xml", oLoadTypeSuffix, USER_LANGUAGE)
        LOGGER.Debug($"LayoutFilename is: {Filename}")
        Return System.IO.Path.Combine(USER_CONFIG_DIRECTORY, Filename)
    End Function

    Private Sub SaveGridLayout()
        Timer_Inactivity_Reset_Disable("SaveGridLayout")
        If NO_WORKFLOW_ITEMS = True Then
            Exit Sub
        End If

        Try
            Dim oXmlPath As String = GetLayoutName_GridMain()
            GridViewWorkflows.SaveLayoutToXml(oXmlPath, OptionsLayoutBase.FullLayout)
            LOGGER.Debug("Layout saved successfully!")
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Error while saving GridLayout MainGrid: " & ex.Message)
        End Try
    End Sub

    Private Sub RestoreLayout()
        If NO_WORKFLOW_ITEMS = True Then
            Exit Sub
        End If

        Try
            Dim oXmlPath As String = GetLayoutName_GridMain()
            If System.IO.File.Exists(oXmlPath) Then
                GridViewWorkflows.RestoreLayoutFromXml(oXmlPath, OptionsLayoutBase.FullLayout)
            Else
                LOGGER.Info("oXmlPath not existing - Saving Layout")
                COLUMNS_INVISIBLE()
                SaveGridLayout()
            End If

        Catch ex As Exception
            LOGGER.Info("Error while restoring layout MainGrid: " & ex.Message)
        End Try
    End Sub
    Private Sub COLUMNS_INVISIBLE()
        Try
            If GridViewWorkflows.Columns.Count = 0 Then
                Exit Sub
            End If

            ' Sichere Prüfung für jede Spalte
            If GridViewWorkflows.Columns.ColumnByFieldName("PROFILE_ID") IsNot Nothing Then
                GridViewWorkflows.Columns.Item("PROFILE_ID").Visible = False
            End If

            If GridViewWorkflows.Columns.ColumnByFieldName("GUID") IsNot Nothing Then
                GridViewWorkflows.Columns.Item("GUID").Visible = False
            End If

            Try
                If GridViewWorkflows.Columns.ColumnByFieldName(FullFilepatColName) IsNot Nothing Then
                    GridViewWorkflows.Columns.Item(FullFilepatColName).Visible = False
                End If
            Catch ex As Exception
            End Try

            Try
                If GridViewWorkflows.Columns.ColumnByFieldName("TL_STATE") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("TL_STATE").Visible = False
                End If
            Catch ex As Exception
            End Try

            Try
                If GridViewWorkflows.Columns.ColumnByFieldName("CONV_YN") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("CONV_YN").Visible = False
                End If
            Catch ex As Exception
            End Try
        Catch ex As Exception
            LOGGER.Warn($"Error in COLUMNS_INVISIBLE: {ex.Message}")
        End Try
    End Sub
    Private Sub ResetLayout()
        Try
            Timer_Inactivity_Reset_Disable("ResetLayout")
            Dim xml As String = GetLayoutName_GridMain()
            IO.File.Delete(xml)
            Try
                GridViewWorkflows.Columns.Clear()
            Catch ex As Exception
                If IsNothing(GridViewWorkflows) Then
                    LOGGER.Warn("⚠️ Somehow GridViewWorkflows is nothing....")
                Else
                    If IsNothing(GridViewWorkflows.Columns) Then
                        LOGGER.Warn("⚠️ Somehow GridViewWorkflows.Columns is nothing....")

                    End If
                End If
                Exit Sub
            End Try

            GridViewWorkflows.PopulateColumns()
            If GridViewWorkflows.Columns.Count > 0 Then
                Try
                    If TL_ICON = True Then
                        GridViewWorkflows.Columns.Item("ICON").MaxWidth = 24
                        GridViewWorkflows.Columns.Item("ICON").MinWidth = 24
                        GridViewWorkflows.Columns.Item("ICON").AppearanceCell.BackColor = Color.White
                        GridViewWorkflows.Columns.Item("ICON").Fixed = FixedStyle.Left
                    End If
                Catch ex As Exception

                End Try


                'If IDB_ACTIVE = True Then
                '    Try
                '        If GridViewWorkflows.Columns.Item("CONV_YN") IsNot Nothing Then
                '            GridViewWorkflows.Columns.Item("CONV_YN").Visible = False
                '        End If
                '    Catch ex As Exception
                '        LOGGER.Info("ResetLayout - Check wether Column CONV_YN is part of select/view..now checking CONVERSATION")
                '    End Try
                '    Try
                '        GridViewWorkflows.Columns.Item("CONVERSATION").MaxWidth = 24
                '        GridViewWorkflows.Columns.Item("CONVERSATION").MinWidth = 24
                '        GridViewWorkflows.Columns.Item("CONVERSATION").Fixed = FixedStyle.Left
                '    Catch ex As Exception
                '        LOGGER.Info("ResetLayout - Column CONVERSATION obviously is not part of GridViewWorkflows")
                '    End Try
                'End If

                Dim oReducedColName As String
                If Not IsNothing(GridViewWorkflows.Columns) Then
                    Try
                        oReducedColName = LAST_EDITED_COLUMN.Replace("[", "")
                        oReducedColName = oReducedColName.Replace("]", "")
                        'GridViewWorkflows.Columns(oReducedColName).DisplayFormat.FormatType = FormatType.DateTime
                        'GridViewWorkflows.Columns(oReducedColName).DisplayFormat.FormatString = "dd.MM.yyyy HH:MM:ss"
                    Catch ex As Exception
                        Try
                            If oReducedColName <> "Zuletzt bearbeitet" Then
                            End If
                        Catch ex1 As Exception
                            LOGGER.Warn($"(ResetLayout)Column [{oReducedColName}] or [Zuletzt bearbeitet] not part of OverviewSQL")
                        End Try

                    End Try
                End If


                Try
                    GridViewWorkflows.Columns.Item("GROUP_TEXT").Visible = False
                    GridViewWorkflows.Columns.Item("GROUP_COLOR").Visible = False

                Catch ex As Exception

                End Try
                Try
                    If GridViewWorkflows.Columns.ColumnByFieldName("ROW_COLOR") IsNot Nothing Then
                        GridViewWorkflows.Columns.Item("ROW_COLOR").Visible = False
                    End If
                Catch ex As Exception

                End Try
                ' GridViewWorkflows.OptionsView.ShowIndicator = False
                COLUMNS_INVISIBLE()

            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Error while resetting layout: " & ex.Message)
        End Try
    End Sub

    'Sub LoadNavBar()
    '    Dim profileGroupOpen As Boolean = False
    '    If Not IsNothing(CurrNavBarGroup) Then
    '        NavBarControl1.BeginUpdate() ' <-- Hinzufügen
    '        Try
    '            profileGroupOpen = CurrNavBarGroup.Expanded
    '            Try
    '                CurrNavBarGroup.ItemLinks.Clear()
    '            Catch ex As Exception
    '                LOGGER.Error(ex)
    '                LOGGER.Info("CurrGroupClear - Error: " & ex.Message)

    '            End Try

    '        Catch ex As Exception
    '        Finally
    '            NavBarControl1.EndUpdate() ' <-- Hinzufügen
    '        End Try

    '    End If
    '    Try



    '        If Load_Profiles_for_User() = False Then
    '            Throw New Exception("Could not load Profiles. Datatable is empty")
    '            Exit Sub
    '        End If
    '        If NO_DETAIL_PROFILES = False Then
    '            NavBarControl1.Visible = True
    '            Dim oCountItems As Integer = 0
    '            For Each oProfileRow As DataRow In CURR_DT_VWPM_PROFILE_ACTIVE.Rows
    '                Dim ODisplayMode = oProfileRow.Item("DISPLAY_MODE")
    '                If (ODisplayMode = "Overview and Detail" Or ODisplayMode = "Detail") Then
    '                    oCountItems += 1
    '                    Dim item1 As NavBarItem = NavBarControl1.Items.Add()
    '                    item1.Caption = oProfileRow.Item("TITLE")
    '                    item1.Hint = oProfileRow.Item("TITLE")
    '                    item1.Appearance.TextOptions.WordWrap = WordWrap.Wrap
    '                    item1.Tag = "itmProfile#" & oProfileRow.Item("GUID").ToString

    '                    Dim _image As Image = Nothing
    '                    _image = DevExpress.Images.ImageResourceCache.Default.GetImage("images/business%20objects/bofileattachment_16x16.png")
    '                    item1.LargeImage = _image
    '                    item1.SmallImage = _image

    '                    NavBarControl1.Groups(1).ItemLinks.Add(item1)
    '                End If
    '            Next
    '            If oCountItems > 0 Then
    '                If NavBarControl1.Groups(1).Visible = False Then
    '                    NavBarControl1.Groups(1).Visible = True
    '                End If
    '            Else
    '                If NavBarControl1.Groups(1).Visible = True Then
    '                    NavBarControl1.Groups(1).Visible = False
    '                End If
    '            End If

    '            If Not IsNothing(CurrNavBarGroup) Then
    '                CurrNavBarGroup.Expanded = profileGroupOpen
    '            Else
    '                NavBarControl1.Groups(1).Expanded = True
    '            End If
    '        Else
    '            LOGGER.Debug("NavBarControl - No Detail Profiles")
    '            NavBarControl1.Visible = False
    '        End If

    '    Catch ex As Exception
    '        LOGGER.Error(ex)
    '        LOGGER.Info("Load_Profile_items - Error: " & ex.Message)
    '        'MsgBox("Unexpected Error in Load_Profile_items - Error: " & vbNewLine & ex.Message, MsgBoxStyle.Critical)
    '    End Try

    'End Sub
    'Private Async Sub navBar_LinkClicked(ByVal sender As Object, ByVal e As NavBarLinkEventArgs)
    '    If Application.OpenForms().OfType(Of frmValidator).Any Then
    '        FormHelper.ShowInfoMessage(S.Bitte_schließen_Sie_den_offenen_Workflow_, omsgTitleWarning)
    '        Exit Sub
    '    End If

    '    FRONTEND_ACTION = NAVBAR_CLICKED
    '    Dim _tag = e.Link.Item.Tag
    '    Timer_Inactivity_Reset_Disable("navBar_LinkClicked")

    '    Try
    '        If Not IsNothing(_tag) Then
    '            If _tag.ToString.Contains("itmProfile#") Then
    '                ' ========== PROFIL WURDE GEKLICKT ==========
    '                _tag = _tag.ToString.Replace("itmProfile#", "")
    '                If IsNumeric(_tag) Then
    '                    If CURRENT_CLICKED_PROFILE_ID <> _tag Then
    '                        LOGGER.Debug($"Profile with ID {_tag} clicked in NavBarControl...loading Profile...")
    '                        OverviewOrDEtail = "DETAIL"
    '                        If Not Application.OpenForms().OfType(Of frmValidator).Any Then
    '                            CURRENT_CLICKED_PROFILE_ID = _tag
    '                            CURRENT_CLICKED_PROFILE_TITLE = e.Link.Item.Caption
    '                        End If

    '                        GRID_LOAD_TYPE = "PROFILE#" & _tag.ToString
    '                        DetailLinkActive = True

    '                        ' RefreshHelper VORHER speichern
    '                        If GridControlWorkflows.Visible = True And FormOpenClose = False Then
    '                            RefreshHelper.SaveViewInfo()
    '                        End If

    '                        Me.Cursor = Cursors.WaitCursor
    '                        Try
    '                            LOGGER.Debug($"Loading profile with ID {_tag}...")
    '                            ' Zentral über Decide_Load laden
    '                            Await Decide_Load(False, True)
    '                        Finally
    '                            Me.Cursor = Cursors.Default
    '                        End Try
    '                    Else
    '                        LOGGER.Debug($"Profile with ID {_tag} clicked in NavBarControl is already active...ignoring click.")
    '                    End If
    '                End If

    '            ElseIf _tag = "OVERVIEW" Then
    '                ' ========== OVERVIEW WURDE GEKLICKT ==========
    '                OverviewOrDEtail = "OVERVIEW"
    '                GRID_LOAD_TYPE = "OVERVIEW"

    '                Dim oForce As Boolean = False
    '                If DetailLinkActive = True Then
    '                    oForce = True
    '                    DetailLinkActive = False
    '                    OVERVIEW_ADDED_WHEN = ""
    '                End If

    '                ' RefreshHelper VORHER speichern
    '                If GridControlWorkflows.Visible = True And FormOpenClose = False Then
    '                    RefreshHelper.SaveViewInfo()
    '                End If

    '                ' Zentral über Decide_Load laden
    '                Await Decide_Load(False, oForce)

    '                ' RefreshHelper NACHHER laden
    '                If GridControlWorkflows.Visible = True And FormOpenClose = False Then
    '                    RefreshHelper.LoadViewInfo()
    '                End If

    '                ' Gruppierung prüfen
    '                If GridViewWorkflows.GroupCount = 0 And Not IsNothing(GridViewWorkflows.Columns("GROUP_TEXT")) Then
    '                    LOGGER.Info("NO GROUPS AFTER CLICK OVERVIEW...CREATING GROUPS NEW...")
    '                    Await Decide_Load(False, True)
    '                    If GridControlWorkflows.Visible = True And FormOpenClose = False Then
    '                        RefreshHelper.LoadViewInfo()
    '                    End If
    '                End If
    '            End If
    '        End If

    '    Catch ex As Exception
    '        LOGGER.Error(ex)
    '        FormHelper.ShowInfoMessage($"Fehler beim Laden: {ex.Message}", omsgTitleWarning)
    '    Finally
    '        FRONTEND_ACTION = FA_NONE
    '    End Try
    'End Sub
    Function Load_Profiles_for_User() As Boolean
        Try
            LOGGER.Debug($"Load_Profiles_for_User ...")
            If IsNothing(CURR_DT_VWPM_PROFILE_ACTIVE) Then
                LOGGER.Info($"ATTENTION: CURR_DT_VWPM_PROFILE_ACTIVE is nothing!")
                Return False
            End If
            LOGGER.Debug($"Load_Profiles_for_User: Current datatable has {CURR_DT_VWPM_PROFILE_ACTIVE.Rows.Count} rows")
            Return True
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Load_Profiles_for_User - Error: " & ex.Message)
            Return False
        End Try
    End Function
    Sub GridControlWorkflows_Visible()
        Try
            If GridControlWorkflows.Visible = False Then
                GridControlWorkflows.Visible = True
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Async Function Load_single_Profile(Optional ForceReload As Boolean = False) As Tasks.Task
        Dim gridUpdateStarted As Boolean = False
        Dim viewUpdateStarted As Boolean = False

        Try
            FRONTEND_ACTION = "Load_single_Profile"
            Load_Profiles_for_User()
            GridControlWorkflows_Visible()

            Dim expression As String = "GUID = " & CURRENT_CLICKED_PROFILE_ID
            Dim foundRow As DataRow = CURR_DT_VWPM_PROFILE_ACTIVE.Select(expression).FirstOrDefault()
            If foundRow Is Nothing Then
                Exit Function
            End If

            If GridControlWorkflows.Visible Then
                GridControlWorkflows.BeginUpdate()
                gridUpdateStarted = True
                GridViewWorkflows.BeginUpdate()
                viewUpdateStarted = True
            End If

            Dim oSQL = foundRow.Item("SQL_VIEW")
            oSQL = clsPatterns.ReplaceInternalValues(oSQL)
            oSQL = clsPatterns.ReplaceUserValues(oSQL)
            oSQL = oSQL.Replace("@USER_ID", USER_ID)
            oSQL = oSQL.Replace("@USERNAME", USER_USERNAME)
            oSQL = oSQL.Replace("@MACHINE_NAME", System.Environment.MachineName)
            oSQL = oSQL.Replace("@DATE", Now.ToShortDateString)
            oSQL = oSQL.Replace("@PROFILE_ID", CURRENT_CLICKED_PROFILE_ID)

            DT_CURR_WF_ITEMS = Await DatabaseFallback.GetDatatableECMAsync(oSQL)

            If IsNothing(DT_CURR_WF_ITEMS) Then
                Exit Function
            End If

            Dim oADDED = GET_LAST_ADDED(DT_CURR_WF_ITEMS)
            Dim oChanged = GET_LAST_CHANGED(DT_CURR_WF_ITEMS)
            Dim oCOUNT = DT_CURR_WF_ITEMS.Rows.Count

            ' Workflowitems-Status setzen
            NO_WORKFLOW_ITEMS = (oCOUNT = 0)

            ' Caption IMMER aktualisieren (vor Hash-Prüfung!)
            UpdateGridCaption()

            ' Datenquelle bei leeren Items zurücksetzen
            If NO_WORKFLOW_ITEMS Then
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Exit Function
            End If

            ' Hash-Prüfung für Performance-Optimierung
            If ForceReload = False Then
                If oADDED = OVERVIEW_ADDED_WHEN And oChanged = OVERVIEW_CHANGED_WHEN And OVERVIEW_COUNT = oCOUNT Then
                    LOGGER.Debug("No data changes - skipping grid reload")
                    Exit Function
                End If
                OVERVIEW_ADDED_WHEN = oADDED
                OVERVIEW_CHANGED_WHEN = oChanged
                OVERVIEW_COUNT = oCOUNT
            End If

            Create_Basic_View()
            RestoreLayout()

        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Load_single_Profile - Error: " & ex.Message)
        Finally
            If viewUpdateStarted Then
                GridViewWorkflows.EndUpdate()
            End If
            If gridUpdateStarted Then
                GridControlWorkflows.EndUpdate()
            End If
            FRONTEND_ACTION = FA_NONE
        End Try
    End Function
    Sub Create_Basic_View()
        Dim gridUpdateStarted As Boolean = False
        Dim viewUpdateStarted As Boolean = False

        Try
            FRONTEND_ACTION = "Create_Basic_View"

            If GridControlWorkflows.Visible Then
                GridControlWorkflows.BeginUpdate()
                gridUpdateStarted = True
                GridViewWorkflows.BeginUpdate()
                viewUpdateStarted = True
            End If

            GridControlWorkflows.DataSource = Nothing
            Try
                GridViewWorkflows.Columns.Clear()
            Catch ex As Exception
                LOGGER.Error(ex)
                LOGGER.Warn("⚠️ Could not clear GridViewWorkflows.Columns")
            End Try

            ' Prüfen, ob TL_STATE-Spalte vorhanden ist
            Dim hasTLStateColumn As Boolean = False
            If DT_CURR_WF_ITEMS IsNot Nothing Then
                hasTLStateColumn = DT_CURR_WF_ITEMS.Columns.Contains("TL_STATE")
            End If

            ' ICON-Spalte nur hinzufügen, wenn TL_ICON aktiv UND TL_STATE verfügbar ist
            If TL_ICON = True AndAlso hasTLStateColumn AndAlso DT_CURR_WF_ITEMS IsNot Nothing AndAlso DT_CURR_WF_ITEMS.Columns.Contains("ICON") = False Then
                Dim columnStateIcon As New DataColumn() With {
                .DataType = GetType(Image),
                .ColumnName = "ICON",
                .Caption = ""
            }
                DT_CURR_WF_ITEMS.Columns.Add(columnStateIcon)
            End If

            RedDocuments = 0
            YellowDocuments = 0
            GreenDocuments = 0

            ' Icons nur setzen, wenn TL_STATE-Spalte vorhanden ist
            If TL_ICON = True AndAlso hasTLStateColumn AndAlso DT_CURR_WF_ITEMS IsNot Nothing Then
                Try
                    For Each row As DataRow In DT_CURR_WF_ITEMS.Rows
                        Dim State As Integer = CInt(row.Item("TL_STATE"))
                        Select Case State
                            Case 1
                                RedDocuments += 1
                                row.Item("ICON") = My.Resources.bullet_red
                            Case 2
                                YellowDocuments += 1
                                row.Item("ICON") = My.Resources.bullet_orange
                            Case 3
                                GreenDocuments += 1
                                row.Item("ICON") = My.Resources.bullet_green
                        End Select
                    Next
                Catch ex As Exception
                    LOGGER.Warn($"Could not set ICON values: {ex.Message}")
                End Try
            ElseIf TL_ICON = True AndAlso Not hasTLStateColumn Then
                LOGGER.Warn("⚠️ TL_ICON is enabled but TL_STATE column is missing in dataset")
            End If

            bindsourcegrid.DataSource = DT_CURR_WF_ITEMS
            GridControlWorkflows.DataSource = bindsourcegrid

            RestoreLayout()
            COLUMNS_INVISIBLE()

            Try
                If TL_ICON = True AndAlso GridViewWorkflows.Columns.Count > 0 AndAlso GridViewWorkflows.Columns.ColumnByFieldName("ICON") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("ICON").MaxWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").MinWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").AppearanceCell.BackColor = Color.White
                    GridViewWorkflows.Columns.Item("ICON").Fixed = FixedStyle.Left
                End If
            Catch ex As Exception
                LOGGER.Warn($"Could not configure ICON column: {ex.Message}")
            End Try

            Try
                Dim oReducedColName = LAST_EDITED_COLUMN.Replace("[", "").Replace("]", "")
            Catch ex As Exception
                Try
                Catch ex1 As Exception
                    LOGGER.Warn("⚠️ (CreateBasicView)Column [Last edited] or [Zuletzt bearbeitet] not part of OverviewSQL")
                End Try
            End Try

            Try
                If GridViewWorkflows.Columns.ColumnByFieldName("GROUP_TEXT") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("GROUP_TEXT").Visible = False
                End If
                If GridViewWorkflows.Columns.ColumnByFieldName("GROUP_COLOR") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("GROUP_COLOR").Visible = False
                End If
            Catch ex As Exception
                If OverviewOrDEtail = "OVERVIEW" Then
                    LOGGER.Warn("⚠️ ATTENTION: GROUP COLUMNS NOT PART OF GRID")
                End If
            End Try

        Catch ex As Exception
            LOGGER.Error(ex)
        Finally
            If viewUpdateStarted Then
                GridViewWorkflows.EndUpdate()
            End If
            If gridUpdateStarted Then
                GridControlWorkflows.EndUpdate()
            End If
            FRONTEND_ACTION = FA_NONE
        End Try
    End Sub
    Private Function GridLayoutChanged() As Boolean
        Try
            For Each oViewColumn As DataColumn In DT_CURR_WF_ITEMS.Columns
                If oViewColumn.Caption = "" Then
                    Continue For
                End If
                Dim oViewColumn_exists As Boolean = False
                For Each oActGridColumn As GridColumn In GridViewWorkflows.Columns
                    Dim oGridDXFieldName = oActGridColumn.FieldName
                    Dim GridDXColumnEditName = oActGridColumn.ColumnEditName
                    Dim GridDXFieldName = oActGridColumn.FieldName
                    If oViewColumn.Caption = oGridDXFieldName Then
                        If oActGridColumn.Visible = False Then
                            If oViewColumn.Caption <> "GUID" And oViewColumn.Caption <> "TL_STATE" And oViewColumn.Caption <> "PROFILE_ID" And oViewColumn.Caption <> "DocID" And
                               oViewColumn.Caption <> "GROUP_COLOR" And oViewColumn.Caption <> "GROUP_TEXT" Then 'And oViewColumn.Caption <> "CONV_YN"
                                Console.WriteLine($"ViewColumn  [{oViewColumn.Caption}] is invisible")
                            Else
                                oViewColumn_exists = True
                            End If
                        Else
                            oViewColumn_exists = True
                        End If
                    End If
                Next
                If oViewColumn_exists = False Then
                    If oViewColumn.Caption = FullFilepatColName And IDB_ACTIVE = False Then
                        LOGGER.Info($"Following ViewColumn no longer exists in the view: [{oViewColumn.Caption}]")
                        Return True
                    End If
                End If
            Next
            For Each oActGridColumn As GridColumn In GridViewWorkflows.Columns
                If oActGridColumn.Caption = "" Then
                    Continue For
                End If
                Dim oGridColumn_exists As Boolean = False
                Dim oGridDXFieldName = oActGridColumn.FieldName
                For Each oViewColumn As DataColumn In DT_CURR_WF_ITEMS.Columns
                    If oViewColumn.Caption = oGridDXFieldName Then
                        oGridColumn_exists = True
                    End If
                Next
                If oGridColumn_exists = False Then
                    LOGGER.Info($"Following GridColumn no longer exists in the View: [{oGridDXFieldName}]")
                    Return True
                End If
            Next
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Unexpected Error in GridLayoutChanged: " & ex.Message)
            Return False
        End Try
    End Function
    Private Function Column_inGridViewLayout(Col2bChecked As String) As Boolean
        Try
            Dim oGridView As New GridView
            Dim oXml As String = GetLayoutName_GridMain()
            oGridView.RestoreLayoutFromXml(oXml, OptionsLayoutBase.FullLayout)
            Dim oViewColumn_exists As Boolean = False
            For Each oActGridColumn As GridColumn In oGridView.Columns
                Dim oGridDXFieldName = oActGridColumn.FieldName
                Dim GridDXColumnEditName = oActGridColumn.ColumnEditName
                Dim GridDXFieldName = oActGridColumn.FieldName
                If Col2bChecked = oGridDXFieldName Then
                    oViewColumn_exists = True
                    Exit For
                End If
            Next
            If oViewColumn_exists = False Then
                LOGGER.Info($"Following ViewColumn is not existing in the view: [{Col2bChecked}]")
                Return Not False
            End If

        Catch ex As Exception
            LOGGER.Info("Unexpected Error in Column_inGridViewLayout: " & ex.Message)
            Return Not False
        End Try
    End Function

    Private Sub NotifyIcon1_MouseDoubleClick(sender As System.Object, e As MouseEventArgs) Handles NotifyIcon1.MouseDoubleClick
        BringMonitor2Front()
    End Sub
    Sub BringMonitor2Front()
        Me.BringToFront()
        Visible = True
    End Sub
    Private Async Sub TimerRefresh_Tick(sender As System.Object, e As EventArgs) Handles TimerRefresh.Tick
        Try
            If TimerRefresh.Enabled = False Then
                Exit Sub
            End If
            If bwBasicData.IsBusy Then
                LOGGER.Info("backGroundWorker BasicData in Action - no Client-Sync")
                bsiMessage.Caption = "bwBasicData is busy - no Refreshing"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Exit Sub
            End If

            TimerRefresh_running = True
            LOGGER.Debug("TimerRefresh_Tick started")
            ' Cancel Refresh if a Validator Form or an Admin Form is opened
            If Application.OpenForms().OfType(Of frmMassValidator).Any() Or
                Application.OpenForms().OfType(Of frmValidator).Any() Or
                Application.OpenForms().OfType(Of frmAdministration).Any() Or
                Application.OpenForms().OfType(Of frmAdmin2).Any() Then
                Exit Sub
            End If

            'bsilastsync.Caption = $"{ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("CaptLastSync")}: " & Now.ToLongTimeString
            bsilastsync.Caption = String.Format(S.Letzte_Synchronisation___0_, Now.ToLongTimeString)

            If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                RefreshHelper.SaveViewInfo()
            End If

            If bwSync.IsBusy Then
                TimerRefresh_running = False
                Exit Sub
            End If

            Try
                'LoadNavBar()

                Dim oStopWatch As New RefreshHelper.SW("Decide_Load")
                Await Decide_Load(False)
                oStopWatch.Done()
                'bwSync.ReportProgress(95)

                If GridControlWorkflows.Visible = True And FormOpenClose = False Then RefreshHelper.LoadViewInfo()
                ' ===== TREELIST COUNTS AKTUALISIEREN =====
                ' Nur ausführen wenn TreeList Knoten mit SQL_QUERY_COUNT vorhanden sind
                Dim oDatasource As DataTable = TryCast(TreeList_Cockpit.DataSource, DataTable)
                If oDatasource IsNot Nothing AndAlso oDatasource.Columns.Contains("SQL_QUERY_COUNT") Then
                    LOGGER.Debug("TimerRefresh_Tick: Refreshing TreeList node counts...")
                    AppendCountsToTreeAsync()
                End If

                Handling_DEBUG_USER()
            Catch ex As Exception
                LOGGER.Error(ex)
            End Try
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
        TimerRefresh_running = False
        'BarEditItem1.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        '' call this method to start your asynchronous Task.
        'bwSync.RunWorkerAsync()


    End Sub

    Private Sub NotifyIcon1_Click(sender As System.Object, e As EventArgs) Handles NotifyIcon1.Click
        BringMonitor2Front()
    End Sub
    ' ========================================
    ' HAUPTLADEMETHODE - Koordiniert den gesamten Ladevorgang
    ' ========================================
    Private Async Function Decide_Load(pIsFormLoad As Boolean, Optional ForceReload As Boolean = False) As Tasks.Task
        Dim oHandle As Object = Nothing
        Dim overlayStartedHere As Boolean = False
        ' Overlay nur anzeigen, wenn die Anwendung aktuell den Fokus hat
        Dim appHasFocus As Boolean = Application.OpenForms().Cast(Of Form)().Any(Function(f) f.ContainsFocus)
        If Not _overlayActive AndAlso appHasFocus Then
            oHandle = SplashScreenManager.ShowOverlayForm(Me)
            _overlayActive = True
            overlayStartedHere = True
        Else
            LOGGER.Debug("Overlay wird nicht angezeigt, da bereits aktiv oder Anwendung keinen Fokus hat.")
        End If
        Dim perfStart As DateTime = DateTime.MinValue
        Dim refreshWasEnabled As Boolean = False

        If LOG_HOTSPOTS Then
            perfStart = DateTime.Now
            LOGGER.Info($"[PERF Decide_Load] START - pIsFormLoad:[{pIsFormLoad}] ForceReload:[{ForceReload}] GRID_LOAD_TYPE:[{GRID_LOAD_TYPE}]")
        End If

        Try
            LOGGER.Debug($"Decide_Load: pIsFormLoad [{pIsFormLoad}] - ForceReload [{ForceReload}] - GRID_LOAD_TYPE [{GRID_LOAD_TYPE}]")

            ' ========== VORBEDINGUNGEN PRÜFEN ==========
            If pIsFormLoad = True Then
                FormShown = False
            End If

            GridIsLoaded = False

            If USER_EXISTS = False Then
                LOGGER.Warn($"USER IS NOT EXISTING - CHECK FNDD_LOGIN_USER_MODULE")
                Exit Function
            End If

            ' ========== TIMER MANAGEMENT ==========
            If TimerRefresh.Enabled Then
                refreshWasEnabled = True
                TimerRefresh.Stop()
            End If

            FRONTEND_ACTION = "DECIDE_LOAD"

            ' ========== UI VORBEREITEN (NUR BEI OVERVIEW) ==========
            Dim loadSuccess As Boolean = False
            If GRID_LOAD_TYPE = "OVERVIEW" Then
                If LOG_HOTSPOTS Then
                    LOGGER.Info("[PERF Decide_Load] ruft LoadOverviewData auf...")
                End If

                Await Task.Yield()

                ' Daten laden
                loadSuccess = Await LoadOverviewData(pIsFormLoad, ForceReload)

            ElseIf GRID_LOAD_TYPE.StartsWith("PROFILE#") Then
                If LOG_HOTSPOTS Then
                    LOGGER.Info("[PERF Decide_Load] ruft LoadProfileData auf...")
                End If

                Await Task.Yield()

                ' Daten laden
                loadSuccess = Await LoadProfileData(ForceReload)
            End If

            If Not loadSuccess Then
                If GRID_LOAD_TYPE <> "OVERVIEW" Then
                    LOGGER.Warn($"LoadProfileData for Profile-ID [{CURRENT_CLICKED_PROFILE_ID}] - Title [{CURRENT_CLICKED_PROFILE_TITLE}] failed or has no Data - exiting Decide_Load")
                Else
                    LOGGER.Warn($"LoadOverviewData failed or has no Data - exiting Decide_Load")
                End If
                Exit Function
            End If
            ' ========== NACHBEARBEITUNG ==========
            ApplyPostLoadSettings()

            GridIsLoaded = True
            ' ========== CAPTION FINAL SICHERSTELLEN ==========
            ' ApplyPostLoadSettings kann durch Spalten-Events den Caption überschreiben,
            ' daher hier nochmals den korrekten Caption setzen
            UpdateGridCaption()

        Catch ex As Exception
            GridIsLoaded = True
            LOGGER.Error(ex)
            LOGGER.Info("Unexpected error in Decide_load: " & ex.Message)
        Finally
            FRONTEND_ACTION = FA_NONE
            If overlayStartedHere Then
                _overlayActive = False
                SplashScreenManager.CloseOverlayForm(oHandle)
            End If
            If refreshWasEnabled Then
                TimerRefresh.Start()
            End If

            If pIsFormLoad = True Then
                FormShown = True
            End If

            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF Decide_Load] GESAMT: {(DateTime.Now - perfStart).TotalMilliseconds}ms")
            End If
        End Try
    End Function
    ' ========================================
    ' OVERVIEW DATEN LADEN - Spezialisiert auf Overview
    ' ========================================
    Private Async Function LoadOverviewData(pFormLoad As Boolean, pForceReload As Boolean) As Task(Of Boolean)
        Dim perfStart As DateTime = DateTime.MinValue
        Dim perfStep As DateTime = DateTime.MinValue
        Dim gridUpdateStarted As Boolean = False
        Dim viewUpdateStarted As Boolean = False

        If LOG_HOTSPOTS Then
            perfStart = DateTime.Now
            perfStep = perfStart
            LOGGER.Info($"[PERF LoadOverviewData] START - pFormLoad:[{pFormLoad}] pForceReload:[{pForceReload}]")
        End If

        Try
            GridControlWorkflows_Visible()
            ' ========== GRID UPDATES VORBEREITEN ==========
            If GridControlWorkflows.Visible Then
                GridControlWorkflows.BeginUpdate()
                gridUpdateStarted = True
                GridViewWorkflows.BeginUpdate()
                viewUpdateStarted = True
            End If

            ' ========== PROFILE VALIDIEREN ==========
            If BASEDATA_DT_VW_PROFILE_USER.Rows.Count = 0 Then
                LOGGER.Info("Attention: No profiles for user: '" & USER_USERNAME & "' configured!", False)
                NO_WORKFLOW_ITEMS = True
                bsiMessage.Caption = "NO PROFILES FOR USER"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                GridControlWorkflows.Visible = False
                Return False
            End If

            If LOG_HOTSPOTS Then
                LOGGER.Debug($"[PERF LoadOverviewData] Load_Profiles_for_User wird aufgerufen...")
            End If

            Load_Profiles_for_User()

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ Load_Profiles_for_User LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] Load_Profiles_for_User: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== SQL VORBEREITEN ==========
            Dim oSQLOverview As String
            Dim isCustomSQL As Boolean = False
            If Not String.IsNullOrWhiteSpace(CUSTOM_OVERVIEW_SQL) Then
                LOGGER.Debug($"[LoadOverviewData] Using CUSTOM_OVERVIEW_SQL from TreeList node [{CUSTOM_OVERVIEW_SQL}]")
                oSQLOverview = CUSTOM_OVERVIEW_SQL
                isCustomSQL = True
            ElseIf Not String.IsNullOrWhiteSpace(_lastUsedOverviewSQL) Then
                LOGGER.Debug($"[LoadOverviewData] CUSTOM_OVERVIEW_SQL is empty - using _lastUsedOverviewSQL (e.g. after ValidatorClosed)")
                oSQLOverview = _lastUsedOverviewSQL
                isCustomSQL = True
            Else
                oSQLOverview = BASEDATA_DT_CONFIG.Rows(0).Item("SQL_PROFILE_MAIN_VIEW")
            End If

            If IsDBNull(oSQLOverview) Then
                LOGGER.Warn("Overview SQL is Null - cannot load overview data")
                NO_WORKFLOW_ITEMS = True
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Return False
            End If

            ' GROUP_TEXT-Prüfung nur für Standard-SQL (nicht für Custom/TreeList-SQL)
            If Not isCustomSQL AndAlso Not oSQLOverview.ToString.Contains("GROUP_TEXT") Then
                LOGGER.Warn("Overview SQL is not properly configured - missing GROUP_TEXT column - might not load overview data")
                LOGGER.Warn($"Overview SQL so far: {oSQLOverview}")
                NO_WORKFLOW_ITEMS = True
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Return False
            End If

            ' SQL-Platzhalter ersetzen
            oSQLOverview = PrepareSQLWithReplacements(oSQLOverview, 0)

            If LOG_HOTSPOTS Then
                Dim rowCount = If(DT_CURR_WF_ITEMS IsNot Nothing, DT_CURR_WF_ITEMS.Rows.Count, 0)
                LOGGER.Info($"[PERF LoadOverviewData] SQL-Abfrage für Workflows startet (aktuelle Rows: {rowCount})...")
            End If

            ' ========== DATEN ABRUFEN ==========
            DT_CURR_WF_ITEMS = Await DatabaseFallback.GetDatatableECMAsync(oSQLOverview)

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                Dim rowCount = If(DT_CURR_WF_ITEMS IsNot Nothing, DT_CURR_WF_ITEMS.Rows.Count, 0)
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ Datenbank-Abfrage für Workflows LANGSAM: {elapsed}ms ({rowCount} Zeilen) (Schwellwert: 4000ms) - SQL prüfen!")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] Datenbank-Abfrage für Workflows: {elapsed}ms ({rowCount} Zeilen)")
                End If
                perfStep = DateTime.Now
            End If

            If IsNothing(DT_CURR_WF_ITEMS) Then
                NO_WORKFLOW_ITEMS = True
                GridControlWorkflows.Visible = False
                Return False
            End If

            LOGGER.Debug($"Datatable CURR_DT_OVERVIEW loaded: {DT_CURR_WF_ITEMS.Rows.Count} rows")

            ' ========== DATEN VERARBEITEN ==========
            NO_WORKFLOW_ITEMS = (DT_CURR_WF_ITEMS.Rows.Count = 0)
            UpdateGridCaption()

            If NO_WORKFLOW_ITEMS Then
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Return False
            End If

            ' ========== ICON-SPALTE VORBEREITEN ==========
            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF LoadOverviewData] Icon-Verarbeitung startet ({DT_CURR_WF_ITEMS.Rows.Count} Zeilen)...")
            End If

            Await Task.Run(Sub() PrepareIconColumn())

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ Icon-Verarbeitung LANGSAM: {elapsed}ms ({DT_CURR_WF_ITEMS.Rows.Count} Zeilen) (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] Icon-Verarbeitung: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== GRID MIT DATEN FÜLLEN ==========
            bindsourcegrid.DataSource = DT_CURR_WF_ITEMS
            GridControlWorkflows.DataSource = bindsourcegrid
            GridControlWorkflows.ForceInitialize()

            Create_View_Caption()

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ Grid-DataSource-Zuweisung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] Grid-DataSource-Zuweisung: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== LAYOUT ANWENDEN ==========
            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF LoadOverviewData] Layout-Anwendung startet...")
            End If

            Await ApplyGridLayout(pForceReload)

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ Layout-Wiederherstellung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] Layout-Wiederherstellung: {elapsed}ms")
                End If
            End If

            Return True

        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("LoadOverviewData - Fehler: " & ex.Message)
            Return False
        Finally
            ' ========== AUFRÄUMEN ==========
            If viewUpdateStarted Then
                GridViewWorkflows.EndUpdate()
            End If
            If gridUpdateStarted Then
                GridControlWorkflows.EndUpdate()
            End If

            If LOG_HOTSPOTS Then
                Dim totalElapsed = (DateTime.Now - perfStart).TotalMilliseconds
                If totalElapsed > 4000 Then
                    LOGGER.Warn($"[PERF LoadOverviewData] ⚠️ GESAMT LANGSAM: {totalElapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LoadOverviewData] GESAMT: {totalElapsed}ms")
                End If
            End If
        End Try
    End Function
    ' ========================================
    ' PROFILE DATEN LADEN - Spezialisiert auf einzelnes Profil
    ' ========================================
    Private Async Function LoadProfileData(ForceReload As Boolean) As Task(Of Boolean)
        Dim gridUpdateStarted As Boolean = False
        Dim viewUpdateStarted As Boolean = False

        Try
            Load_Profiles_for_User()

            Dim expression As String = "GUID = " & CURRENT_CLICKED_PROFILE_ID

            Dim foundRow As DataRow = CURRENT_DT_PROFILES.Select(expression).FirstOrDefault()
            If foundRow Is Nothing Then
                LOGGER.Warn($"LoadProfileData for Profile-ID [{CURRENT_CLICKED_PROFILE_ID}] - Title [{CURRENT_CLICKED_PROFILE_TITLE}] not found - exiting")
                Return False
            End If

            If GridControlWorkflows.Visible Then
                GridControlWorkflows.BeginUpdate()
                gridUpdateStarted = True
                GridViewWorkflows.BeginUpdate()
                viewUpdateStarted = True
            End If

            ' ===== PRIORISIERUNG: TreeList-SQL (COCKPIT_PROFILE_SQL) VOR Datenbank-SQL (SQL_VIEW) =====
            Dim oSQL As String = String.Empty

            ' 1️⃣ ERSTE PRIORITÄT: SQL aus TreeList-Knoten
            If Not String.IsNullOrWhiteSpace(COCKPIT_PROFILE_SQL) Then
                oSQL = COCKPIT_PROFILE_SQL
                LOGGER.Debug($"LoadProfileData: Using COCKPIT_PROFILE_SQL from TreeList node")

                ' 2️⃣ FALLBACK: SQL aus Datenbank-Tabelle (nur wenn TreeList-SQL fehlt)
            Else
                oSQL = foundRow.Item("SQL_VIEW")?.ToString()
                LOGGER.Debug($"LoadProfileData: SQL_VIEW from foundRow = [{oSQL}]")

                ' Prüfen ob SQL leer oder "select 'NONE'" ist
                If String.IsNullOrWhiteSpace(oSQL) OrElse oSQL.Trim().ToUpper() = "SELECT 'NONE'" Then
                    LOGGER.Warn($"⚠️ LoadProfileData: Both COCKPIT_PROFILE_SQL and SQL_VIEW are empty/invalid for Profile-ID [{CURRENT_CLICKED_PROFILE_ID}]")
                    NO_WORKFLOW_ITEMS = True
                    GridControlWorkflows.Visible = False
                    bindsourcegrid.DataSource = Nothing
                    GridControlWorkflows.DataSource = Nothing
                    Return False
                End If
                LOGGER.Debug($"LoadProfileData: COCKPIT_PROFILE_SQL empty - using SQL_VIEW from database as fallback")
            End If

            ' ===== SQL NACH allen Ersetzungen loggen =====
            LOGGER.Debug($"LoadProfileData: Final SQL BEFORE PrepareSQLWithReplacements: [{oSQL}]")
            oSQL = PrepareSQLWithReplacements(oSQL, CURRENT_CLICKED_PROFILE_ID)
            LOGGER.Debug($"LoadProfileData: Final SQL AFTER PrepareSQLWithReplacements: [{oSQL}]")

            ' ===== DATEN ABRUFEN =====
            DT_CURR_WF_ITEMS = Await DatabaseFallback.GetDatatableECMAsync(oSQL)

            If IsNothing(DT_CURR_WF_ITEMS) Then
                LOGGER.Warn($"LoadProfileData for Profile-ID [{CURRENT_CLICKED_PROFILE_ID}] - Title [{CURRENT_CLICKED_PROFILE_TITLE}] failed - exiting")
                Return False
            End If

            ' ===== DATEN VERARBEITEN =====
            NO_WORKFLOW_ITEMS = (DT_CURR_WF_ITEMS.Rows.Count = 0)
            UpdateGridCaption()

            If NO_WORKFLOW_ITEMS Then
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                LOGGER.Info("Keine Workflow-Items für Profil: " & CURRENT_CLICKED_PROFILE_TITLE)
                Return False
            End If

            GridControlWorkflows_Visible()

            ' ===== BASIC VIEW ERSTELLEN =====
            Await CreateBasicViewForProfile()
            LOGGER.Debug("Basic View für Profil erstellt: " & CURRENT_CLICKED_PROFILE_TITLE)
            Return True

        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("LoadProfileData - Error: " & ex.Message)
            Return False
        Finally
            If viewUpdateStarted Then
                GridViewWorkflows.EndUpdate()
            End If
            If gridUpdateStarted Then
                GridControlWorkflows.EndUpdate()
            End If
        End Try
    End Function

    ' ========================================
    ' HILFSMETHODEN - Extrahierte Logik für Wiederverwendung
    ' ========================================

    Private Function PrepareSQLWithReplacements(oSQL As String, oProfileID As Integer) As String
        oSQL = clsPatterns.ReplaceInternalValues(oSQL)
        oSQL = clsPatterns.ReplaceUserValues(oSQL)
        LOGGER.Debug("PrepareSQLWithReplacements - Original SQL: " & oSQL)
        oSQL = oSQL.Replace("@USERNAME", USER_USERNAME)
        oSQL = oSQL.Replace("@MACHINE_NAME", System.Environment.MachineName)
        oSQL = oSQL.Replace("@DATE", Now.ToShortDateString)
        ' ===== ZUSÄTZLICHE PLATZHALTER-FORMATE FÜR USER_ID =====
        oSQL = oSQL.Replace("{#USER#USER_ID}", USER_ID)
        oSQL = oSQL.Replace("#USER#USER_ID", USER_ID)
        oSQL = oSQL.Replace("@USER_ID", USER_ID)
        LOGGER.Debug("PrepareSQLWithReplacements - SQL after replacements: " & oSQL)
        If oProfileID = 0 Then
            If GRID_LOAD_TYPE = "OVERVIEW" Then
                LOGGER.Debug("PrepareSQLWithReplacements called with oProfileID = 0 in OVERVIEW context")
            Else
                LOGGER.Warn("PrepareSQLWithReplacements called with oProfileID = 0, using CURRENT_CLICKED_PROFILE_ID instead")
            End If
            oProfileID = CURRENT_CLICKED_PROFILE_ID
        Else
            LOGGER.Debug($"PrepareSQLWithReplacements called with oProfileID = {oProfileID}")
        End If
        oSQL = oSQL.Replace("@PROFILE_ID", oProfileID)
        oSQL = oSQL.Replace("@PROFIL_ID", oProfileID)
        Return oSQL
    End Function

    Private Sub PrepareIconColumn()
        ' Prüfen, ob TL_STATE-Spalte vorhanden ist
        Dim hasTLStateColumn As Boolean = False
        If DT_CURR_WF_ITEMS IsNot Nothing Then
            hasTLStateColumn = DT_CURR_WF_ITEMS.Columns.Contains("TL_STATE")
        End If

        If TL_ICON = True AndAlso DT_CURR_WF_ITEMS IsNot Nothing AndAlso DT_CURR_WF_ITEMS.Columns.Contains("ICON") = False Then
            Dim columnStateIcon As New DataColumn() With {
            .DataType = GetType(Image),
            .ColumnName = "ICON",
            .Caption = ""
        }
            DT_CURR_WF_ITEMS.Columns.Add(columnStateIcon)
        End If

        RedDocuments = 0
        YellowDocuments = 0
        GreenDocuments = 0

        If TL_ICON = True AndAlso hasTLStateColumn AndAlso DT_CURR_WF_ITEMS IsNot Nothing Then
            For Each row As DataRow In DT_CURR_WF_ITEMS.Rows
                Try
                    Dim State As Integer = CInt(row.Item("TL_STATE"))
                    Select Case State
                        Case 1
                            RedDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_red
                        Case 2
                            YellowDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_orange
                        Case 3
                            GreenDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_green
                    End Select
                Catch ex As Exception
                    LOGGER.Warn($"Could not set ICON value: {ex.Message}")
                End Try

            Next
        ElseIf TL_ICON = True AndAlso Not hasTLStateColumn Then
            LOGGER.Warn("⚠️ TL_ICON is enabled but TL_STATE column is missing in DT_CURR_WF_ITEMS")
        End If
    End Sub

    Private Async Function ApplyGridLayout(pForceReload As Boolean) As Tasks.Task
        Dim oColNotPartofLayout As Boolean = False

        If pForceReload = True And (GridLayoutChanged() = True Or oColNotPartofLayout = True) Then
            LOGGER.Debug("Now GridLayout_Reset..")
            Await GridLayout_Reset(False)
        Else
            RestoreLayout()
        End If

        If pForceReload = True And (GridLayoutChanged() = True Or oColNotPartofLayout = True) Then
            Create_GroupBy_Parts()
        End If

        ' Icon-Spalte konfigurieren
        If TL_ICON = True Then
            Try
                GridViewWorkflows.Columns.Item("ICON").MaxWidth = 24
                GridViewWorkflows.Columns.Item("ICON").MinWidth = 24
                GridViewWorkflows.Columns.Item("ICON").AppearanceCell.BackColor = Color.White
                GridViewWorkflows.Columns.Item("ICON").Fixed = DevExpress.XtraGrid.Columns.FixedStyle.Left
            Catch ex As Exception
            End Try
        End If

        If GridViewWorkflows.Columns.Count <= 5 Then
            LOGGER.Info("GridViewWorkflows.Columns.Count <= 5 - Reset_Gridlayout will be forced...", False)
            Await Reset_GridLayout(False)
        Else
            RestoreLayout()
        End If

        COLUMNS_INVISIBLE()

        ' Spaltenformatierung anwenden
        ApplyColumnFormatting()
    End Function

    Private Sub ApplyColumnFormatting()
        Try
            For Each oColumn As DevExpress.XtraGrid.Columns.GridColumn In GridViewWorkflows.Columns
                For Each oRow As DataRow In BASEDATA_TBDD_COLUMNS_FORMAT.Rows
                    Dim colName = oRow("COLUMN_TITLE").ToString()

                    If oColumn.FieldName = colName Then
                        Dim oSollFormatType = oRow("TYPE2FORMAT").ToString()

                        If oSollFormatType = "DateTime" Then
                            If oColumn.ColumnType <> GetType(DateTime) Then
                                oColumn.DisplayFormat.FormatType = DevExpress.Utils.FormatType.DateTime
                            End If

                            If oColumn.ColumnType = GetType(DateTime) And oColumn.DisplayFormat.FormatString <> "dd.MM.yyyy HH:mm:ss" Then
                                oColumn.DisplayFormat.FormatString = "dd.MM.yyyy HH:mm:ss"
                            End If
                        ElseIf oSollFormatType = "Numeric" Then
                            If oColumn.ColumnType <> GetType(Int32) Then
                                oColumn.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Numeric
                            End If
                        End If
                    End If
                Next
            Next
        Catch ex As Exception
            LOGGER.Warn("⚠️ Fehler beim Anwenden der Formatierung aus TBDD_COLUMNS_FORMAT: " & ex.Message)
        End Try
    End Sub

    Private Async Function CreateBasicViewForProfile() As Task
        ' ===== GRID DATASOURCE ZURÜCKSETZEN =====
        GridControlWorkflows.DataSource = Nothing
        Try
            GridViewWorkflows.Columns.Clear()
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Warn("⚠️ Could not clear GridViewWorkflows.Columns")
        End Try

        ' ===== ICON-SPALTE VORBEREITEN =====
        Await Task.Run(Sub() PrepareIconColumn())

        ' ===== DATASOURCE ZUWEISEN =====
        bindsourcegrid.DataSource = DT_CURR_WF_ITEMS
        GridControlWorkflows.DataSource = bindsourcegrid

        ' ✅ KRITISCH: Grid zwingen, Columns zu erstellen BEVOR RestoreLayout
        GridControlWorkflows.ForceInitialize()

        ' ✅ Wenn kein gespeichertes Layout existiert → Columns manuell populieren
        Dim oXmlPath As String = GetLayoutName_GridMain()
        If Not System.IO.File.Exists(oXmlPath) Then
            LOGGER.Debug($"CreateBasicViewForProfile: No layout file found at [{oXmlPath}] - populating columns")
            GridViewWorkflows.PopulateColumns()
        End If

        ' ===== LAYOUT WIEDERHERSTELLEN =====
        RestoreLayout()
        COLUMNS_INVISIBLE()

        ' ===== GRUPPIERUNG FÜR PROFIL-ANSICHT ENTFERNEN =====
        If GridViewWorkflows.GroupCount > 0 Then
            LOGGER.Debug($"CreateBasicViewForProfile: Clearing [{GridViewWorkflows.GroupCount}] group(s) from restored layout for profile view")
            GridViewWorkflows.ClearGrouping()
        End If

        ' ===== ICON-SPALTE KONFIGURIEREN =====
        If TL_ICON = True Then
            Try
                If GridViewWorkflows.Columns.ColumnByFieldName("ICON") IsNot Nothing Then
                    GridViewWorkflows.Columns.Item("ICON").MaxWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").MinWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").AppearanceCell.BackColor = Color.White
                    GridViewWorkflows.Columns.Item("ICON").Fixed = FixedStyle.Left
                    GridViewWorkflows.Columns.Item("ICON").VisibleIndex = 0 ' ✅ Ganz links
                End If
            Catch ex As Exception
                LOGGER.Warn($"Could not configure ICON column: {ex.Message}")
            End Try
        End If

        ' ✅ DEBUG: Spalten-Info loggen
        LOGGER.Debug($"CreateBasicViewForProfile: Grid has [{GridViewWorkflows.Columns.Count}] columns, DataSource has [{DT_CURR_WF_ITEMS.Rows.Count}] rows")
    End Function

    Private Sub ApplyPostLoadSettings()
        If SHOW_MASS_VALIDATOR = False Then
            GridViewWorkflows.OptionsSelection.MultiSelect = False
            GridViewWorkflows.OptionsSelection.MultiSelectMode = GridMultiSelectMode.RowSelect
            BarButtonItemMassValidation.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        Else
            BarButtonItemMassValidation.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
            GridViewWorkflows.OptionsSelection.MultiSelect = True
            GridViewWorkflows.OptionsSelection.MultiSelectMode = GridMultiSelectMode.CheckBoxRowSelect
        End If

        If GridViewWorkflows.OptionsView.ShowAutoFilterRow = True Then
            BarCheckItemAutofilter.Checked = True
        End If
        If GridViewWorkflows.OptionsFind.AlwaysVisible Then
            BarCheckItemShowSearch.Checked = True
        End If

        COLUMNS_INVISIBLE()
    End Sub
    Private Sub ToolStripButton2_Click_2(sender As Object, e As EventArgs)
        frmAdminPasswort.ShowDialog()
    End Sub

    Public Sub New()


        Dim splash As New frmSplash()
        Try
            splash.ShowDialog()
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info($"Error in Splash: {ex.Message}")
        End Try
        ' LookAndFeel ZUERST global setzen
        ConfigureGlobalLookAndFeel()
        Try
            If USER_LANGUAGE <> "" Then
                Dim cultureInfo As New System.Globalization.CultureInfo(USER_LANGUAGE)
                cultureInfo.DateTimeFormat.ShortDatePattern = USER_DATE_FORMAT
                Thread.CurrentThread.CurrentCulture = cultureInfo
                Thread.CurrentThread.CurrentUICulture = cultureInfo
                CultureInfo.DefaultThreadCurrentCulture = cultureInfo
                CultureInfo.DefaultThreadCurrentUICulture = cultureInfo
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
        Try
            InitializeComponent()
            FormHelper = New FormHelper(LOGCONFIG, Me)
            ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info($"Error in InitializeComponent: {ex.Message}")
        End Try
    End Sub


    Private Sub TimerReminder_Tick(sender As Object, e As EventArgs) Handles TimerReminder.Tick
        Try

            If Application.OpenForms().OfType(Of frmValidator).Any Then
                Exit Sub
            End If

            If DT_CURR_WF_ITEMS.Rows.Count > 0 And POPUP_REMINDER_ACTIVE = True Then
                Dim oMessage As String = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("App.ReminderPipeline")
                NotifyIcon1.ShowBalloonTip(30000, $"Reminder {ADDITIONAL_TITLE}", oMessage, ToolTipIcon.Info)
            End If
        Catch ex As Exception
            LOGGER.Warn($"Unexpected error in TimerReminderTick:  {ex.Message}")
        End Try

    End Sub
    Public Function GetEnvironment() As Environment
        Return New Environment With {
            .Database = DatabaseECM,
            .DatabaseIDB = DatabaseIDB,
            .Service = EDMIService,
            .User = User
        }
    End Function

    Sub Load_Profil_from_Grid(pProfilID As Integer)
        Dim perfStart As DateTime = DateTime.MinValue
        Dim useWaitCursorApplied As Boolean = False
        Dim previousMessage As String = bsiMessage.Caption
        Dim messageApplied As Boolean = False
        Dim oHandle As Object = Nothing
        Dim overlayStartedHere As Boolean = False

        If LOG_HOTSPOTS Then
            perfStart = DateTime.Now
            LOGGER.Info($"[PERF  Load_Profil_from_Grid START - pProfilID:[{pProfilID}]")
        End If

        Try
            CURRENT_ProfilGUID = pProfilID
            WM_AHWF_docPath = String.Empty

            ' ========== OVERLAY ANZEIGEN ==========
            If Not _overlayActive Then
                oHandle = SplashScreenManager.ShowOverlayForm(Me)
                _overlayActive = True
                overlayStartedHere = True
            End If


            ' ========== UI-VORBEREITUNG ==========
            Me.UseWaitCursor = True
            useWaitCursorApplied = True

            bsiMessage.Caption = "Loading profile..."
            messageApplied = True

            If Not Application.OpenForms().OfType(Of frmValidator).Any Then
                ' ========== TIMER MANAGEMENT ==========
                If TimerRefresh.Enabled Then
                    TimerRefresh.Enabled = False
                End If

                ' ========== FORM DESIGN CHECK ==========
                If CHANGES_FORM_DESIGN = True Then
                    LoadCURRENT_DT_PROFILES()
                    LoadVWPM_CONTROL_INDEX()
                    CHANGES_FORM_DESIGN = False
                End If

                ' ========== PROFILE DATA PREPARATION ==========
                Dim oExpression = $"GUID = {CURRENT_ProfilGUID}"
                CURRENT_DT_PROFILE = Nothing
                CURRENT_DT_PROFILE = CURRENT_DT_PROFILES.Clone
                CURRENT_DT_PROFILES.Select(oExpression).CopyToDataTable(CURRENT_DT_PROFILE, LoadOption.PreserveChanges)

                If CURRENT_DT_PROFILE.Rows.Count = 1 Then
                    CURRENT_ProfilName = CURRENT_DT_PROFILE.Rows(0).Item("NAME")
                    CURRENT_WMObjecttype = CURRENT_DT_PROFILE.Rows(0).Item("WD_OBJECTTYPE")
                    PROFILE_SHOW_DOCUMENT = Convert.ToBoolean(CURRENT_DT_PROFILE.Rows(0).Item("SHOW_DOCUMENT"))
                    ActiveWorkflowType = 1
                Else
                    MsgBox("Could not get a Profile - Check Your log!", MsgBoxStyle.Exclamation, ADDITIONAL_TITLE)
                    Exit Sub
                End If
                LOGGER.Debug($"Load_Profil_from_Grid: Loaded profile [{CURRENT_ProfilName}] with GUID [{CURRENT_ProfilGUID}]")
                LOGGER.Debug($"Load_Profil_from_Grid: PROFILE_SHOW_DOCUMENT = [{PROFILE_SHOW_DOCUMENT}]")
                ' ========== SEARCH DOCUMENTS PREPARATION ==========
                oExpression = $"PROFILE_ID = {CURRENT_ProfilGUID} "
                DT_FILTERED_PROFILE_SEARCHES_DOC = Nothing
                Dim rows = BASEDATA_DT_PROFILES_SEARCHES_DOC.Select(oExpression, "TAB_INDEX")
                If rows.Length > 0 Then
                    DT_FILTERED_PROFILE_SEARCHES_DOC = rows.CopyToDataTable()
                Else
                    DT_FILTERED_PROFILE_SEARCHES_DOC = BASEDATA_DT_PROFILES_SEARCHES_DOC.Clone()
                End If

                ' ========== SEARCH SQL PREPARATION ==========
                DT_FILTERED_PROFILE_SEARCHES_DATA = Nothing
                rows = BASEDATA_DT_PROFILES_SEARCHES_DATA.Select(oExpression, "TAB_INDEX")
                If rows.Length > 0 Then
                    DT_FILTERED_PROFILE_SEARCHES_DATA = rows.CopyToDataTable()
                Else
                    DT_FILTERED_PROFILE_SEARCHES_DATA = BASEDATA_DT_PROFILES_SEARCHES_DATA.Clone()
                End If

                ' ========== VALIDATOR-FORM ÖFFNEN ==========
                Try
                    If LOG_HOTSPOTS Then
                        LOGGER.Info("[PERF  Load_Profil_from_Grid öffnet frmValidator...")
                    End If

                    Dim oEnvironment = GetEnvironment()
                    _FormValidator = New frmValidator(oEnvironment)
                    AddHandler _FormValidator.FormClosed, AddressOf ValidatorClosed
                    _FormValidator.Show()
                Catch ex As Exception
                    LOGGER.Warn($"Error opening Form frmValidator [{ex.Message}]")
                    If Not IsNothing(ex.InnerException) Then
                        LOGGER.Warn($"ex.InnerException.Message [{ex.InnerException.Message}]")
                        LOGGER.Warn($"ex.InnerException.Source [{ex.InnerException.Source}]")
                        LOGGER.Error(ex.InnerException)
                    End If

                    MsgBox(ex.Message, MsgBoxStyle.Critical, ADDITIONAL_TITLE)
                End Try

                ' ========== ROW AUS ÜBERSICHT ENTFERNEN ==========
                Try
                    Dim iterateIndex As Integer = 0
                    Dim oNewDataTable As DataTable = DT_CURR_WF_ITEMS.Copy
                    For Each row As DataRow In oNewDataTable.Rows
                        If row("GUID") = CURRENT_DOC_GUID Then
                            DT_CURR_WF_ITEMS.Rows.RemoveAt(iterateIndex)
                            Exit For
                        Else
                            iterateIndex += 1
                        End If
                    Next
                Catch ex As Exception
                    LOGGER.Warn("⚠️ Unexpected Error In Removing Row after Loading Record from Grid: " & ex.Message)
                End Try

                ' ========== TIMER RE-ENABLE ==========
                TimerRefresh.Enabled = True
            Else
                LOGGER.Debug("Validator is already open...")
                FormHelper.ShowInfoMessage(S.Es_existiert_bereits_ein_aktiver_Workflow_, omsgTitleAttention)
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox("Unexpected error in Load_Profil_from_Grid: " & ex.Message & vbNewLine & ADDITIONAL_TITLE & " will try to reload the overview - Please try again!", MsgBoxStyle.Information, ADDITIONAL_TITLE)
            Dim task = Decide_Load(False, True)
        Finally
            ' ========== OVERLAY SCHLIESSEN (FALLBACK) ==========
            If overlayStartedHere AndAlso _overlayActive Then
                SplashScreenManager.CloseOverlayForm(oHandle)
                LOGGER.Debug("Overlay closed in Load_Profil_from_Grid")
                _overlayActive = False
            End If

            ' ========== UI AUFRÄUMEN ==========
            If useWaitCursorApplied Then
                Me.UseWaitCursor = False
            End If

            If messageApplied AndAlso bsiMessage.Caption = "Loading profile..." Then
                bsiMessage.Caption = previousMessage
            End If

            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF  Load_Profil_from_Grid GESAMT: {(DateTime.Now - perfStart).TotalMilliseconds}ms")
            End If
        End Try
    End Sub
    Private Async Function Item_Scope(startedFrom As String) As Task
        ' ========== FRÜHE VALIDIERUNGEN (VOR UI-ÄNDERUNGEN) ==========
        If Application.OpenForms().OfType(Of frmValidator).Any Then
            bsiMessage.Caption = S.Es_existiert_bereits_ein_aktiver_Workflow_
            LOGGER.Info("Item Scope - Workflow open! - Exit")
            bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
            bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
            Exit Function
        End If

        Dim perfStart As DateTime = DateTime.MinValue
        Dim useWaitCursorApplied As Boolean = False
        Dim previousMessage As String = bsiMessage.Caption
        Dim messageApplied As Boolean = False

        If LOG_HOTSPOTS Then
            perfStart = DateTime.Now
            LOGGER.Info($"[PERF Item_Scope] START - startedFrom:[{startedFrom}]")
        End If

        Try
            LOGGER.Info("Starting Profile Loading")

            ' ========== UI-VORBEREITUNG ==========
            Me.UseWaitCursor = True
            useWaitCursorApplied = True
            bsiMessage.Caption = "Processing selection..."
            messageApplied = True

            ' ========== HITINFO NUR EINMAL BERECHNEN ==========
            Dim hitInfo As GridHitInfo = GridViewWorkflows.CalcHitInfo(GridCursorLocation)

            ' ========== STARTEDROM NORMALISIEREN ==========
            If startedFrom = "DOUBLECLICK" Then
                startedFrom = If(hitInfo.InGroupRow, "CMGROUP", "CMROW")
                LOGGER.Debug($"User clicked {If(hitInfo.InGroupRow, "group", "normal")} row.")
            End If

            ' ========== PROFIL-ID ERMITTELN (OPTIMIERT) ==========
            Dim oHitProfilID As Object = Nothing
            If hitInfo.InGroupRow Then
                oHitProfilID = GridViewWorkflows.GetRowCellValue(
                GridViewWorkflows.GetDataRowHandleByGroupRowHandle(hitInfo.RowHandle),
                GridViewWorkflows.Columns("PROFILE_ID"))
            ElseIf hitInfo.InDataRow Then
                oHitProfilID = GridViewWorkflows.GetRowCellValue(
                GridViewWorkflows.GetDataRowHandleByGroupRowHandle(
                    GridViewWorkflows.GetParentRowHandle(hitInfo.RowHandle)),
                GridViewWorkflows.Columns("PROFILE_ID"))
            End If

            LOGGER.Debug("Clicked ProfileId: [{0}], Started From: [{1}]", oHitProfilID, startedFrom)

            ' ========== PROFIL-ID VALIDIERUNG UND UPDATE ==========
            If oHitProfilID IsNot Nothing AndAlso IsNumeric(oHitProfilID) AndAlso CInt(oHitProfilID) > 0 Then
                If oHitProfilID <> CURRENT_CLICKED_PROFILE_ID Then
                    LOGGER.Debug($"Item_Scope: oHitProfilID {oHitProfilID} <> CURRENT_CLICKED_PROFILE_ID {CURRENT_CLICKED_PROFILE_ID}")
                    CURRENT_CLICKED_PROFILE_ID = oHitProfilID
                End If
            End If
            ' ========== GRUPPE VERARBEITEN (MIT KORREKTER GRUPPEN-ERMITTLUNG) ==========
            If startedFrom = "CMGROUP" Then
                LOGGER.Debug("Loading Child DocIds from focused expanded group..")
                Dim oIds As New List(Of Integer)
                Dim oGroupRowHandle As Integer

                ' KRITISCH: Den RICHTIGEN Gruppen-Handle ermitteln
                If GridViewWorkflows.IsGroupRow(hitInfo.RowHandle) Then
                    ' User hat direkt auf die Gruppen-Zeile geklickt
                    oGroupRowHandle = hitInfo.RowHandle
                    LOGGER.Debug($"User clicked directly on group row, handle: {oGroupRowHandle}")
                Else
                    ' User hat auf eine Daten-Zeile INNERHALB einer Gruppe geklickt
                    ' → Parent-Gruppe ermitteln
                    oGroupRowHandle = GridViewWorkflows.GetParentRowHandle(hitInfo.RowHandle)
                    LOGGER.Debug($"User clicked on data row {hitInfo.RowHandle}, parent group handle: {oGroupRowHandle}")

                    If Not GridViewWorkflows.IsGroupRow(oGroupRowHandle) Then
                        LOGGER.Warn($"⚠️ Parent handle {oGroupRowHandle} is not a group row!")
                        FormHelper.ShowWarningMessage("Bitte klicken Sie direkt auf die Gruppenzeile!", omsgTitleAttention)
                        Exit Function
                    End If
                End If

                ' Spalten-Objekt VOR der Schleife holen
                Dim docIdColumn As GridColumn = GridViewWorkflows.Columns.ColumnByFieldName("DocID")
                If docIdColumn Is Nothing Then
                    docIdColumn = GridViewWorkflows.Columns.ColumnByFieldName("DOCID")
                End If
                If docIdColumn Is Nothing Then
                    LOGGER.Error("⚠️ Column 'DocID' not found in GridView!")

                    ' DEBUG: Alle verfügbaren Spalten ausgeben
                    LOGGER.Debug("=== Available Columns ===")
                    For Each col As GridColumn In GridViewWorkflows.Columns
                        LOGGER.Debug($"  {col.FieldName} (Caption: {col.Caption})")
                    Next
                    LOGGER.Debug("=== END Available Columns ===")

                    FormHelper.ShowInfoMessage("Column 'DocID' not found!", omsgTitleWarning)
                    Exit Function
                End If

                ' JETZT GetChildRowCount auf der RICHTIGEN Gruppe
                Dim oChildRowCount = GridViewWorkflows.GetChildRowCount(oGroupRowHandle)
                LOGGER.Debug($"Group handle {oGroupRowHandle} has {oChildRowCount} total child rows")

                ' WICHTIG: Wenn 0 Kinder → Gruppe ist zugeklappt oder leer
                If oChildRowCount = 0 Then
                    ' Versuche die Gruppe aufzuklappen
                    LOGGER.Debug($"Expanding group at handle {oGroupRowHandle}...")
                    GridViewWorkflows.ExpandGroupRow(oGroupRowHandle)

                    ' UI-Thread Zeit geben
                    Application.DoEvents()

                    ' Erneut prüfen
                    oChildRowCount = GridViewWorkflows.GetChildRowCount(oGroupRowHandle)
                    LOGGER.Debug($"After expanding: {oChildRowCount} child rows")

                    If oChildRowCount = 0 Then
                        LOGGER.Warn($"⚠️ Group has 0 children even after expanding")
                        Dim omsg = "Die Gruppe ist leer!"
                        FormHelper.ShowWarningMessage(omsg, omsgTitleAttention)
                        Exit Function
                    End If
                End If

                ' JETZT sollten Kinder vorhanden sein
                For childIndex = 0 To oChildRowCount - 1
                    Dim oChildRowHandle = GridViewWorkflows.GetChildRowHandle(oGroupRowHandle, childIndex)

                    ' WICHTIG: Nur Daten-Rows verarbeiten, KEINE Gruppen
                    If Not GridViewWorkflows.IsDataRow(oChildRowHandle) Then
                        LOGGER.Debug($"Skipping non-data row at child index {childIndex} (Handle: {oChildRowHandle})")
                        Continue For
                    End If

                    ' DocId auslesen - MIT COLUMN-OBJEKT
                    Try
                        Dim oDocId = GridViewWorkflows.GetRowCellValue(oChildRowHandle, docIdColumn)

                        If oDocId IsNot Nothing AndAlso IsNumeric(oDocId) Then
                            oIds.Add(CInt(oDocId))
                            LOGGER.Debug($"Added DocId: {oDocId} from child index {childIndex} (Handle: {oChildRowHandle})")
                        Else
                            LOGGER.Warn($"⚠️ DocId is Nothing/Invalid at child index {childIndex}, Handle: {oChildRowHandle}")
                        End If
                    Catch ex As Exception
                        LOGGER.Error($"Error reading DocId at child index {childIndex}: {ex.Message}")
                    End Try
                Next

                LOGGER.Debug($"[{oIds.Count}] DocIds collected from focused group")

                If oIds.Count = 0 Then
                    Dim omsg = String.Format(S.System_konnte_die_Profilworkflows_nicht_auswerten_, vbNewLine)
                    FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                    Exit Function
                End If


                If oIds.Count > 1000 Then
                    Dim omsg = String.Format("You chose more than 1000 Workflows. Please select fewer items.", vbNewLine)
                    FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                    Exit Function
                End If

                ' ========== DB-OPERATIONEN ==========
                LOGGER.Debug("Cleaning up queued DocIds..")
                Dim oDelete = $"DELETE FROM TBPM_VALIDATION_PROFILE_GROUP_USER WHERE UserID = {USER_ID}"

                If DatabaseFallback.ExecuteNonQueryECM(oDelete) = True Then
                    LOGGER.Debug("Adding {0} queued DocIds..", oIds.Count)

                    Dim oInsertBatch As New System.Text.StringBuilder()
                    oInsertBatch.AppendLine("INSERT INTO TBPM_VALIDATION_PROFILE_GROUP_USER ([PROFIL_ID],[DocID],[UserID],[ADDED_WHO]) VALUES")

                    For i As Integer = 0 To oIds.Count - 1
                        If i > 0 Then oInsertBatch.Append(",")
                        oInsertBatch.AppendLine($"({CURRENT_CLICKED_PROFILE_ID},{oIds(i)},{USER_ID},'{USER_USERNAME}')")
                    Next

                    ' WICHTIG: Debug-Logging des Batch-Inserts
                    LOGGER.Debug(String.Format("Batch-Insert {0}", oInsertBatch.ToString))

                    DatabaseFallback.ExecuteNonQueryECM(oInsertBatch.ToString())
                End If
            End If

            CURRENT_JUMP_DOC_GUID = 0

            ' ========== HITINFO VALIDIERUNG ==========
            If hitInfo Is Nothing Then
                bsiMessage.Caption = "Could not specify hitinfo via click event (CalcHitInfo)"
                LOGGER.Info("Could not specify hitinfo via click event (CalcHitInfo)")
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Exit Function
            End If

            ' ========== PROFIL-TITEL ERMITTELN ==========
            Dim PROFIL_TITLE As String = String.Empty

            If hitInfo.InGroupRow Then
                GridViewItem_Clicked = "GROUP"
                startedFrom = "CMGROUP"
                LOGGER.Debug($"Item_Scope: InGroupRow")

                Dim groupRowText = GridViewWorkflows.GetGroupRowDisplayText(hitInfo.RowHandle)
                LOGGER.Debug($"Item_Scope: groupRowText {groupRowText}")

                If GRID_LOAD_TYPE = "OVERVIEW" Then
                    groupRowText = groupRowText.Replace("Profile (Fixed): ", "").Trim()
                    Dim splitIndex = groupRowText.IndexOf("|")
                    PROFIL_TITLE = If(splitIndex >= 0, groupRowText.Substring(0, splitIndex).Trim(), groupRowText)
                End If

            ElseIf hitInfo.InDataRow Then
                GridViewItem_Clicked = "ROW"
                LOGGER.Debug($"Item_Scope: InDataRow")

                If GRID_LOAD_TYPE = "OVERVIEW" Then
                    LOGGER.Debug($"Item_Scope: GRID_LOAD_TYPE = OVERVIEW")
                    Dim groupRowText = GridViewWorkflows.GetGroupRowDisplayText(
                    GridViewWorkflows.GetParentRowHandle(hitInfo.RowHandle))
                    LOGGER.Debug($"Item_Scope: OVERVIEWgroupRowText {groupRowText}")

                    groupRowText = groupRowText.Replace("Profile (Fixed): ", "").Trim()
                    Dim splitIndex = groupRowText.IndexOf("|")
                    PROFIL_TITLE = If(splitIndex >= 0, groupRowText.Substring(0, splitIndex).Trim(), groupRowText)
                Else
                    LOGGER.Debug($"Item_Scope: NOT GRID_LOAD_TYPE = OVERVIEW")
                    If Not IsNothing(CURRENT_CLICKED_PROFILE_ID) AndAlso CURRENT_CLICKED_PROFILE_ID <> 0 Then
                        LOGGER.Debug($"Item_Scope: CURRENT_CLICKED_PROFILE_ID [{CURRENT_CLICKED_PROFILE_ID}]")
                        oHitProfilID = CURRENT_CLICKED_PROFILE_ID
                    Else
                        LOGGER.Warn("⚠️ ItemScope: CURRENT_CLICKED_PROFILE_ID is nothing or 0!!!")
                        Exit Function
                    End If
                End If
            Else
                Exit Function
            End If

            ' ========== PROFIL-TITEL SETZEN ==========
            If Not String.IsNullOrEmpty(PROFIL_TITLE) Then
                CURRENT_CLICKED_PROFILE_TITLE = PROFIL_TITLE.Replace("GROUP_TEXT:", "")
            End If

            ' ========== PROFIL LADEN ==========
            If Not IsNothing(CURRENT_CLICKED_PROFILE_ID) AndAlso IsNumeric(CURRENT_CLICKED_PROFILE_ID) Then
                LOGGER.Debug($"Item_Scope: Valid PROFIL_ID")

                If hitInfo.InGroupRow OrElse (startedFrom = "CMGROUP" AndAlso hitInfo.InDataRow) Then
                    ' GRUPPE: Workflow ohne spezifisches Dokument
                    CURRENT_JUMP_DOC_GUID = 0
                    CURRENT_DOC_GUID = 0
                    CURRENT_DOC_ID = 0
                    CURRENT_ProfilGUID = CURRENT_CLICKED_PROFILE_ID
                    LOGGER.Debug($"Item_Scope: hitInfo.InGroupRow...CURRENT_CLICKED_PROFILE_ID [{CURRENT_CLICKED_PROFILE_ID}]")
                    Load_Profil_from_Grid(CURRENT_CLICKED_PROFILE_ID)

                ElseIf hitInfo.InDataRow Then
                    ' EINZELNE ZEILE: Mit spezifischem Dokument
                    LOGGER.Debug($"Item_Scope: hitInfo.InDataRow...")

                    ' ========== DOKUMENT-DATEN ABRUFEN ==========
                    Dim oFocusedDocGUID = GridViewWorkflows.GetFocusedRowCellValue(GridViewWorkflows.Columns("GUID"))
                    Dim oFocusedDocID = GridViewWorkflows.GetFocusedRowCellValue(GridViewWorkflows.Columns("DocID"))

                    ' Validierungen
                    If oFocusedDocID Is Nothing Then
                        LOGGER.Warn("⚠️ In hitInfo.InDataRow: DocID is nothing!!!")
                        bsiMessage.Caption = "Error getting DocID!"
                        bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
                        bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                        Exit Function
                    End If

                    If oFocusedDocGUID Is Nothing Then
                        LOGGER.Warn("⚠️ In hitInfo.InDataRow: oFocusedDocGUID is nothing!!!")
                        bsiMessage.Caption = "Error getting DocGUID!"
                        bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
                        bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                        Exit Function
                    End If

                    LOGGER.Debug($"Item_Scope: GotDocID {oFocusedDocID} and DocGUID {oFocusedDocGUID}")

                    ' ========== DATEIPFAD (OPTIONAL) ==========
                    If GridViewWorkflows.Columns(FullFilepatColName) IsNot Nothing Then
                        Dim DOC_PATH = GridViewWorkflows.GetFocusedRowCellValue(GridViewWorkflows.Columns(FullFilepatColName))
                        If DOC_PATH IsNot Nothing Then
                            DOC_PATH = DOC_PATH.Replace("W:\", "\\windream\objects\").Replace("K:\", "\\windream\objects\")
                        End If
                    End If

                    ' ========== DOKUMENT-DATEN SETZEN ==========
                    CURRENT_DOC_ID = oFocusedDocID
                    CURRENT_JUMP_DOC_GUID = oFocusedDocGUID
                    CURRENT_DOC_GUID = CURRENT_JUMP_DOC_GUID

                    ' ========== DOKUMENT-VALIDIERUNG (OPTIMIERT) ==========
                    Dim oSQL = $"SELECT [dbo].[FNPM_CHECK_DocGUID_Valid] ({CURRENT_DOC_GUID})"
                    Dim oResult = DatabaseFallback.GetScalarValueECM(oSQL)

                    If CBool(oResult) = True Then
                        Load_Profil_from_Grid(CURRENT_CLICKED_PROFILE_ID)
                    Else
                        Dim omsg = S.Der_gewählte_Beleg_ist_durch_einen_anderen_Benutzer_bereits_in_Bearbeitung_oder_anderweitig_gesperrt_
                        FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                    End If
                End If
            Else
                FormHelper.ShowInfoMessage("Could not get the ProfileID of file! - Check Your configuration of MainView!", omsgTitleWarning)
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            bsiMessage.Caption = "Warning in Item_Scope: " & ex.Message
            bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
            bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
        Finally
            ' ========== UI AUFRÄUMEN ==========
            If useWaitCursorApplied Then
                Me.UseWaitCursor = False
            End If
            bsiMessage.Caption = ""
            bsiMessage.ItemAppearance.Normal.BackColor = Color.Transparent

            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF Item_Scope] GESAMT: {(DateTime.Now - perfStart).TotalMilliseconds}ms")
            End If
        End Try
    End Function
    Private Async Sub ValidatorClosed(sender As Object, e As FormClosedEventArgs)
        Try
            ' LoadingPanel-Verwaltung erfolgt in Decide_Load
            Await Decide_Load(False, True)

            If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                RefreshHelper.LoadViewInfo()
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Function Init_IDB()
        Try
            IDBData = New ClassIDBData()

            Return True
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox("Error Init_IDB:" & vbNewLine & ex.Message, MsgBoxStyle.Critical, "Attention:")
            LOGGER.Info("Unexpected error in Init_IDB: " & ex.Message, True)
            Return False
        End Try
    End Function
    Private Function Init_windream()
        Try
            WINDREAM = New ClassPMWindream()
            WINDREAM_MOD = New Windream(LOGCONFIG, False, WMDRIVE_LETTER, WMSUFFIX, True, "", "", "", "")

            WINDREAM.Create_Session()
            WINDREAM_ALLG = New ClassWindream_allgemein
            Return WINDREAM.IsLoggedIn
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox("Error Init_windream:" & vbNewLine & ex.Message, MsgBoxStyle.Critical, "Attention:")
            LOGGER.Info("Unexpected error in Init_windream: " & ex.Message, True)
            Return False
        End Try
    End Function
    Private Sub Create_GroupBy_Parts()
        Try
            LOGGER.Debug("Now Create_GroupBy_Parts ...")
            GridViewWorkflows.OptionsView.ShowGroupPanel = False
            Dim oindex As Integer = 0
            If Not IsNothing(BASEDATA_DTGRID_GROUPS) Then
                For Each oGridGroup As DataRow In BASEDATA_DTGRID_GROUPS.Rows

                    Dim oGroupName = oGridGroup.Item("GROUPNAME")

                    LOGGER.Debug($"Adding group [{oGroupName}] for Grid...")
                    Try
                        Dim oGroupColumn As GridColumn = GridViewWorkflows.Columns.Item(oGroupName)

                        If oGroupColumn IsNot Nothing Then
                            oGroupColumn.GroupIndex = oindex
                            oGroupColumn.Group()
                            oGroupColumn.OptionsColumn.AllowGroup = DefaultBoolean.False
                            oGroupColumn.OptionsColumn.AllowMove = False
                            oGroupColumn.OptionsColumn.AllowShowHide = False
                            oGroupColumn.Caption = "Profile (Fixed)"
                        End If
                    Catch ex As Exception

                    End Try

                    oindex += 1
                Next
            End If

            Try
                GridViewWorkflows.Columns.Item("GROUP_TEXT").Visible = False
                GridViewWorkflows.Columns.Item("GROUP_COLOR").Visible = False
            Catch ex As Exception
            End Try
            For index = 0 To GridViewWorkflows.GroupCount - 1
                'Dim v = GridViewWorkflows.GroupedColumns(index).ToString
                LOGGER.Debug($"Adding tag [{GridViewWorkflows.Columns.Item("PROFILE_ID")}] for group...")
                Dim sd = GridViewWorkflows.GroupedColumns(index).GetTextCaption
                GridViewWorkflows.GroupedColumns(index).Tag = GridViewWorkflows.Columns.Item("PROFILE_ID")

            Next
            GridViewWorkflows.CollapseAllGroups()
            LOGGER.Debug("finished Grouping!")
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Async Function Load_Grid_Overview(pFormLoad As Boolean, pForceReload As Boolean, pNavbarClick As Boolean) As Tasks.Task
        Dim perfStart As DateTime = DateTime.MinValue
        Dim perfStep As DateTime = DateTime.MinValue
        Dim gridUpdateStarted As Boolean = False
        Dim viewUpdateStarted As Boolean = False
        Dim layoutRestored As Boolean = False
        Dim resetLayoutTriggered As Boolean = False
        Dim useWaitCursorApplied As Boolean = False
        Dim previousMessage As String = bsiMessage.Caption
        Dim loadingMessageApplied As Boolean = False

        If LOG_HOTSPOTS Then
            perfStart = DateTime.Now
            perfStep = perfStart
            LOGGER.Info($"[PERF Load_Grid_Overview] START - pFormLoad:[{pFormLoad}] pForceReload:[{pForceReload}] pNavbarClick:[{pNavbarClick}]")
        End If

        ' ========== LOADING PANEL UND UI-VORBEREITUNG ==========
        ' SCHRITT 1: Grid sichtbar machen
        If GridControlWorkflows.Visible = False Then
            GridControlWorkflows.Visible = True
        End If

        GRID_LOAD_TYPE = "OVERVIEW"
        CURRENT_CLICKED_PROFILE_ID = 0

        If LOG_HOTSPOTS Then
            Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
            If elapsed > 4000 Then
                LOGGER.Warn($"[PERF LGO] ⚠️ UI-Vorbereitung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
            Else
                LOGGER.Info($"[PERF LGO] UI-Vorbereitung: {elapsed}ms")
            End If
            perfStep = DateTime.Now
        End If

        ' WaitCursor setzen
        If Me.UseWaitCursor = False Then
            Me.UseWaitCursor = True
            useWaitCursorApplied = True
        End If

        ' Statusmeldung aktualisieren
        bsiMessage.Caption = "Overviewdata loading..."
        loadingMessageApplied = True

        Try
            ' ========== GRID UPDATES VORBEREITEN ==========
            If GridControlWorkflows.Visible Then
                GridControlWorkflows.BeginUpdate()
                gridUpdateStarted = True
                GridViewWorkflows.BeginUpdate()
                viewUpdateStarted = True
            End If

            ' ========== DATEN VALIDIEREN ==========
            If BASEDATA_DT_VW_PROFILE_USER.Rows.Count = 0 Then
                LOGGER.Info("Attention: No profiles for user: '" & USER_USERNAME & "' configured!", False)
                NO_WORKFLOW_ITEMS = True
                bsiMessage.Caption = "NO PROFILES FOR USER"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Red
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                GridControlWorkflows.Visible = False
                Exit Try
            End If

            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF LGO] Load_Profiles_for_User wird aufgerufen...")
            End If

            Load_Profiles_for_User()

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Load_Profiles_for_User LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LGO] Load_Profiles_for_User: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== SQL UND DATEN LADEN ==========
            Dim oSQLOverview = BASEDATA_DT_CONFIG.Rows(0).Item("SQL_PROFILE_MAIN_VIEW")

            If IsDBNull(oSQLOverview) Then
                bsiMessage.Caption = "No SQL_PROFILE_MAIN_VIEW in Baseconfig"
                Exit Try
            End If

            If oSQLOverview.ToString.Contains("GROUP_TEXT") = False Then
                LOGGER.Info($"SQL SO FAR: {oSQLOverview} ")
                FormHelper.ShowInfoMessage("Incomplete Overview-Source (No Group-Columns). Column", omsgTitleWarning)
                NO_WORKFLOW_ITEMS = True
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Try
                    GridViewWorkflows.Columns.Clear()
                Catch ex As Exception
                    LOGGER.Error(ex)
                End Try
                Exit Try
            End If

            ' SQL-Platzhalter ersetzen
            oSQLOverview = clsPatterns.ReplaceInternalValues(oSQLOverview)
            oSQLOverview = clsPatterns.ReplaceUserValues(oSQLOverview)
            oSQLOverview = oSQLOverview.Replace("@USER_ID", USER_ID)
            oSQLOverview = oSQLOverview.Replace("@USERNAME", USER_USERNAME)
            oSQLOverview = oSQLOverview.Replace("@MACHINE_NAME", System.Environment.MachineName)
            oSQLOverview = oSQLOverview.Replace("@DATE", Now.ToShortDateString)
            oSQLOverview = oSQLOverview.Replace("@PROFILE_ID", CURRENT_CLICKED_PROFILE_ID)

            If LOG_HOTSPOTS Then
                LOGGER.Info($"[PERF LGO] SQL-Abfrage startet (Rows erwartet: {If(DT_CURR_WF_ITEMS IsNot Nothing, DT_CURR_WF_ITEMS.Rows.Count.ToString(), "N/A")})...")
            End If

            DT_CURR_WF_ITEMS = Await DatabaseFallback.GetDatatableECMAsync(oSQLOverview)

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                Dim rowCount = If(DT_CURR_WF_ITEMS IsNot Nothing, DT_CURR_WF_ITEMS.Rows.Count, 0)
                If elapsed > 4500 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Datenbank-Abfrage Overview LANGSAM: {elapsed}ms ({rowCount} Zeilen) (Schwellwert: 4500ms) - SQL prüfen!")
                Else
                    LOGGER.Info($"[PERF LGO] Datenbank-Abfrage Overview: {elapsed}ms ({rowCount} Zeilen)")
                End If
                perfStep = DateTime.Now
            End If

            If IsNothing(DT_CURR_WF_ITEMS) Then
                NO_WORKFLOW_ITEMS = True
                GridControlWorkflows.Visible = False
                GridControlWorkflows.DataSource = Nothing
                Try
                    GridViewWorkflows.Columns.Clear()
                Catch ex As Exception
                    LOGGER.Error(ex)
                End Try
                Exit Try
            End If

            LOGGER.Debug($"Datatable CURR_DT_OVERVIEW loaded: {DT_CURR_WF_ITEMS.Rows.Count} rows")

            ' ========== DATEN ANALYSIEREN ==========
            Dim oADDED = GET_LAST_ADDED(DT_CURR_WF_ITEMS)
            Dim oChanged = GET_LAST_CHANGED(DT_CURR_WF_ITEMS)
            Dim oCOUNT = DT_CURR_WF_ITEMS.Rows.Count

            NO_WORKFLOW_ITEMS = (oCOUNT = 0)
            UpdateGridCaption()

            If NO_WORKFLOW_ITEMS Then
                GridControlWorkflows.Visible = False
                bindsourcegrid.DataSource = Nothing
                GridControlWorkflows.DataSource = Nothing
                Try
                    GridViewWorkflows.Columns.Clear()
                Catch ex As Exception
                    LOGGER.Error(ex)
                End Try
                Exit Try
            End If

            ' ========== ICON-SPALTE VORBEREITEN ==========
            If TL_ICON = True AndAlso DT_CURR_WF_ITEMS.Columns.Contains("ICON") = False Then
                Dim columnStateIcon As New DataColumn() With {
                    .DataType = GetType(Image),
                    .ColumnName = "ICON",
                    .Caption = ""
                }
                DT_CURR_WF_ITEMS.Columns.Add(columnStateIcon)
            End If

            RedDocuments = 0
            YellowDocuments = 0
            GreenDocuments = 0

            If TL_ICON = True Then
                For Each row As DataRow In DT_CURR_WF_ITEMS.Rows
                    Dim State As Integer = row.Item("TL_STATE")
                    Select Case State
                        Case 1
                            RedDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_red
                        Case 2
                            YellowDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_orange
                        Case 3
                            GreenDocuments += 1
                            row.Item("ICON") = My.Resources.bullet_green
                    End Select
                Next
            End If

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Icon-Verarbeitung LANGSAM: {elapsed}ms ({DT_CURR_WF_ITEMS.Rows.Count} Zeilen) (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LGO] Icon-Verarbeitung: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== GRID MIT DATEN FÜLLEN ==========
            bindsourcegrid.DataSource = DT_CURR_WF_ITEMS
            GridControlWorkflows.DataSource = bindsourcegrid
            GridControlWorkflows.ForceInitialize()

            Create_View_Caption()

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Grid-DataSource-Zuweisung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LGO] Grid-DataSource-Zuweisung: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== LAYOUT WIEDERHERSTELLEN ODER ZURÜCKSETZEN ==========
            Dim oColNotPartofLayout As Boolean = False
            If pNavbarClick = False Then
                If pForceReload = True And (GridLayoutChanged() = True Or oColNotPartofLayout = True) Then
                    LOGGER.Debug("Now GridLayout_Reset..")
                    Await GridLayout_Reset(False)
                    resetLayoutTriggered = True
                ElseIf oColNotPartofLayout = False Then
                    RestoreLayout()
                    layoutRestored = True
                End If
            Else
                RestoreLayout()
                layoutRestored = True
            End If

            If pForceReload = True And (GridLayoutChanged() = True Or oColNotPartofLayout = True) Then
                Create_GroupBy_Parts()
            End If

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Layout-Wiederherstellung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LGO] Layout-Wiederherstellung: {elapsed}ms")
                End If
                perfStep = DateTime.Now
            End If

            ' ========== ICON-SPALTE KONFIGURIEREN ==========
            If TL_ICON = True Then
                Try
                    GridViewWorkflows.Columns.Item("ICON").MaxWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").MinWidth = 24
                    GridViewWorkflows.Columns.Item("ICON").AppearanceCell.BackColor = Color.White
                    GridViewWorkflows.Columns.Item("ICON").Fixed = DevExpress.XtraGrid.Columns.FixedStyle.Left
                Catch ex As Exception
                End Try
            End If

            If GridViewWorkflows.Columns.Count <= 5 Then
                LOGGER.Info("GridViewWorkflows.Columns.Count <= 5 - Reset_Gridlayout will be forced...", False)
                Await Reset_GridLayout(pFormLoad)
                resetLayoutTriggered = True
            End If

            If Not layoutRestored And Not resetLayoutTriggered Then
                RestoreLayout()
            End If

            COLUMNS_INVISIBLE()

            ' ========== SPALTENFORMATIERUNG ANWENDEN ==========
            Try
                For Each oColumn As DevExpress.XtraGrid.Columns.GridColumn In GridViewWorkflows.Columns
                    For Each oRow As DataRow In BASEDATA_TBDD_COLUMNS_FORMAT.Rows
                        Dim colName = oRow("COLUMN_TITLE").ToString()

                        If oColumn.FieldName = colName Then
                            Dim oSollFormatType = oRow("TYPE2FORMAT").ToString()

                            If oSollFormatType = "DateTime" Then
                                If oColumn.ColumnType <> GetType(DateTime) Then
                                    oColumn.DisplayFormat.FormatType = DevExpress.Utils.FormatType.DateTime
                                End If

                                If oColumn.ColumnType = GetType(DateTime) And oColumn.DisplayFormat.FormatString <> "dd.MM.yyyy HH:mm:ss" Then
                                    oColumn.DisplayFormat.FormatString = "dd.MM.yyyy HH:mm:ss"
                                End If
                            ElseIf oSollFormatType = "Numeric" Then
                                If oColumn.ColumnType <> GetType(Int32) Then
                                    oColumn.DisplayFormat.FormatType = DevExpress.Utils.FormatType.Numeric
                                End If
                            End If
                        End If
                    Next
                Next
            Catch ex As Exception
                LOGGER.Warn("⚠️ Fehler beim Anwenden der Formatierung aus TBDD_COLUMNS_FORMAT: " & ex.Message)
            End Try

            If LOG_HOTSPOTS Then
                Dim elapsed = (DateTime.Now - perfStep).TotalMilliseconds
                If elapsed > 4000 Then
                    LOGGER.Warn($"[PERF LGO] ⚠️ Spaltenformatierung LANGSAM: {elapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF LGO] Spaltenformatierung: {elapsed}ms")
                End If
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Info("Load_Grid_Overview - Fehler: " & ex.Message)

        Finally
            ' ========== AUFRÄUMEN ==========
            If viewUpdateStarted Then
                GridViewWorkflows.EndUpdate()
            End If
            If gridUpdateStarted Then
                GridControlWorkflows.EndUpdate()
            End If

            ' WaitCursor entfernen
            If useWaitCursorApplied Then
                Me.UseWaitCursor = False
            End If

            ' Statusmeldung zurücksetzen
            If loadingMessageApplied AndAlso bsiMessage.Caption = "Overviewdata loading..." Then
                bsiMessage.Caption = previousMessage
            End If

            If LOG_HOTSPOTS Then
                Dim totalElapsed = (DateTime.Now - perfStart).TotalMilliseconds
                If totalElapsed > 4000 Then
                    LOGGER.Warn($"[PERF Load_Grid_Overview] ⚠️ GESAMT LANGSAM: {totalElapsed}ms (Schwellwert: 4000ms)")
                Else
                    LOGGER.Info($"[PERF Load_Grid_Overview] GESAMT: {totalElapsed}ms")
                End If
            End If
        End Try
    End Function
    Private Sub tsmiValidationProfil_Click(sender As Object, e As EventArgs) Handles tsmiValidationProfil.Click
        If CURRENT_CLICKED_PROFILE_ID <> 0 Then
            Load_Profil_from_Grid(CURRENT_CLICKED_PROFILE_ID)
        Else
            FormHelper.ShowInfoMessage(S.Bitte_wählen_Sie_ein_Profil_aus_, omsgTitleWarning)
        End If
    End Sub

    Private Async Function GridLayout_Reset(Also_decideload As Boolean) As Tasks.Task


        FRONTEND_ACTION = "RESET_LAYOUT"
        Await Reset_GridLayout(False)
        If Also_decideload Then
            Await Decide_Load(False, True)
        End If

        GridViewWorkflows.OptionsView.ShowViewCaption = False
        SaveGridLayout()

        ' ===== GRUPPIERUNG NUR FÜR OVERVIEW ERSTELLEN =====
        ' Bei Profil-Ansichten (GRID_LOAD_TYPE = PROFILE#xxx) darf nicht gruppiert werden
        If GRID_LOAD_TYPE = "OVERVIEW" Then
            If GridViewWorkflows.GroupCount = 0 AndAlso Not IsNothing(GridViewWorkflows.Columns("GROUP_TEXT")) Then
                LOGGER.Info("NO GROUPS AFTER GridLayout_Reset Load...")
                Create_GroupBy_Parts()
            End If
        Else
            LOGGER.Debug($"GridLayout_Reset: Skipping Create_GroupBy_Parts for non-OVERVIEW mode [{GRID_LOAD_TYPE}]")
        End If

        GridBuilder.WithFontSizeDelta(CONFIG.Config.GridFontSizeDelta)
        If GridControlWorkflows.Visible = True And FormOpenClose = False Then RefreshHelper.LoadViewInfo()
        FRONTEND_ACTION = FA_NONE
    End Function

    Async Function Reset_GridLayout(FormLoad As Boolean) As Tasks.Task

        If GridControlWorkflows.Visible = True And FormOpenClose = False Then
            RefreshHelper.SaveViewInfo()
        End If

        InResetlayout = True
        ' Layout zurücksetzen
        ResetLayout()

        ' Ansicht neu laden
        'LoadNavBar()
        Await Decide_Load(FormLoad)
        InResetlayout = False
    End Function

    Private Async Sub GridViewWorkflows_DoubleClick(sender As Object, e As EventArgs) Handles GridViewWorkflows.DoubleClick
        Me.Cursor = Cursors.WaitCursor
        Await Item_Scope("DOUBLECLICK")
        Me.Cursor = Cursors.Default
    End Sub

    'Private Sub GridViewWorkflows_CustomDrawGroupRow(sender As Object, e As Views.Base.RowObjectCustomDrawEventArgs) Handles GridViewWorkflows.CustomDrawGroupRow
    '    Try
    '        ' Added
    '        If FormOpenClose = True And GridIsLoaded = False Then
    '            Exit Sub
    '        End If

    '        Dim info As GridGroupRowInfo = TryCast(e.Info, GridGroupRowInfo)
    '        Dim view As GridView = sender

    '        If info.Column.FieldName = "GROUP_TEXT" Then
    '            info.GroupText = info.GroupValueText

    '            Dim oColorString As String = "LightGray"
    '            Dim oFontColorString As String = "Black"
    '            Dim oFoundConfig As Boolean = False
    '            Dim oGROUP_TEXT_COL As String
    '            If USER_LANGUAGE = "de-DE" Then
    '                oGROUP_TEXT_COL = "GROUP_TEXT"
    '            Else
    '                oGROUP_TEXT_COL = "GROUP_TEXT_LANG"
    '            End If


    '            For Each oProfileRow As DataRow In CURR_DT_VWPM_PROFILE_ACTIVE.Rows
    '                If oProfileRow.Item(oGROUP_TEXT_COL) = info.GroupValueText Then
    '                    oFoundConfig = True
    '                    oColorString = oProfileRow.Item("GROUP_COLOR")
    '                    oFontColorString = oProfileRow.Item("GROUP_FONT_COLOR")
    '                    ' Added
    '                    Exit For
    '                End If
    '            Next
    '            If oFoundConfig = False Then
    '                LOGGER.Info($"CustomDrawGroupRow: Could not find a ColorConfig for ProfileGroupValueText [{info.GroupValueText}]...")
    '                ' Added
    '                Exit Sub
    '            End If

    '            Dim oColor As Color = ParseColorString(oColorString, Color.LightGray, "Background Color")
    '            Dim oFontColor As Color = ParseColorString(oFontColorString, Color.Black, "Font Color")

    '            info.Appearance.BackColor = oColor
    '            info.Appearance.ForeColor = oFontColor
    '        End If
    '    Catch ex As Exception
    '        LOGGER.Error(ex)
    '    End Try
    'End Sub

    Private Sub GridViewWorkflows_CustomDrawGroupRow(sender As Object, e As Views.Base.RowObjectCustomDrawEventArgs) Handles GridViewWorkflows.CustomDrawGroupRow
        Try

            If FormOpenClose = True And GridIsLoaded = False Then
                Exit Sub
            End If

            Dim oInfo As GridGroupRowInfo = TryCast(e.Info, GridGroupRowInfo)
            If oInfo Is Nothing OrElse oInfo.Column Is Nothing Then
                Exit Sub
            End If

            Dim oView As GridView = sender

            If oInfo.Column.FieldName = "GROUP_TEXT" Then
                oInfo.GroupText = oInfo.GroupValueText

                Dim oColorString As String = "LightGray"
                Dim oFontColorString As String = "Black"
                Dim oChildRowHandle As Integer = oView.GetChildRowHandle(oInfo.RowHandle, 0)

                oColorString = oView.GetRowCellValue(oChildRowHandle, "GROUP_COLOR")

                Dim oColor As Color = ParseColorString(oColorString, Color.LightGray, "Background Color")
                Dim oFontColor As Color = ParseColorString(oFontColorString, Color.Black, "Font Color")

                oInfo.Appearance.BackColor = oColor
                oInfo.Appearance.ForeColor = oFontColor
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Function ParseColorString(ColorString As String, DefaultColor As Color, ColorDescription As String) As Color
        Dim oResultColor As Color

        If ColorString.Contains(";") Or ColorString.Contains(".") Then
            Dim oSplitColorString As String()

            If ColorString.Contains(";") Then
                oSplitColorString = ColorString.Split(";")
            Else
                oSplitColorString = ColorString.Split(".")
            End If

            Try
                oResultColor = Color.FromArgb(oSplitColorString(0), oSplitColorString(1), oSplitColorString(2))
            Catch ex As Exception
                oResultColor = DefaultColor
                LOGGER.Info("ParseColorString: Could not get Color.FromArgb [{0}] for {1}", ColorString, ColorDescription)
            End Try
        Else
            Try
                oResultColor = Color.FromName(ColorString)
            Catch ex As Exception
                LOGGER.Info("ParseColorString: Could not get Color.FromArgb [{0}] for {1}", ColorString, ColorDescription)
                oResultColor = DefaultColor
            End Try
        End If

        Return oResultColor
    End Function


    Private Sub GridViewWorkflows_MouseDown(sender As Object, e As MouseEventArgs) Handles GridViewWorkflows.MouseDown
        Dim view As GridView = sender
        Dim hi As GridHitInfo = view.CalcHitInfo(e.Location)
        Dim groupRowButtonClicked = (hi.HitTest = GridHitTest.RowGroupButton)
        GridCursorLocation = e.Location

        'If e.Button = MouseButtons.Left Then
        ' wenn in eine Group Row Doppelt geklickt wurde..
        If hi.InGroupRow And Not groupRowButtonClicked Then
            ' Ein/Ausklappen verhindern
            DXMouseEventArgs.GetMouseArgs(e).Handled = True
            GridViewItem_Clicked = "GROUP"
            If Not Application.OpenForms().OfType(Of frmValidator).Any Then
                CURRENT_CLICKED_PROFILE_ID = GridViewWorkflows.GetRowCellValue(GridViewWorkflows.GetDataRowHandleByGroupRowHandle(hi.RowHandle), GridViewWorkflows.Columns("PROFILE_ID"))
            End If

        ElseIf hi.InDataRow Then
            GridViewItem_Clicked = "ROW"
            If Not Application.OpenForms().OfType(Of frmValidator).Any Then
                CURRENT_CLICKED_PROFILE_ID = GridViewWorkflows.GetRowCellValue(GridViewWorkflows.GetDataRowHandleByGroupRowHandle(hi.RowHandle), GridViewWorkflows.Columns("PROFILE_ID"))
            End If

        Else
            GridViewItem_Clicked = Nothing
            If hi.HitTest = GridHitTest.FilterPanelCloseButton Then
                Ev_Filter_Panel_Closed = True
                Grid_Reset_Filter()
                Ev_Filter_Panel_Closed = False
            End If
        End If
        If Not IsNothing(CURRENT_CLICKED_PROFILE_ID) Then
            If IsNumeric(CURRENT_CLICKED_PROFILE_ID) Then
                If CURRENT_CLICKED_PROFILE_ID > 0 Then
                    For Each orow As DataRow In CURRENT_DT_PROFILES.Rows
                        If orow.Item("GUID") = CURRENT_CLICKED_PROFILE_ID Then
                            If Not Application.OpenForms().OfType(Of frmValidator).Any Then
                                CURRENT_CLICKED_PROFILE_TITLE = orow.Item("TITLE")
                            End If

                            Exit For
                        End If
                    Next
                End If
            End If
        End If

    End Sub

    Private Sub GridViewWorkflows_ColumnWidthChanged(sender As Object, e As Views.Base.ColumnEventArgs) Handles GridViewWorkflows.ColumnWidthChanged
        GridLayout_Changed("ColumnWidthChanged")
    End Sub
    Private Sub GridViewWorkflows_EndSorting(sender As Object, e As EventArgs) Handles GridViewWorkflows.EndSorting
        GridLayout_Changed("EndSorting")
    End Sub

    Private Sub GridViewWorkflows_LostFocus(sender As Object, e As EventArgs) Handles GridViewWorkflows.LostFocus
        ' Save expanded GroupRows
        If GridControlWorkflows.Visible = True And FormOpenClose = False Then
            RefreshHelper.SaveViewInfo()
        End If
    End Sub
    Sub LoadCURRENT_DT_PROFILES()
        Dim oSQL = $"select * from TBPM_PROFILE WITH (NOLOCK) where ACTIVE = 1"
        CURRENT_DT_PROFILES = DatabaseFallback.GetDatatable("TBPM_PROFILE", New GetDatatableOptions(oSQL, DatabaseType.ECM))
        oSQL = $"select * from TBDD_GUI_LANGUAGE_PHRASE WITH (NOLOCK) where LANGUAGE = '{USER_LANGUAGE}' AND MODULE = 'PM' AND TITLE LIKE 'PROFILE_%'"
        CURRENT_DT_PROFILE_LANGUAGE = DatabaseFallback.GetDatatable("TBPMPROFILE_LANGUAGE_TERMS", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
                .FilterExpression = $"LANGUAGE = '{USER_LANGUAGE}'"
            })
    End Sub
    Sub LoadVWPM_CONTROL_INDEX()
        Dim oSQL = $"SELECT * FROM VWPM_CONTROL_INDEX ORDER BY PROFIL_ID,Y_LOC, X_LOC"
        'DTVWCONTROLS_INDEX = DataASorDB.GetDatatable("DD_ECM", oSQL, "VWPM_CONTROL_INDEX", "")
        DTVWCONTROLS_INDEX = DatabaseFallback.GetDatatable("VWPM_CONTROL_INDEX", New GetDatatableOptions(oSQL, DatabaseType.ECM))
    End Sub
    Sub GetBaseData(pMode As String)
        Dim oStopWatch As New RefreshHelper.SW("GetBaseData")
        Try
            Dim oSQL = String.Format("SELECT * FROM [dbo].[FNDD_LOGIN_USER_MODULE] ('{0}','PM',{1})", USER_USERNAME, CLIENT_SELECTED)
            Dim DT_CHECKUSER_MODULE As DataTable
            DT_CHECKUSER_MODULE = DatabaseFallback.GetDatatable("TBDD_USER_MODULE", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
                                .FilterExpression = $"USERNAME = '{USER_USERNAME.ToLower}' AND MODULE_SHORT = 'PM'"
                            })

            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(10)
            If pMode <> "Load" Then
                ClassParamRefresh.Refresh_Params(DT_CHECKUSER_MODULE, pMode)
            End If

            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(20)
            If SQL_PROFILES_USER <> "" Then
                oSQL = SQL_PROFILES_USER.Replace("@USER_ID", USER_ID)
                LOGGER.Debug($"VWPM_PROFILE_ACTIVE-SELECT used from DD-SQL-Config..")
            Else
                oSQL = $"SELECT [dbo].[FNDD_LANGUAGE_PHRASE] ('PROFILE_TITLE' + CONVERT(VARCHAR(4),T.GUID),'{USER_LANGUAGE}','PM') as GROUP_TEXT_LANG, T.* 
FROM VWPM_PROFILE_ACTIVE T WHERE T.GUID IN (SELECT PROFILE_ID FROM [dbo].[FNPM_GET_ACTIVE_PROFILES_USER] ({USER_ID}))"

            End If
            LOGGER.Debug($"VWPM_PROFILE_ACTIVE-SELECT: {oSQL}")
            CURR_DT_VWPM_PROFILE_ACTIVE = DatabaseFallback.GetDatatableECM(oSQL)
            CURR_DT_VWPM_PROFILE_AH_WORKFLOW = CURR_DT_VWPM_PROFILE_ACTIVE.Copy
            CURR_DT_VWPM_PROFILE_AH_WORKFLOW.Clear()
            Dim AHWFRows As DataRow() = CURR_DT_VWPM_PROFILE_ACTIVE.Select($"TYPE = {ConstAHWorkflow_BlindFile}", "PRIORITY")
            If AHWFRows.Length > 0 Then
                LOGGER.Info($"...NUMBER OF ADHOC-WORKFLOW PROFILES ({AHWFRows.Length})")
                CURR_DT_VWPM_PROFILE_AH_WORKFLOW = AHWFRows.CopyToDataTable()
            Else
                LOGGER.Debug($"...NO ADHOC-WORKFLOW PROFILES!")
            End If

            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(30)
            LoadCURRENT_DT_PROFILES()

            If pMode = "Load" Then
                CURRENT_DT_PROFILE = CURRENT_DT_PROFILES.Clone()
            End If
            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(40)
            oSQL = "select * from TBPM_PROFILE_SEARCH WITH (NOLOCK) where TYPE = 'DOC' AND ACTIVE = 1 ORDER BY PROFILE_ID,TAB_INDEX"
            If SQL_VALIDATOR_SEARCHES <> String.Empty Then
                SQL_VALIDATOR_SEARCHES = SQL_VALIDATOR_SEARCHES.Replace("@USR_LANG_CODE", User.Language)
                oSQL = SQL_VALIDATOR_SEARCHES
            End If

            BASEDATA_DT_PROFILES_SEARCHES_DOC = DatabaseECM.GetDatatable(oSQL)
            EnsureProfileSearchType(BASEDATA_DT_PROFILES_SEARCHES_DOC, "DOC", NameOf(BASEDATA_DT_PROFILES_SEARCHES_DOC))

            If pMode = "Load" Then
                DT_FILTERED_PROFILE_SEARCHES_DOC = BASEDATA_DT_PROFILES_SEARCHES_DOC.Clone()
            End If
            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(50)
            oSQL = "select * from TBPM_PROFILE_SEARCH WITH (NOLOCK) where TYPE = 'SQL' AND ACTIVE = 1 ORDER BY PROFILE_ID,TAB_INDEX"

            BASEDATA_DT_PROFILES_SEARCHES_DATA = DatabaseFallback.GetDatatable("TBPM_PROFILE_SEARCH", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
            .FilterExpression = "TYPE = 'SQL'",
            .SortByColumn = "PROFILE_ID,TAB_INDEX"
            })
            EnsureProfileSearchType(BASEDATA_DT_PROFILES_SEARCHES_DATA, "SQL", NameOf(BASEDATA_DT_PROFILES_SEARCHES_DATA))

            oSQL = String.Format("SELECT [dbo].[FNPM_LANGUAGE_CONTROL_TEXT] (NAME,'{0}',CTRL_TYPE,CTRL_TEXT) CTRL_CAPTION_LANG, '{0}' as LANGUAGE, * FROM TBPM_PROFILE_CONTROLS WITH (NOLOCK) WHERE CONTROL_ACTIVE = 1", {USER_LANGUAGE})
            BASEDATA_TBPM_PROFILE_CONTROLS = DatabaseFallback.GetDatatable("TBPM_PROFILE_CONTROLS_LANGUAGE", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
                .FilterExpression = String.Format("LANGUAGE = '{0}'", {USER_LANGUAGE})
            })
            If pMode = "Load" Then
                DT_FILTERED_PROFILE_SEARCHES_DATA = BASEDATA_DT_PROFILES_SEARCHES_DATA.Clone()
            End If
            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(60)
            LoadVWPM_CONTROL_INDEX()
            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(80)
            If pMode = "Load" Then
                DTVWCONTROL_INDEX = DTVWCONTROLS_INDEX.Clone()
            End If
            oSQL = $"SELECT * FROM TBPM_PROFILE_CONTROLS WITH (NOLOCK) WHERE CONTROL_ACTIVE = 1 AND LEN(ISNULL(SQL_UEBERPRUEFUNG,'')) > 0 AND CTRL_TYPE <> 'BUTTON'"
            DTCONTROLS_WITH_SQL = DatabaseFallback.GetDatatable("DTCONTROLS_WITH_SQL", New GetDatatableOptions(oSQL, DatabaseType.ECM))

            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(85)
            oSQL = "SELECT * FROM TBPM_PROFILE_FINAL_INDEXING with (NOLOCK) WHERE ACTIVE = 1"
            DTTBPM_PROFILE_FINAL_INDEXING = DatabaseFallback.GetDatatable("TBPM_PROFILE_FINAL_INDEXING", New GetDatatableOptions(oSQL, DatabaseType.ECM))

            If pMode = "bwBasicData" Then bwBasicData.ReportProgress(100)
        Catch ex As Exception
            LOGGER.Warn($"Error in GetBaseData - Error: [{ex.Message}]")
        End Try
        oStopWatch.Done()
    End Sub
    Private Sub EnsureProfileSearchType(ByRef pTable As DataTable, expectedType As String, tableName As String)
        Try
            If pTable Is Nothing Then
                LOGGER.Warn($"{tableName} is Nothing - type guard skipped")
                Exit Sub
            End If

            If pTable.Columns.Contains("TYPE") = False Then
                LOGGER.Warn($"{tableName} has no TYPE column - type guard skipped")
                Exit Sub
            End If

            Dim cleanedTable As DataTable = pTable.Clone()
            Dim removedCount As Integer = 0
            Dim sampleInvalidSql As String = String.Empty

            For Each row As DataRow In pTable.Rows
                Dim rowType As String = String.Empty
                If row("TYPE") IsNot DBNull.Value Then
                    rowType = row("TYPE").ToString().Trim().ToUpperInvariant()
                End If

                If rowType = expectedType.ToUpperInvariant() Then
                    cleanedTable.ImportRow(row)
                Else
                    removedCount += 1
                    If sampleInvalidSql = String.Empty AndAlso pTable.Columns.Contains("SQL_COMMAND") Then
                        If row("SQL_COMMAND") IsNot DBNull.Value Then
                            sampleInvalidSql = row("SQL_COMMAND").ToString()
                        End If
                    End If
                End If
            Next

            If removedCount > 0 Then
                LOGGER.Warn($"{tableName}: removed {removedCount} row(s) with unexpected TYPE. Expected TYPE='{expectedType}'.")
                If sampleInvalidSql <> String.Empty Then
                    LOGGER.Warn($"{tableName}: sample unexpected SQL_COMMAND => {sampleInvalidSql}")
                End If
            End If
            LOGGER.Debug($"{tableName}: {cleanedTable.Rows.Count} rows with TYPE='{expectedType}' after type guard.")
            pTable = cleanedTable
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Warn($"EnsureProfileSearchType failed for {tableName}")
        End Try
    End Sub
    Private Sub ConfigureGlobalLookAndFeel()
        If RIBBON_COLOR_SCHEME <> "" Then
            UserLookAndFeel.Default.UseDefaultLookAndFeel = False
            If RIBBON_COLOR_SCHEME = "Blue".ToUpper Then
                LookAndFeel.SetSkinStyle(SkinStyle.Office2019White, SkinSvgPalette.Office2019White.Yale)
            ElseIf RIBBON_COLOR_SCHEME = "Green".ToUpper Then
                LookAndFeel.SetSkinStyle(SkinStyle.Office2019White, SkinSvgPalette.Office2019White.Pine)
            ElseIf RIBBON_COLOR_SCHEME = "Purple".ToUpper Then
                LookAndFeel.SetSkinStyle(SkinStyle.Office2019White, SkinSvgPalette.Office2019White.Plum)
            ElseIf RIBBON_COLOR_SCHEME = "Red".ToUpper Then
                LookAndFeel.SetSkinStyle(SkinStyle.Office2019White, SkinSvgPalette.Office2019White.FireBrick)
            Else
                RibbonControl1.ColorScheme = DevExpress.XtraBars.Ribbon.RibbonControlColorScheme.Default
            End If
            LOGGER.Debug($" RibbonControl1.ColorScheme [{RIBBON_COLOR_SCHEME}]")
        End If
    End Sub
    Private Async Sub frmMain_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        Me.Text = ADDITIONAL_TITLE
        FormShown = True
        Try
            If CONFIG.Config.MainTreeList_Width > 0 Then
                TreeList_Cockpit.Width = CONFIG.Config.MainTreeList_Width
            End If
        Catch ex As Exception
        End Try



        Timer_Inactivity_Reset_Disable("Decide_Load")

        Dim oFirstNode As DevExpress.XtraTreeList.Nodes.TreeListNode = TreeList_Cockpit.Nodes.FirstOrDefault()
        If oFirstNode IsNot Nothing Then
            LOGGER.Debug($"Selecting first TreeList node: [{oFirstNode.GetValue("NAME")}]")
            TreeList_Cockpit.FocusedNode = oFirstNode
            Await ProcessTreeListNodeAsync(oFirstNode)
        Else
            LOGGER.Debug("No TreeList nodes found - falling back to Decide_Load")
            Await Decide_Load(True)
        End If

        If GridViewWorkflows.GroupCount = 0 And Not IsNothing(GridViewWorkflows.Columns("GROUP_TEXT")) Then
            LOGGER.Info("NO GROUPS AFTER SHOWN_Decide Load...")
            Create_GroupBy_Parts()
        End If

        ' ===== SICHTBARKEIT NACH LADEVORGANG NOCHMALS ANWENDEN =====
        ' AppendCountsToTreeAsync könnte bereits vor frmMain_Shown abgeschlossen sein (Race Condition),
        ' daher hier sicherstellen, dass die korrekte Sichtbarkeit gesetzt ist
        If _treeNodeCounts.Count > 0 Then
            LOGGER.Debug($"frmMain_Shown: Applying node visibility after load (Hide_Empty_Workflows=[{CONFIG.Config.Hide_Empty_Workflows}])")
            Decide_Show_Empty_Workflows(Not CONFIG.Config.Hide_Empty_Workflows)
        End If

        Handling_DEBUG_USER()

        Dim oSQL = $"SELECT * FROM TBDD_NOTIFICATIONS_SYSTEM NOTE WITH (NOLOCK) 
            INNER JOIN (SELECT * FROM TBDD_NOTIFICATIONS_SYSTEM WITH (NOLOCK) WHERE LANG_CODE = '{USER_LANGUAGE}' OR LANG_CODE = 'ALL') LANG ON NOTE.GUID = LANG.GUID
                where (CONVERT(DATE,GETDATE()) <= NOTE.DISPLAY_UNTIL or NOTE.DISPLAY_UNTIL IS NULL) AND NOTE.MODULE = 'PM' 
            AND NOTE.GUID NOT IN (SELECT NOTIFY_ID FROM TBDD_NOTIFICATIONS_USER_HISTORY WITH (NOLOCK) WHERE USR_ID = {USER_ID})"
        Dim oDT As DataTable = DatabaseFallback.GetDatatable("TBDD_NOTIFICATIONS_SYSTEM", New GetDatatableOptions(oSQL, DatabaseType.ECM))

        If Not IsNothing(oDT) Then
            If oDT.Rows.Count > 0 Then
                NOTIFICATIONS_DT = oDT
                BBtnItmNotfications.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                Open_Notifications_Form()
            End If
        End If

    End Sub
    Sub Open_Notifications_Form()
        Try
            Dim oEnvironment = GetEnvironment()
            Dim oNForm As New frmNotification_Startup(NOTIFICATIONS_DT, LOGCONFIG, GDPICTURE_LICENSE, TITLE_NOTIFICATIONS, oEnvironment)
            oNForm.ShowDialog()
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Sub Handling_DEBUG_USER()
        If DEBUG = True Then
            'bsiDebug.Caption = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("DebugModeActive")
            bsiDebug.Caption = S.HINWEIS__Debug_Modus_ist_eingeschaltet_
            bsiDebug.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
        Else
            bsiDebug.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        End If
    End Sub

    Sub DebuglogBackgroundthread()
        Dim oSQL As String = FA_NONE
        Try
            For Each oSLogstring As String In LOGCONFIG.Logs
                Dim oLogSplit As String() = oSLogstring.Split("|")
                Dim oMessage = PrepareLogMessage(oSLogstring)
                Dim oDateTime As Date = CDate(oLogSplit(0))
                oSQL = $"INSERT INTO [dbo].[TBPM_LOG_DEBUG] ([USERID] , [LOGMSG], [ADDED_WHEN],DATE_STR) VALUES({USER_ID},'{oMessage}',GetDate(),'{oDateTime}')"
                DatabaseFallback.ExecuteNonQueryECM(oSQL)
            Next
            LOGCONFIG.ClearLogs()
        Catch ex As Exception
            LOGGER.Error(ex)
            LOGGER.Warn($"oSQL so far [{oSQL}]")
        End Try
    End Sub
    Private Sub tsslblDEBUG_LOG_MouseHover(sender As Object, e As EventArgs)
        MsgBox("UserDebugMode is activated remotely. Debugdata will be transferred to database and will be deleted after 10 days!!", MsgBoxStyle.Information, ADDITIONAL_TITLE)
    End Sub

    Private Sub frmMain_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
        If Application.OpenForms().OfType(Of frmValidator).Any Then
            _FormValidator.Close()
        End If
        If Not IsNothing(WINDREAM_MOD) And IDB_ACTIVE = False Then
            LOGGER.Debug("Closing frmMain - Now logging out...")
            Try
                WINDREAM_MOD.Session.Logout()
                LOGGER.Debug("WINDREAM_MOD Session logged out successfully.")

            Catch ex As Exception
                LOGGER.Warn("Error while logging out WINDREAM_MOD Session: {0}", ex.Message)
                LOGGER.Error(ex)
            End Try
        End If

    End Sub


    Sub Grid_Reset_Filter()
        Timer_Inactivity_Reset_Disable("LöscheAlleFilterToolStripMenuItem")

        Try
            GridViewWorkflows.ClearFindFilter()
            GridViewWorkflows.ClearColumnsFilter()
            SaveGridLayout()
        Catch ex As Exception

        End Try
    End Sub

    Private Sub ContextMenuNotifyIcon_Opening(sender As Object, e As CancelEventArgs) Handles ContextMenuNotifyIcon.Opening
        If CONFIG.Config.ReminderTimer <> 0 Then
            PopupErinnerungInaktivierenToolStripMenuItem.Text = "Popup Erinnerung inaktivieren"
        Else
            PopupErinnerungInaktivierenToolStripMenuItem.Text = $"Popup Erinnerung aktivieren ({CONFIG.Config.ReminderTimer} min)"
        End If
    End Sub

    Private Sub PopupErinnerungInaktivierenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles PopupErinnerungInaktivierenToolStripMenuItem.Click
        If CONFIG.Config.ReminderTimer <> 0 Then
            TimerReminder.Stop()
            TimerReminder.Enabled = False
        Else
            CONFIG.Config.ReminderTimer = 5
            CONFIG.Save()
            Check_Timer_Notification()

        End If
    End Sub
    Private Sub AnzeigenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AnzeigenToolStripMenuItem.Click
        BringMonitor2Front()
    End Sub

    Private Sub frmMain_Resize(sender As Object, e As EventArgs) Handles Me.Resize
        Try
            If FormShown = False Then
                Exit Sub
            End If

            If WindowState = FormWindowState.Maximized Then
                My.Settings.frmMainWindowState = "Maximized"
            ElseIf WindowState = FormWindowState.Normal Then
                My.Settings.frmMainWindowState = "Normal"
            End If
            My.Settings.Save()
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Sub BarButtonItem3_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtniGrundeinstellung.ItemClick
        Try
            frmKonfig.ShowDialog()

            '  Load_Profil()
            Check_Timer_Notification()
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox(ex.Message, MsgBoxStyle.Critical, "Fehler beim Laden Grundeinstellungen:")
        End Try
    End Sub


    Private Async Sub bbtniRefresh_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtniRefresh.ItemClick
        If Application.OpenForms().OfType(Of frmValidator).Any Then
            'FormHelper.ShowInfoMessage(omsgOpenWorkflow, omsgTitleWarning)
            FormHelper.ShowInfoMessage(S.Bitte_schließen_Sie_den_offenen_Workflow_, omsgTitleWarning)
            Exit Sub
        End If
        Timer_Inactivity_Reset_Disable("OverviewRefreshClick")
        'If GridControlWorkflows.Visible = True And FormOpenClose = False Then
        '    RefreshHelper.SaveViewInfo()
        '    SaveGridLayout()
        'End If
        Await Decide_Load(False, True)
        'LoadNavBar()
        If GridControlWorkflows.Visible = True And FormOpenClose = False Then
            RefreshHelper.LoadViewInfo()
        End If
    End Sub

    Private Sub bbtniMonitor_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs)
        ' Prüfen ob bereits ein Monitor mit der aktuellen COCKPIT_MONITOR_ID geöffnet ist
        If COCKPIT_MONITOR_ID > 0 Then
            Dim existingMonitor = Application.OpenForms().OfType(Of frmMonitor)().FirstOrDefault(Function(f) f.MonitorID = COCKPIT_MONITOR_ID)
            If existingMonitor IsNot Nothing Then
                LOGGER.Debug($"bbtniMonitor_ItemClick: Monitor with ID [{COCKPIT_MONITOR_ID}] is already open - bringing to front")
                existingMonitor.Activate()
                existingMonitor.BringToFront()
                Exit Sub
            End If
        End If

        Dim newMonitor As New frmMonitor(COCKPIT_MONITOR_ID)
        newMonitor.Show()
    End Sub

    Private Sub bbiProfilverwaltung_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbiProfilverwaltung.ItemClick
        'Dim AdminSecurity As Boolean = False
        'AdminSecurity = TBPM_KONFIGURATIONTableAdapter.cmdGetAdminSecurity()
        'If AdminSecurity = True Then
        '    frmLoginAdmin.ShowDialog()
        'Else
        frmAdministration.Show()
        ' End If

    End Sub

    Private Sub bbiKonfiguration_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbiKonfiguration.ItemClick
        frmAdmin2.ShowDialog()
    End Sub

    Private Sub bbtniMetadataFile_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtniMetadataFile.ItemClick
        frmDesignerLayout.Show()
    End Sub

    Private Sub bwSync_DoWork(sender As Object, e As DoWorkEventArgs) Handles bwSync.DoWork

    End Sub

    Private Sub bwSync_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bwSync.ProgressChanged
        BarEditItem1.EditValue = e.ProgressPercentage
    End Sub


    Private Sub Timer5Mins_Tick(sender As Object, e As EventArgs) Handles Timer5Mins.Tick

        Try
            Timer5Mins_running = True
            If Not bwBasicData.IsBusy Then
                BarEditItem1.Caption = "Get BasicData"
                BarEditItem1.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                bwBasicData.RunWorkerAsync()
            End If

            If DEBUG = True Then
                '    'Jetzt der insert der Inhalte
                If Not IsNothing(LOGCONFIG.Logs) Then
                    If LOGCONFIG.Logs.Count > 0 Then
                        Dim thread As New Thread(AddressOf DebuglogBackgroundthread)
                        thread.Start()

                    End If

                End If
            End If
        Catch ex As Exception
            LOGGER.Warn($"Timer5Mins Error: {ex.Message}")
        End Try
        Timer5Mins_running = False
    End Sub
    Private Sub bwBasicData_DoWork(sender As Object, e As DoWorkEventArgs) Handles bwBasicData.DoWork
        GetBaseData("bwBasicData")
    End Sub

    Private Sub bwBasicData_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bwBasicData.RunWorkerCompleted
        Try
            If e.Error IsNot Nothing Then
                LOGGER.Error(e.Error)
                LOGGER.Warn($"bwBasicData completed with error: {e.Error.Message}")
            End If

            If USER_IS_ADMIN Then
                bsiDebug.Caption = String.Format(S.Anzahl_Lizenzen___0_, USERCOUNT_LOGGED_IN)
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        Finally
            BarEditItem1.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
            ' Caption zurücksetzen, falls sie noch auf "busy" steht
            If bsiMessage.Caption = "bwBasicData is busy - no Refreshing" Then
                bsiMessage.Caption = ""
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Transparent
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Empty
            End If
        End Try
    End Sub

    Private Sub bwBasicData_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles bwBasicData.ProgressChanged
        BarEditItem1.EditValue = e.ProgressPercentage
    End Sub

    Private Sub BarButtonItem2_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs)
        If Application.OpenForms().OfType(Of frmInvDashboard).Any Then
            Exit Sub
        End If

        frmInvDashboard.Show()
    End Sub

    Private Sub OutOfRangePMFixierenToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles OutOfRangePMFixierenToolStripMenuItem.Click
        Dim myPoint As System.Drawing.Point = New System.Drawing.Point(50, 50)
        Me.Location = Screen.AllScreens(UBound(Screen.AllScreens)).Bounds.Location + myPoint
        BringMonitor2Front()
    End Sub

    Private Sub GridViewWorkflows_RowStyle(sender As Object, e As RowStyleEventArgs) Handles GridViewWorkflows.RowStyle
        If FormShown = False Then
            Exit Sub
        End If
        If e.RowHandle = -1 Then
            IsFilterMode = True
            Exit Sub
        End If
        If e.RowHandle = DevExpress.XtraGrid.GridControl.AutoFilterRowHandle Then
            IsFilterMode = True
            ' e.Appearance.BackColor = Color.Yellow
        Else
            IsFilterMode = False
            Try
                Dim oRowColorCellValue = GridViewWorkflows.GetRowCellValue(e.RowHandle, "ROW_COLOR")
                If Not IsNothing(oRowColorCellValue) Then
                    Dim oColor As Color
                    Try
                        If oRowColorCellValue.ToString.Contains(";") Or oRowColorCellValue.ToString.Contains(".") Then
                            Dim oColorSplit As String()
                            If oRowColorCellValue.Contains(";") Then
                                oColorSplit = oRowColorCellValue.Split(";")
                            ElseIf oRowColorCellValue.Contains(".") Then
                                oColorSplit = oRowColorCellValue.Split(".")
                            End If


                            Try
                                oColor = Color.FromArgb(oColorSplit(0), oColorSplit(1), oColorSplit(2))
                            Catch ex As Exception
                                LOGGER.Info($"RowColorHandler: Could not get Color.FromArgb [{oRowColorCellValue}]")
                                oColor = Color.LightGray
                            End Try
                        Else
                            Try
                                oColor = Color.FromName(oRowColorCellValue)
                            Catch ex As Exception
                                LOGGER.Info($"RowColorHandler: Could not get Color.FromName [{oRowColorCellValue}]")
                            End Try


                        End If
                    Catch ex As Exception
                        LOGGER.Info("RowBackColor: " & ex.Message, False)
                        Exit Sub
                    End Try
                    e.Appearance.BackColor = oColor
                    e.HighPriority = True
                End If
            Catch ex As Exception
                LOGGER.Info("Unexpected Error in RowStyle: " & ex.Message, False)
            End Try

        End If
    End Sub

    Private Async Sub BarButtonItem2_ItemClick_1(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtnitmGhostMode.ItemClick
        frmGhostMode.ShowDialog()
        If USER_GHOST_MODE_ACTIVE = True And USER_GHOST_MODE_USRNAME <> String.Empty Then
            LOGGER.Info($"GHOST MODE for User {USER_GHOST_MODE_USRNAME} will now be initialized!")
            Dim oUserLanguage = User.Language
            USER_USERNAME_ORG = USER_USERNAME
            BarButtonItemGhostMode.Caption = String.Format(S.Ghost_Modus___0___deaktivieren, USER_GHOST_MODE_USRNAME)
            BarButtonItemGhostMode.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
            _Init.InitBasics()
            _Init.InitUserLogin()
            _Init.InitBasics2()
            Dim onewUserLanguage = User.Language
            GetBaseData("Load")
            'LoadNavBar()
            If oUserLanguage <> onewUserLanguage Then
                MsgBox($"Layout will be reset as language changed from {oUserLanguage} to {onewUserLanguage}", MsgBoxStyle.Exclamation, ADDITIONAL_TITLE)
                Await GridLayout_Reset(True)
            Else
                Await Decide_Load(False)
            End If


            If GridControlWorkflows.Visible = True And FormOpenClose = False Then RefreshHelper.LoadViewInfo()
        End If
    End Sub

    Private Async Sub BarButtonItem2_ItemClick_2(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemGhostMode.ItemClick
        USER_GHOST_MODE_ACTIVE = False
        USER_GHOST_MODE_USRNAME = String.Empty
        USER_ID = 0
        USER_USERNAME = USER_USERNAME_ORG

        BarButtonItemGhostMode.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
        _Init.InitUserLogin()
        GetBaseData("InactivateGM")
        'LoadNavBar()
        Await Decide_Load(False)
        If GridControlWorkflows.Visible = True And FormOpenClose = False Then RefreshHelper.LoadViewInfo()
    End Sub

    Private Sub GridViewWorkflows_ColumnFilterChanged(sender As Object, e As EventArgs) Handles GridViewWorkflows.ColumnFilterChanged
        Try
            If FormShown = False Or FRONTEND_ACTION <> FA_NONE Then
                Exit Sub
            End If

            Timer_Inactivity_Reset_Disable("GridViewWorkflows.ColumnFilterChanged")
            If DetailLinkActive = False Then
                Create_View_Caption()
            End If

            If GridViewWorkflows.ActiveFilterEnabled Then

            End If
            If Ev_Filter_Panel_Closed = False Then
                Dim oTermFilterActive As String = String.Format("{0} ({1})", S.Filter_aktiv, GridViewWorkflows.DataRowCount)
                If GridViewWorkflows.ActiveFilterString <> String.Empty Then
                    If lblCaptionMainGrid.Text.Contains(oTermFilterActive) Then
                        Ev_Filter_Panel_Closed = False
                    End If

                    ' Caption korrekt setzen: Profil-Titel oder Gesamtübersicht
                    If GRID_LOAD_TYPE.StartsWith("PROFILE#") AndAlso Not String.IsNullOrEmpty(CURRENT_CLICKED_PROFILE_TITLE) Then
                        LOGGER.Debug($"Setting Grid Caption with Profile Title [{CURRENT_CLICKED_PROFILE_TITLE}] and Filter Active Term [{oTermFilterActive}]")
                        lblCaptionMainGrid.Text = String.Format("{0} - {1}", CURRENT_CLICKED_PROFILE_TITLE, oTermFilterActive)
                    Else
                        LOGGER.Debug($"Setting Grid Caption with Gesamtübersicht and Filter Active Term [{oTermFilterActive}]")
                        lblCaptionMainGrid.Text = String.Format("{0} - {1}", S.Gesamtübersicht, oTermFilterActive)
                    End If

                    bsitmCount.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                    bsitmCount.Caption = oTermFilterActive
                Else
                    bsitmCount.Visibility = DevExpress.XtraBars.BarItemVisibility.Never
                    LOGGER.Debug("No active filter - resetting caption to default")
                End If

            End If
            GridLayout_Changed("ColumnFilterChanged")
        Catch ex As Exception
            LOGGER.Error(ex.Message)
        End Try
    End Sub
    Private Sub UpdateGridCaption()
        Try
            LOGGER.Debug($"UpdateGridCaption called - GRID_LOAD_TYPE: [{GRID_LOAD_TYPE}], CURRENT_CLICKED_PROFILE_TITLE: [{CURRENT_CLICKED_PROFILE_TITLE}], NO_WORKFLOWITEMS: [{NO_WORKFLOW_ITEMS}]")
            If GRID_LOAD_TYPE = "OVERVIEW" Then
                ' Übersicht-Caption
                lblCaptionMainGrid.Text = S.Gesamtübersicht

                ' Filter-Info hinzufügen, falls aktiv
                If GridViewWorkflows.ActiveFilterString <> String.Empty Then
                    Dim oTermFilterActive As String = String.Format("{0} ({1})", S.Filter_aktiv, GridViewWorkflows.DataRowCount)
                    lblCaptionMainGrid.Text = String.Format("{0} - {1}", S.Gesamtübersicht, oTermFilterActive)
                End If
            ElseIf GRID_LOAD_TYPE.StartsWith("PROFILE#") Then
                ' Profil-Caption
                If Not String.IsNullOrEmpty(CURRENT_CLICKED_PROFILE_TITLE) Then
                    If NO_WORKFLOW_ITEMS Then
                        lblCaptionMainGrid.Text = String.Format(S.Aktuell_keine_Workflowdaten_vorhanden___0_, CURRENT_CLICKED_PROFILE_TITLE)
                    Else
                        lblCaptionMainGrid.Text = CURRENT_CLICKED_PROFILE_TITLE
                    End If
                End If
            End If

            LOGGER.Debug($"Grid Caption updated: [{lblCaptionMainGrid.Text}]")
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Sub Create_View_Caption()
        UpdateGridCaption()
    End Sub
    Sub Grid_Export()
        XtraSaveFileDialog1.FileName = "Overview.xlsx"
        XtraSaveFileDialog1.DefaultExt = ".xlsx"

        If XtraSaveFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
            Dim oOptions As New XlsxExportOptions() With {
                    .ExportMode = XlsxExportMode.SingleFile
                }
            GridViewWorkflows.ExportToXlsx(XtraSaveFileDialog1.FileName, oOptions)
        End If
    End Sub



    Private Sub TimerInactivity_Tick(sender As Object, e As EventArgs) Handles TimerInactivity.Tick
        Try
            If Application.OpenForms().OfType(Of frmValidator).Any Then
                bsiMessage.Caption = "Validation Active - no Inactivity-Logout"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Timer_Inactivity_Reset_Disable("frmValidator")
                Exit Sub
            End If
            If Application.OpenForms().OfType(Of frmAdministration).Any Then
                bsiMessage.Caption = "Administration Active - no Inactivity-Logout"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Timer_Inactivity_Reset_Disable("frmAdministration")
                Exit Sub
            End If
            If Application.OpenForms().OfType(Of frmAdmin2).Any Then
                bsiMessage.Caption = "Administration2 Active - no Inactivity-Logout"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Timer_Inactivity_Reset_Disable("frmAdmin2")
                Exit Sub
            End If
            If Application.OpenForms().OfType(Of frmMonitor).Any Then
                bsiMessage.Caption = "Monitoring open - no Inactivity-Logout"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Timer_Inactivity_Reset_Disable("frmMonitor")
                Exit Sub
            End If
            If GHOSTMODE_ACTIVE And USER_GHOST_MODE_ACTIVE Then
                bsiMessage.Caption = "GhostMode Active - no Inactivity-Logout"
                bsiMessage.ItemAppearance.Normal.BackColor = Color.Yellow
                bsiMessage.ItemAppearance.Normal.ForeColor = Color.Black
                Timer_Inactivity_Reset_Disable("USER_GHOST_MODE_ACTIVE")
                Exit Sub
            End If
            INACTIVITYRecognized = True

            'Dim omsg As String = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("INACTIVITYRecognized")
            Dim omsg As String = S.Sie_wurden_aufgrund_von_Inaktivität_automatisch_abgemeldet_

            Timer5Mins.Stop()
            TimerRefresh.Stop()
            TimerReminder.Stop()
            LOGGER.Info("Inactivity recognized. Automatic Logout In process!")
            Hide()
            ClassAllgemeineFunktionen.LoginOut("LOGOUT")
            TimerInactivity.Stop()
            MsgBox(omsg, MsgBoxStyle.Information, ADDITIONAL_TITLE)
            Application.Exit()
        Catch ex As Exception
            LOGGER.Error(ex.Message)
        End Try
    End Sub

    Private Sub BarButtonItem3_ItemClick_1(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles SearchItem1.ItemClick
        Try
            Dim oTag = SearchItem1.Tag
            Dim _SPLIT As String()
            _SPLIT = oTag.Split("%")
            Dim oPath = LTrim(RTrim(_SPLIT(0).ToString))
            Dim MyProcess As New Process()
            MyProcess.StartInfo.FileName = oPath
            MyProcess.StartInfo.Arguments = LTrim(RTrim(_SPLIT(1).ToString))
            MyProcess.Start() 'Startet den Prozess
        Catch ex As Exception
            LOGGER.Error(ex.Message)
        End Try


    End Sub

    Private Sub bbtniCW_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtniCW.ItemClick
        Try
            If File.Exists(bbtniCW.Tag) Then
                Dim MyProcess As New Process()
                MyProcess.StartInfo.FileName = bbtniCW.Tag
                MyProcess.Start()
            Else
                LOGGER.Warn($"easyFLOW-Exe Not found [{bbtniCW.Tag}]")
                FormHelper.ShowInfoMessage("Clipboard Watcher could Not be started!", omsgTitleWarning)
            End If

        Catch ex As Exception
            LOGGER.Error(ex.Message)
        End Try
    End Sub

    Private Sub GridViewWorkflows_ColumnPositionChanged(sender As Object, e As EventArgs) Handles GridViewWorkflows.ColumnPositionChanged
        GridLayout_Changed("ColumnPositionChanged")
    End Sub
    Private Sub GridLayout_Changed(oEvent As String)
        If FormShown = False Or Ev_Filter_Panel_Closed Then
            Exit Sub
        End If
        If FRONTEND_ACTION <> FA_NONE Then
            Exit Sub
        End If
        SaveGridLayout()
    End Sub


    Private Sub GridViewWorkflows_EndGrouping(sender As Object, e As EventArgs) Handles GridViewWorkflows.EndGrouping
        GridLayout_Changed("EndGrouping")
    End Sub

    Private Sub bsilastsync_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bsilastsync.ItemClick

    End Sub

    Private Sub GridViewWorkflows_KeyDown(sender As Object, e As KeyEventArgs) Handles GridViewWorkflows.KeyDown
        Dim view As GridView = CType(sender, GridView)
        If e.Control AndAlso e.KeyCode = Keys.C Then
            If view.GetRowCellValue(view.FocusedRowHandle, view.FocusedColumn) IsNot Nothing AndAlso view.GetRowCellValue(view.FocusedRowHandle, view.FocusedColumn).ToString() <> [String].Empty Then
                Clipboard.SetText(view.GetRowCellValue(view.FocusedRowHandle, view.FocusedColumn).ToString())
            End If
            e.Handled = True
        End If
    End Sub

    Private Sub BarCheckItem1_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarCheckItemAutofilter.CheckedChanged
        If GridIsLoaded = True Then
            GridViewWorkflows.OptionsView.ShowAutoFilterRow = BarCheckItemAutofilter.Checked
        End If

    End Sub
    Private Sub BarCheckItem1_CheckedChanged_1(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarCheckItemShowSearch.CheckedChanged
        If GridIsLoaded = True Then
            GridViewWorkflows.OptionsFind.AlwaysVisible = BarCheckItemShowSearch.Checked
        End If
    End Sub

    Private Sub BarButtonItem4_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItem4.ItemClick
        Grid_Layout_Save()
    End Sub
    Sub Grid_Layout_Save()
        FRONTEND_ACTION = "SAVE GRID LAYOUT"
        GridViewWorkflows.OptionsView.ShowViewCaption = False
        GridLayout_Changed("Grid_Layout_Save")
        FRONTEND_ACTION = FA_NONE
    End Sub

    Private Sub BarButtonItem5_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemExportExcel.ItemClick
        Grid_Export()
    End Sub

    Private Sub BarButtonItem6_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItem6.ItemClick
        Grid_Reset_Filter()
    End Sub

    Private Sub BarButtonItem7_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItem7.ItemClick
        GridViewWorkflows.ShowCustomization()
    End Sub

    Private Async Sub BarButtonItem8_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemWFSingle.ItemClick
        Me.Cursor = Cursors.WaitCursor
        Await Item_Scope("CMROW")
        Me.Cursor = Cursors.Default
    End Sub

    Private Async Sub BarButtonItemWFGroup_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemWFGroup.ItemClick
        Me.Cursor = Cursors.WaitCursor
        Await Item_Scope("CMGROUP")
        Me.Cursor = Cursors.Default
    End Sub

    Private Sub BarButtonItemFileLink_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemFileLink.ItemClick
        Dim oReceipiant = ""
        Dim oFocusedDocGUID = GridViewWorkflows.GetFocusedRowCellValue(GridViewWorkflows.Columns("GUID"))
        Dim oSQL = $"Select [dbo].[FNPM_GET_FILEPATH] ({oFocusedDocGUID}, 1)"
        Dim oFilePath = DatabaseFallback.GetScalarValueECM(oSQL)
        If File.Exists(oFilePath) Then
            Dim oLink = "<HTML><body><p><a href=" + "file:///" + oFilePath + ">Link zur Datei</a></p></body></HTML>"
            Dim oLink2 = "<a href=" + "file:///" + oFilePath + ">Link zur Datei</a>"
            If Not IsNothing(oFilePath) Then
                Process.Start($"mailto:{oReceipiant}?subject=Link aus taskFLOW Manager&body={oLink}")
            End If
        End If

    End Sub

    Private Async Sub BarButtonItemMassValidation_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemMassValidation.ItemClick
        Try
            Dim oSelectedRows As Integer() = GridViewWorkflows.GetSelectedRows()
            Dim oHitInfo As GridHitInfo = GridViewWorkflows.CalcHitInfo(GridCursorLocation)
            Dim oSelectedRowHandle As Integer = oHitInfo.RowHandle
            Dim oWorkedFiles As Integer = 0

            Dim oProfileId = 0

            If oSelectedRows.Count = 0 Then
                'Dim omsg = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("MASS_NO_WF_SELECTED")
                Dim omsg = S.Bitte_wählen_Sie_ein_Profil_aus_

                FormHelper.ShowInfoMessage(omsg, omsgTitleWarning)
                Exit Sub
            End If

            oProfileId = GridViewWorkflows.GetRowCellValue(oSelectedRows.Last(), GridViewWorkflows.Columns("PROFILE_ID"))

            If oProfileId = 0 Then
                FormHelper.ShowInfoMessage("Could not select a profile!", omsgTitleWarning)
                Exit Sub
            End If


            If SOURCE_INIT = True Then
                CURRENT_ProfilGUID = oProfileId
                Dim oSQL = $"select * from TBPM_PROFILE_FINAL_INDEXING WITH (NOLOCK) where PROFIL_ID = {CURRENT_ProfilGUID} ORDER BY [SEQUENCE]"

                'CURRENT_DT_FINAL_INDEXING = DataASorDB.GetDatatable("DD_ECM", oSQL, "TBPM_PROFILE_FINAL_INDEXING", $"PROFIL_ID = {CURRENT_ProfilGUID}", "SEQUENCE")
                CURRENT_DT_FINAL_INDEXING = DatabaseFallback.GetDatatable("TBPM_PROFILE_FINAL_INDEXING", New GetDatatableOptions(oSQL, DatabaseType.ECM) With {
                    .FilterExpression = $"PROFIL_ID = {CURRENT_ProfilGUID}",
                    .SortByColumn = "SEQUENCE"
                })

                CURRENT_DT_PROFILE = Nothing '.Clear
                CURRENT_DT_PROFILE = CURRENT_DT_PROFILES.Clone
                Dim oExpression = $"GUID = {CURRENT_ProfilGUID}"
                CURRENT_DT_PROFILES.Select(oExpression).CopyToDataTable(CURRENT_DT_PROFILE, LoadOption.PreserveChanges)
                If CURRENT_DT_PROFILE.Rows.Count = 1 Then
                    CURRENT_ProfilName = CURRENT_DT_PROFILE.Rows(0).Item("NAME")
                    PROFILE_SHOW_DOCUMENT = CURRENT_DT_PROFILE.Rows(0).Item("SHOW_DOCUMENT")
                    PROFILE_NOT_RESP_COMMENT = CURRENT_DT_PROFILE.Rows(0).Item("NOT_RESP_COMMENT")
                    ActiveWorkflowType = 1
                Else
                    Exit Sub
                End If

                CURRENT_PROFILE_LOG_INDEX = CURRENT_DT_PROFILE.Rows(0).Item("PM_VEKTOR_INDEX")
                If CURRENT_PROFILE_LOG_INDEX = "" Then
                    CURRENT_PROFILE_LOG_INDEX = CURRENT_DT_PROFILE.Rows(0).Item("LOG_INDEX")
                End If


                Dim NewDatatable As New DataTable
                NewDatatable.Columns.Add("DocID")
                NewDatatable.Columns.Add("DOC_GUID")
                NewDatatable.Columns.Add("FULL_PATH")

                For Each oRowHandle As Integer In oSelectedRows

                    Dim oDocID = GridViewWorkflows.GetRowCellValue(oRowHandle, "DocID")
                    If IsNothing(oDocID) Then
                        Continue For
                    End If
                    Dim R As DataRow = NewDatatable.NewRow
                    CURRENT_DOC_ID = oDocID
                    Dim DOC_PATH = GridViewWorkflows.GetRowCellValue(oRowHandle, FullFilepatColName)
                    ' CURRENT_DOC_PATH = DOC_PATH
                    CURRENT_DOC_GUID = GridViewWorkflows.GetRowCellValue(oRowHandle, "GUID")
                    R("DocID") = CURRENT_DOC_ID
                    R("FULL_PATH") = DOC_PATH
                    R("DOC_GUID") = GridViewWorkflows.GetRowCellValue(oRowHandle, "GUID")
                    NewDatatable.Rows.Add(R)
                Next

                CURRENT_DT_MASS_CHANGE_DOCS = Nothing
                CURRENT_DT_MASS_CHANGE_DOCS = NewDatatable
                TimerRefresh.Enabled = False
                frmMassValidator.ShowDialog()
                'LoadNavBar()
                Await Decide_Load(False)
            Else
                'Dim oMSG = ClassAllgemeineFunktionen.GUI_LANGUAGE_INFO("MASS_ERROR_WINDREAM")
                Dim oMSG = S.Massenabschluss_konnte_nicht_ausgeführt_werden__weil_windream_nicht_initialisiert_werden_konnte_
                MsgBox(oMSG, MsgBoxStyle.Critical, "Unexpected Error Massvalidation")
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
            MsgBox("Unhandled Error in tsmiMarkedFilesFinish_Click: " & ex.Message)
        End Try
    End Sub

    Private Sub RibbonControl1_SelectedPageChanged(sender As Object, e As EventArgs) Handles RibbonControl1.SelectedPageChanged
        Dim ribbon As RibbonControl = TryCast(sender, RibbonControl)
        Timer_Inactivity_Reset_Disable("RibbonControl1_SelectedPageChanged")
        If ribbon.SelectedPage Is RibbonPageAktionen Then
            If USER_GHOST_MODE_ACTIVE = True And USER_GHOST_MODE_USRNAME <> String.Empty Then
                LOGGER.Debug("Ghostmode is active...")
                bbtnitmLanguage_Change.Enabled = False
            Else
                bbtnitmLanguage_Change.Enabled = True
            End If
            Select Case GridViewItem_Clicked
                Case "GROUP"
                    If SHOW_MASS_VALIDATOR = True Then
                        BarButtonItemMassValidation.Visibility = DevExpress.XtraBars.BarItemVisibility.Always
                    End If
                Case "ROW"
                    '        If selectedRows.Count > 1 Then
                    '            CMFileStart.Enabled = False
                    '        Else
                    '            CMFileStart.Enabled = True
                    '        End If
                    '        If CURRENT_CLICKED_PROFILE_ID > 0 Then
                    '            CMGroupStart.Enabled = True
                    '        End If
            End Select
        End If
    End Sub

    Private Sub barItemGridFontSize_EditValueChanged(sender As Object, e As EventArgs) Handles barItemGridFontSize.EditValueChanged
        Try
            Dim fontDelta As Integer = DirectCast(barItemGridFontSize.EditValue, FontSetting).Value

            ' Schriftgröße im Grid anpassen
            CONFIG.Config.GridFontSizeDelta = fontDelta
            CONFIG.Save()
            GridBuilder.WithFontSizeDelta(fontDelta)

            ' Schriftgröße im TreeList anpassen
            Dim baseFont As Font = TreeList_Cockpit.Appearance.Row.Font
            If baseFont Is Nothing Then
                baseFont = New Font("Segoe UI", 12, FontStyle.Regular)
            End If

            Dim newSize As Single = 12 + fontDelta ' Basis-Größe 12pt
            If newSize < 8 Then newSize = 8 ' Mindestgröße
            If newSize > 20 Then newSize = 20 ' Maximalgröße

            TreeList_Cockpit.Appearance.Row.Font = New Font(baseFont.FontFamily, newSize, FontStyle.Regular)
            TreeList_Cockpit.Appearance.FocusedRow.Font = New Font(baseFont.FontFamily, newSize, FontStyle.Bold)
            TreeList_Cockpit.Appearance.HideSelectionRow.Font = New Font(baseFont.FontFamily, newSize, FontStyle.Regular)

            ' TreeList neu zeichnen
            TreeList_Cockpit.Refresh()

        Catch ex As Exception
        End Try
    End Sub

    Private Sub GridViewWFItems_SelectionChanged(sender As Object, e As DevExpress.Data.SelectionChangedEventArgs) Handles GridViewWorkflows.SelectionChanged
        Timer_Inactivity_Reset_Disable("GridViewWFItems_SelectionChanged")
    End Sub

    Private Sub GridViewWFItems_Click(sender As Object, e As MouseEventArgs) Handles GridViewWorkflows.Click
        Try
            If e.Button = Windows.Forms.MouseButtons.Right Then
                RibbonControl1.SelectedPage = RibbonPageTabelle
            Else
                RibbonControl1.SelectedPage = RibbonPageStart
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Sub frmMain_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
        Try
            'System.Diagnostics.Process.GetCurrentProcess().Kill()
        Catch ex As Exception

        End Try

    End Sub

    Private Sub GridViewWFItems_SubstituteFilter(sender As Object, e As DevExpress.Data.SubstituteFilterEventArgs) Handles GridViewWorkflows.SubstituteFilter
        GridLayout_Changed("GridViewWFItems_SubstituteFilter")

    End Sub

    Private Sub BbtnitmAHWF1_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BbtnitmAHWF1.ItemClick, BbtnitmAHWF2.ItemClick, BbtnitmAHWF3.ItemClick, BbtnitmAHWF4.ItemClick
        Dim obutton As DevExpress.XtraBars.BarButtonItem = TryCast(e.Item, DevExpress.XtraBars.BarButtonItem)
        AdHocWorkflow_BlindFile(obutton.Tag)
    End Sub
    Private Sub AdHocWorkflow_BlindFile(pProfileID As Int16)
        Try
            If Not Application.OpenForms().OfType(Of frmValidator).Any Then
                Dim oExpression = $"GUID = {pProfileID}"
                LOGGER.Debug($"Starting AHWFNoFile for ProfileID: {pProfileID}...")
                CURRENT_DT_PROFILE = Nothing
                CURRENT_DT_PROFILE = CURRENT_DT_PROFILES.Clone
                CURRENT_DT_PROFILES.Select(oExpression).CopyToDataTable(CURRENT_DT_PROFILE, LoadOption.PreserveChanges)
                If CURRENT_DT_PROFILE.Rows.Count = 1 Then
                    CURRENT_ProfilGUID = pProfileID
                    Dim sGUID As String
                    sGUID = System.Guid.NewGuid.ToString()
                    Dim oTargetPath = CURRENT_DT_PROFILE.Rows(0).Item("TARGET_PATH_BLIND_FILE")
                    Dim oSourcePath = CURRENT_DT_PROFILE.Rows(0).Item("WD_SEARCH")
                    Dim oWMObjecttype = CURRENT_DT_PROFILE.Rows(0).Item("WD_OBJECTTYPE")
                    LOGGER.Debug($"oTargetPath: {oTargetPath}")
                    LOGGER.Debug($"oSourcePath: {oSourcePath}")
                    If oTargetPath = String.Empty Or oSourcePath = String.Empty Then
                        LOGGER.Warn($"oTargetPath is nothing - PRofile can not be startet . Check TARGET_PATH_BLIND_FILE Column in Profile")
                        Exit Sub
                    End If
                    oTargetPath = $"{oTargetPath}\{Now.Year}\{Now.Month}\{Now.Day}"
                    oTargetPath = oTargetPath & "\" & sGUID & ".pdf"

                    LOGGER.Debug($"oTargetPath with NowParams: {oTargetPath}")

                    Dim oResult = WINDREAM_MOD.NewFileStream(oSourcePath, oTargetPath, oWMObjecttype)
                    If oResult = True Then
                        WM_AHWF_docPath = oTargetPath
                        Dim oDocID = WINDREAM_MOD.NewDocumentID
                        CURRENT_CLICKED_PROFILE_ID = pProfileID
                        PROFILE_SHOW_DOCUMENT = CURRENT_DT_PROFILE.Rows(0).Item("SHOW_DOCUMENT")
                        CURRENT_CLICKED_PROFILE_TITLE = CURRENT_DT_PROFILE.Rows(0).Item("TITLE")

                        CURRENT_WMObjecttype = CURRENT_DT_PROFILE.Rows(0).Item("WD_OBJECTTYPE")
                        CURRENT_DOC_ID = oDocID
                        CURRENT_DOC_GUID = 99123456789
                        ActiveWorkflowType = ConstAHWorkflow_BlindFile
                        CURRENT_JUMP_DOC_GUID = CURRENT_DOC_GUID
                        DT_FILTERED_PROFILE_SEARCHES_DOC = Nothing
                        DT_FILTERED_PROFILE_SEARCHES_DOC = BASEDATA_DT_PROFILES_SEARCHES_DOC.Copy
                        DT_FILTERED_PROFILE_SEARCHES_DOC.Clear()
                        oExpression = $"PROFILE_ID = {CURRENT_ProfilGUID}"
                        BASEDATA_DT_PROFILES_SEARCHES_DOC.Select(oExpression, "TAB_INDEX").CopyToDataTable(DT_FILTERED_PROFILE_SEARCHES_DOC, LoadOption.PreserveChanges)

                        DT_FILTERED_PROFILE_SEARCHES_DATA = Nothing
                        DT_FILTERED_PROFILE_SEARCHES_DATA = BASEDATA_DT_PROFILES_SEARCHES_DATA.Copy
                        DT_FILTERED_PROFILE_SEARCHES_DATA.Clear()
                        BASEDATA_DT_PROFILES_SEARCHES_DATA.Select(oExpression, "TAB_INDEX").CopyToDataTable(DT_FILTERED_PROFILE_SEARCHES_DATA, LoadOption.PreserveChanges)

                        Try
                            Dim oEnvironment = GetEnvironment()
                            _FormValidator = New frmValidator(oEnvironment)
                            AddHandler _FormValidator.FormClosed, AddressOf ValidatorClosed
                            _FormValidator.Show()
                        Catch ex As Exception
                            LOGGER.Warn($"Error opening Form frmValidator [{ex.Message}]")
                            LOGGER.Warn($"ex.InnerException.Message [{ex.InnerException.Message}]")
                            LOGGER.Warn($"ex.InnerException.Source [{ex.InnerException.Source}]")
                            LOGGER.Error(ex.InnerException)
                            MsgBox(ex.Message, MsgBoxStyle.Critical, ADDITIONAL_TITLE)
                        End Try


                    End If
                Else
                    LOGGER.Info("Attention: CURRENT_DT_PROFILE.Rows.Count <> 1")
                End If

            Else
                FormHelper.ShowInfoMessage(S.Bitte_schließen_Sie_den_offenen_Workflow_, omsgTitleWarning)
                Exit Sub
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Sub bbtnitmLanguage_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles bbtnitmLanguage_Change.ItemClick
        Dim oNForm As New frmLanguage_Select(LOGCONFIG, CONNECTION_STRING_ECM, USER_USERNAME, BASEDATA_DT_LANGUAGE, "TF")
        oNForm.ShowDialog()

        If oNForm.pChanged = True Then
            MsgBox("For the changes to take effect, the program must now be closed. Restart it afterwards.", MsgBoxStyle.Exclamation, "Restart:")
            Me.Close()
        End If
    End Sub

    Private Sub BBtnItmNotfications_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BBtnItmNotfications.ItemClick
        Open_Notifications_Form()
    End Sub

    Private Sub GridViewWFItems_Click(sender As Object, e As EventArgs) Handles GridViewWorkflows.Click

    End Sub

    Private Async Sub BarButtonItem3_ItemClick_2(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemResetLayout.ItemClick
        LOGGER.Info("User clicked reset layout")
        Await GridLayout_Reset(True)
    End Sub

    Private Sub barbtnitmsaveLogfiles_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles barbtnitmsaveLogfiles.ItemClick
        ClassAllgemeineFunktionen.Save_Logfiles()
    End Sub

    Private Async Function ProcessTreeListNodeAsync(oNode As DevExpress.XtraTreeList.Nodes.TreeListNode) As Task
        Try
            Dim oTypeId As Object = oNode.GetValue("TYPE_ID")
            Dim oCockpitConfigID As Object = oNode.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")
            Dim oFkProfileId As Object = oNode.GetValue("FK_PROFILE_ID")
            Dim oSqlQuery As Object = oNode.GetValue("SQL_QUERY")
            Dim oProfileTitle As Object = oNode.GetValue("NAME")

            LOGGER.Debug($"TreeList_Cockpit Node selected - PK_CFG_COCKPIT_DEFINITION_ID:[{oCockpitConfigID}] NAME:[{oProfileTitle}] TYPE_ID:[{oTypeId}] FK_PROFILE_ID:[{oFkProfileId}]")

            If oTypeId Is Nothing OrElse IsDBNull(oTypeId) Then
                LOGGER.Debug("ProcessTreeListNodeAsync: TYPE_ID is Nothing/DBNull - Folder node, skipping")
                Exit Function
            End If

            RibbonPageGroup7.Visible = False

            FRONTEND_ACTION = NAVBAR_CLICKED
            Timer_Inactivity_Reset_Disable("TreeList1_FocusedNodeChanged")
            COCKPIT_CONFIG_ID = oCockpitConfigID
            COCKPIT_PROFILE_SQL = String.Empty
            Dim oTypeIdInt As Integer = CInt(oTypeId)

            If oTypeIdInt = 0 Or oTypeId = 1 Then
                If Application.OpenForms().OfType(Of frmValidator).Any Then
                    FormHelper.ShowInfoMessage(S.Bitte_schließen_Sie_den_offenen_Workflow_, omsgTitleWarning)
                    Exit Function
                End If
            End If




                Select Case oTypeIdInt

                Case 0
                    LOGGER.Debug("TreeList_Cockpit: Loading overview")
                    OverviewOrDEtail = "OVERVIEW"
                    GRID_LOAD_TYPE = "OVERVIEW"

                    Dim oForce As Boolean = False
                    If DetailLinkActive = True Then
                        oForce = True
                        DetailLinkActive = False
                        OVERVIEW_ADDED_WHEN = ""
                    End If
                    If IsDBNull(oSqlQuery) OrElse String.IsNullOrWhiteSpace(oSqlQuery?.ToString()) Then
                        LOGGER.Warn($"TreeList_Cockpit: SQL_QUERY for ProfileID {oFkProfileId} is DBNull or empty for overview node - this should not happen, check data integrity of TreeList's DataSource")
                        Exit Function
                    Else
                        LOGGER.Debug($"TreeList_Cockpit: Overview SQL query to be used: [{oSqlQuery}]")
                    End If
                    ' ✅ NEU: Verifizieren Sie die Zuweisung
                    LOGGER.Debug($"TreeList_Cockpit: COCKPIT_PROFILE_SQL after assignment: [{COCKPIT_PROFILE_SQL}]")
                    LOGGER.Debug($"TreeList_Cockpit: COCKPIT_PROFILE_SQL.Length = [{COCKPIT_PROFILE_SQL.Length}]")
                    CURRENT_CLICKED_PROFILE_ID = 0
                    CUSTOM_OVERVIEW_SQL = oSqlQuery.ToString()
                    _lastUsedOverviewSQL = CUSTOM_OVERVIEW_SQL  ' ← SQL merken BEVOR es gelöscht wird

                    If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                        RefreshHelper.SaveViewInfo()
                    End If

                    Me.Cursor = Cursors.WaitCursor
                    Try
                        Await Decide_Load(False, oForce)
                    Finally
                        Me.Cursor = Cursors.Default
                    End Try
                    ' ✅ CUSTOM_OVERVIEW_SQL erst HIER leeren – nach dem kompletten Lade-Zyklus inkl. internem GridLayout_Reset
                    LOGGER.Debug("TreeList_Cockpit: Clearing CUSTOM_OVERVIEW_SQL after loading overview")
                    CUSTOM_OVERVIEW_SQL = String.Empty
                    If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                        RefreshHelper.LoadViewInfo()
                    End If

                    If GridViewWorkflows.GroupCount = 0 AndAlso Not IsNothing(GridViewWorkflows.Columns("GROUP_TEXT")) Then
                        LOGGER.Info("TreeList_Cockpit: NO GROUPS AFTER CLICK OVERVIEW - creating groups...")
                        Await Decide_Load(False, True)
                        If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                            RefreshHelper.LoadViewInfo()
                        End If
                    End If
                    RibbonPageGroup7.Visible = True
                Case 1
                    If oFkProfileId Is Nothing OrElse IsDBNull(oFkProfileId) Then
                        LOGGER.Warn("TreeList_Cockpit: TYPE_ID=1 but FK_PROFILE_ID is Nothing/DBNull")
                        Exit Function
                    End If

                    Dim oProfileId As Integer = CInt(oFkProfileId)
                    LOGGER.Debug($"TreeList_Cockpit: Profile node clicked - FK_PROFILE_ID:[{oProfileId}]")
                    If CURRENT_CLICKED_PROFILE_ID = oProfileId Then
                        LOGGER.Debug($"TreeList_Cockpit: Profile [{oProfileId}] is already active - ignoring click")
                        Exit Function
                    End If

                    LOGGER.Debug($"TreeList_Cockpit: Loading profile with ID [{oProfileId}]...")

                    If IsDBNull(oSqlQuery) OrElse String.IsNullOrWhiteSpace(oSqlQuery?.ToString()) Then
                        LOGGER.Warn($"TreeList_Cockpit: SQL_QUERY for ProfileID {oFkProfileId} is DBNull or empty for Profile-Node - this should not happen, check data integrity of TreeList's DataSource")
                        Exit Function
                    Else
                        LOGGER.Debug($"TreeList_Cockpit: Profile-SQL query to be used: [{oSqlQuery}]")
                    End If
                    COCKPIT_PROFILE_SQL = oSqlQuery.ToString()
                    ' ===== ANZAHL-SUFFIX ENTFERNEN (von AppendCountsToTreeAsync angehängt: "Titel (42)" → "Titel") =====
                    Dim oCleanProfileTitle As String = oProfileTitle?.ToString()
                    Dim oSuffixMatch = System.Text.RegularExpressions.Regex.Match(oCleanProfileTitle, "^(.*)\s+\(\d+\)$")
                    If oSuffixMatch.Success Then
                        oCleanProfileTitle = oSuffixMatch.Groups(1).Value.Trim()
                        LOGGER.Debug($"TreeList_Cockpit: Stripped count suffix from title [{oProfileTitle}] → [{oCleanProfileTitle}]")
                    End If

                    OverviewOrDEtail = "DETAIL"
                    CURRENT_CLICKED_PROFILE_ID = oProfileId
                    CURRENT_CLICKED_PROFILE_TITLE = oCleanProfileTitle
                    GRID_LOAD_TYPE = $"PROFILE#{oProfileId}"
                    DetailLinkActive = True

                    If GridControlWorkflows.Visible = True And FormOpenClose = False Then
                        RefreshHelper.SaveViewInfo()
                    End If

                    Me.Cursor = Cursors.WaitCursor
                    Try
                        Await Decide_Load(False, True)
                    Finally
                        Me.Cursor = Cursors.Default
                    End Try

                Case 2
                    Dim oMONITOR_ID As Object = oNode.GetValue("FK_MONITOR_ID")
                    If oMONITOR_ID Is Nothing OrElse IsDBNull(oMONITOR_ID) Then
                        LOGGER.Warn($"TreeList_Cockpit: TYPE_ID=2 but FK_MONITOR_ID is Nothing/DBNull - PK_CFG_COCKPIT_DEFINITION_ID:[{oCockpitConfigID}]")
                        Exit Function
                    End If

                    Dim oMonitorIdInt As Integer = CInt(oMONITOR_ID)

                    ' Prüfen ob bereits ein Monitor mit dieser ID geöffnet ist
                    Dim existingMonitor = Application.OpenForms().OfType(Of frmMonitor)().FirstOrDefault(Function(f) f.MonitorID = oMonitorIdInt)
                    If existingMonitor IsNot Nothing Then
                        LOGGER.Debug($"TreeList_Cockpit: Monitor with ID [{oMonitorIdInt}] is already open - bringing to front")
                        existingMonitor.Activate()
                        existingMonitor.BringToFront()
                        Exit Function
                    End If

                    COCKPIT_MONITOR_ID = oMonitorIdInt
                    COCKPIT_MONITOR_CAPTION = oNode.GetValue("NAME")

                    ' ✅ KEIN Overlay bei Monitor-Öffnung
                    ' Overlay nur bei Datenlade-Operationen (Case 0, 1)

                    Me.Cursor = Cursors.WaitCursor
                    Try
                        Dim newMonitor As New frmMonitor(oMonitorIdInt)
                        newMonitor.Show()
                        newMonitor.Activate()
                        newMonitor.BringToFront()
                    Finally
                        Me.Cursor = Cursors.Default
                    End Try
                Case 3
                    Dim oCHART_ID As Object = oNode.GetValue("FK_CHART_ID")
                    If oCHART_ID Is Nothing OrElse IsDBNull(oCHART_ID) Then
                        LOGGER.Warn($"TreeList_Cockpit: TYPE_ID=3 but FK_CHART_ID is Nothing/DBNull - PK_CFG_COCKPIT_DEFINITION_ID:[{oCockpitConfigID}]")
                        Exit Function
                    End If
                    COCKPIT_CHART_ID = oCHART_ID

                    ' ✅ KEIN Overlay bei Dashboard (verhindert Fokus-Raub)
                    Me.Cursor = Cursors.WaitCursor
                    Try
                        ' ===== SCHRITT 1: Dashboard öffnen/referenzieren =====
                        Dim dashboardForm As frmInvDashboard

                        If Application.OpenForms().OfType(Of frmInvDashboard).Any Then
                            ' Dashboard ist bereits offen
                            dashboardForm = Application.OpenForms().OfType(Of frmInvDashboard).First()
                            LOGGER.Debug("TreeList_Cockpit: Dashboard already open - reusing existing instance")
                        Else
                            ' Dashboard neu öffnen
                            dashboardForm = New frmInvDashboard()
                            dashboardForm.Show()
                            LOGGER.Debug("TreeList_Cockpit: Dashboard opened new instance")
                        End If

                        ' ===== SCHRITT 2: Garantierte Vordergrund-Aktivierung =====
                        ' TopMost temporär setzen (wird sofort wieder entfernt)
                        dashboardForm.TopMost = True
                        dashboardForm.TopMost = False

                        ' Aktivieren und Fokus setzen
                        dashboardForm.Activate()
                        dashboardForm.BringToFront()
                        dashboardForm.Focus()

                        ' ===== SCHRITT 3: Windows-API als Fallback (optional) =====
                        ' Falls DevExpress hartnäckig ist
                        NativeMethods.SetForegroundWindow(dashboardForm.Handle)

                    Finally
                        Me.Cursor = Cursors.Default
                    End Try

                Case Else
                    LOGGER.Warn($"ProcessTreeListNodeAsync: Unhandled TYPE_ID [{oTypeIdInt}] - PK_CFG_COCKPIT_DEFINITION_ID:[{oCockpitConfigID}]")

            End Select

        Catch ex As Exception
            LOGGER.Error(ex)
        Finally
            FRONTEND_ACTION = FA_NONE
        End Try
    End Function
    Private Async Sub TreeList1_FocusedNodeChanged(sender As Object, e As DevExpress.XtraTreeList.FocusedNodeChangedEventArgs) Handles TreeList_Cockpit.FocusedNodeChanged
        Try
            If e.Node Is Nothing Then
                LOGGER.Debug("TreeList1_FocusedNodeChanged: Node is Nothing - skipping")
                Exit Sub
            End If

            If FormShown = False Then
                LOGGER.Debug("TreeList1_FocusedNodeChanged: Form not shown - skipping")
                Exit Sub
            End If
            LOGGER.Debug("TreeList1_FocusedNodeChanged: Node changed - processing")
            Await ProcessTreeListNodeAsync(e.Node)

        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Async Sub TreeList_Cockpit_Click(sender As Object, e As EventArgs) Handles TreeList_Cockpit.Click
        Try
            Dim oFocusedNode As DevExpress.XtraTreeList.Nodes.TreeListNode = TreeList_Cockpit.FocusedNode
            If oFocusedNode Is Nothing Then Exit Sub

            Dim oTypeId As Object = oFocusedNode.GetValue("TYPE_ID")
            If oTypeId Is Nothing OrElse IsDBNull(oTypeId) OrElse CInt(oTypeId) <> 2 Then
                Exit Sub
            End If

            ' ===== PRÜFEN OB MONITOR BEREITS GEÖFFNET IST =====
            Dim oMonitorId As Object = oFocusedNode.GetValue("FK_MONITOR_ID")
            If oMonitorId Is Nothing OrElse IsDBNull(oMonitorId) Then
                Exit Sub
            End If

            Dim oMonitorIdInt As Integer = CInt(oMonitorId)
            Dim existingMonitor = Application.OpenForms().OfType(Of frmMonitor)().FirstOrDefault(Function(f) f.MonitorID = oMonitorIdInt)

            If existingMonitor IsNot Nothing Then
                ' ✅ Monitor ist offen → Nach vorne bringen
                LOGGER.Debug($"TreeList_Cockpit_NodeCellClick: Monitor [{oMonitorIdInt}] already open - bringing to front")
                existingMonitor.Activate()
                existingMonitor.BringToFront()
            Else
                ' ✅ Monitor ist geschlossen → Neu öffnen via ProcessTreeListNodeAsync
                LOGGER.Debug($"TreeList_Cockpit_NodeCellClick: Monitor [{oMonitorIdInt}] closed - reopening")
                Await ProcessTreeListNodeAsync(oFocusedNode)
            End If
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub
    Private Sub BarButtonItemCock_refresh_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles BarButtonItemCock_refresh.ItemClick
        Load_Treeview()
    End Sub

    Private Sub Bchkitm_load_empty_wf_CheckedChanged(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles Bchkitm_load_empty_wf.CheckedChanged
        If FormShown = False Then
            Exit Sub
        End If
        CONFIG.Config.Hide_Empty_Workflows = Bchkitm_load_empty_wf.Checked
        CONFIG.Save()
    End Sub

    Private Sub Bchkitm_load_empty_wf_ItemClick(sender As Object, e As DevExpress.XtraBars.ItemClickEventArgs) Handles Bchkitm_load_empty_wf.ItemClick
        Decide_Show_Empty_Workflows(Not Bchkitm_load_empty_wf.Checked)
    End Sub
    Sub Decide_Show_Empty_Workflows(pShow As Boolean)
        Try
            LOGGER.Debug($"Decide_Show_Empty_Workflows: pShow=[{pShow}], cached node counts: [{_treeNodeCounts.Count}]")
            TreeList_Cockpit.BeginUpdate()
            Try
                TreeList_Cockpit.NodesIterator.DoOperation(
                    Sub(oNode As DevExpress.XtraTreeList.Nodes.TreeListNode)
                        Dim oPk As Object = oNode.GetValue("PK_CFG_COCKPIT_DEFINITION_ID")

                        If oPk Is Nothing OrElse IsDBNull(oPk) Then
                            oNode.Visible = True
                            LOGGER.Debug($"Decide_Show_Empty_Workflows: oPk is Nothing/DBNull - Node visible set to True")
                            Exit Sub
                        End If

                        Dim oPkInt As Integer = CInt(oPk)

                        If Not _treeNodeCounts.ContainsKey(oPkInt) Then
                            oNode.Visible = True
                            LOGGER.Debug($"Decide_Show_Empty_Workflows: oPkInt [{oPkInt}] not found in _treeNodeCounts - Node visible set to True")
                            Exit Sub
                        End If

                        oNode.Visible = pShow OrElse (_treeNodeCounts(oPkInt) > 0)
                    End Sub)
            Finally
                TreeList_Cockpit.EndUpdate()
            End Try
            TreeList_Cockpit.Refresh()
        Catch ex As Exception
            LOGGER.Error(ex)
        End Try
    End Sub

    Private Async Sub TreeList_Cockpit_DoubleClick(sender As Object, e As EventArgs) Handles TreeList_Cockpit.DoubleClick
        Try
            Dim oFocusedNode As DevExpress.XtraTreeList.Nodes.TreeListNode = TreeList_Cockpit.FocusedNode
            If oFocusedNode Is Nothing Then
                LOGGER.Debug("TreeList_Cockpit_DoubleClick: No focused node")
                Exit Sub
            End If

            Dim oTypeId As Object = oFocusedNode.GetValue("TYPE_ID")
            If oTypeId Is Nothing OrElse IsDBNull(oTypeId) Then
                LOGGER.Debug("TreeList_Cockpit_DoubleClick: TYPE_ID is Nothing/DBNull - skipping")
                Exit Sub
            End If

            Dim oTypeIdInt As Integer = CInt(oTypeId)

            ' Nur bei Profil-Knoten (TYPE_ID = 1) Validator öffnen
            If oTypeIdInt = 1 Then
                Dim oFkProfileId As Object = oFocusedNode.GetValue("FK_PROFILE_ID")
                If oFkProfileId Is Nothing OrElse IsDBNull(oFkProfileId) Then
                    LOGGER.Warn("TreeList_Cockpit_DoubleClick: TYPE_ID=1 but FK_PROFILE_ID is Nothing/DBNull")
                    Exit Sub
                End If

                Dim oProfileId As Integer = CInt(oFkProfileId)
                LOGGER.Debug($"TreeList_Cockpit_DoubleClick: Opening validator for profile ID [{oProfileId}]")

                ' ===== PROFIL-DATEN INS GRID LADEN (FALLS NOCH NICHT GELADEN) =====
                ' Wenn das Grid aktuell leer ist oder ein anderes Profil zeigt, müssen wir erst laden
                If GRID_LOAD_TYPE <> $"PROFILE#{oProfileId}" OrElse DT_CURR_WF_ITEMS Is Nothing OrElse DT_CURR_WF_ITEMS.Rows.Count = 0 Then
                    LOGGER.Debug($"TreeList_Cockpit_DoubleClick: Grid does not show profile [{oProfileId}] - loading it first")

                    CURRENT_CLICKED_PROFILE_ID = oProfileId

                    ' Profil-Titel setzen (ohne Count-Suffix)
                    Dim oProfileTitle As Object = oFocusedNode.GetValue("NAME")
                    Dim oCleanProfileTitle As String = oProfileTitle?.ToString()
                    Dim oSuffixMatch = System.Text.RegularExpressions.Regex.Match(oCleanProfileTitle, "^(.*)\s+\(\d+\)$")
                    If oSuffixMatch.Success Then
                        oCleanProfileTitle = oSuffixMatch.Groups(1).Value.Trim()
                    End If
                    CURRENT_CLICKED_PROFILE_TITLE = oCleanProfileTitle

                    GRID_LOAD_TYPE = $"PROFILE#{oProfileId}"

                    ' Profil-Daten laden
                    Await Decide_Load(False, True)

                    ' Warten bis DT_CURR_WF_ITEMS gefüllt ist
                    If DT_CURR_WF_ITEMS Is Nothing OrElse DT_CURR_WF_ITEMS.Rows.Count = 0 Then
                        LOGGER.Warn($"TreeList_Cockpit_DoubleClick: No workflow items found for profile [{oProfileId}]")
                        Dim omsg = String.Format(S.Aktuell_keine_Workflowdaten_vorhanden___0_, oCleanProfileTitle)
                        FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                        Exit Sub
                    End If
                End If

                ' ===== DOCIDS AUS DT_CURR_WF_ITEMS SAMMELN =====
                Dim oIds As New List(Of Integer)

                If DT_CURR_WF_ITEMS IsNot Nothing AndAlso DT_CURR_WF_ITEMS.Columns.Contains("DocID") Then
                    For Each oRow As DataRow In DT_CURR_WF_ITEMS.Rows
                        Dim oDocId As Object = oRow("DocID")
                        If oDocId IsNot Nothing AndAlso IsNumeric(oDocId) Then
                            oIds.Add(CInt(oDocId))
                        End If
                    Next

                    LOGGER.Debug($"TreeList_Cockpit_DoubleClick: Collected [{oIds.Count}] DocIDs from DT_CURR_WF_ITEMS")
                Else
                    LOGGER.Warn("TreeList_Cockpit_DoubleClick: DT_CURR_WF_ITEMS is Nothing or has no DocID column")
                    Exit Sub
                End If

                ' ===== VALIDIERUNG: MINDESTENS 1 WORKFLOW =====
                If oIds.Count = 0 Then
                    Dim omsg = String.Format(S.System_konnte_die_Profilworkflows_nicht_auswerten_, vbNewLine)
                    FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                    Exit Sub
                End If

                ' ===== VALIDIERUNG: MAXIMUM 1000 WORKFLOWS =====
                If oIds.Count > 1000 Then
                    Dim omsg = "You chose more than 1000 Workflows. Please select fewer items."
                    FormHelper.ShowInfoMessage(omsg, omsgTitleAttention)
                    Exit Sub
                End If

                ' ===== DB-OPERATIONEN: TABELLE LEEREN UND NEU BEFÜLLEN =====
                LOGGER.Debug("TreeList_Cockpit_DoubleClick: Cleaning up queued DocIds...")
                Dim oDelete = $"DELETE FROM TBPM_VALIDATION_PROFILE_GROUP_USER WHERE UserID = {USER_ID}"

                If DatabaseFallback.ExecuteNonQueryECM(oDelete) = True Then
                    LOGGER.Debug($"TreeList_Cockpit_DoubleClick: Adding [{oIds.Count}] queued DocIds...")

                    Dim oInsertBatch As New System.Text.StringBuilder()
                    oInsertBatch.AppendLine("INSERT INTO TBPM_VALIDATION_PROFILE_GROUP_USER ([PROFIL_ID],[DocID],[UserID],[ADDED_WHO]) VALUES")

                    For i As Integer = 0 To oIds.Count - 1
                        If i > 0 Then oInsertBatch.Append(",")
                        oInsertBatch.AppendLine($"({oProfileId},{oIds(i)},{USER_ID},'{USER_USERNAME}')")
                    Next

                    LOGGER.Debug($"TreeList_Cockpit_DoubleClick: Batch-Insert SQL: {oInsertBatch.ToString()}")
                    DatabaseFallback.ExecuteNonQueryECM(oInsertBatch.ToString())
                End If

                ' ===== VALIDATOR IM GRUPPEN-MODUS ÖFFNEN =====
                CURRENT_ProfilGUID = oProfileId
                CURRENT_CLICKED_PROFILE_ID = oProfileId

                ' Profil-Titel setzen (ohne Count-Suffix)
                Dim oProfileTitle2 As Object = oFocusedNode.GetValue("NAME")
                Dim oCleanProfileTitle2 As String = oProfileTitle2?.ToString()
                Dim oSuffixMatch2 = System.Text.RegularExpressions.Regex.Match(oCleanProfileTitle2, "^(.*)\s+\(\d+\)$")
                If oSuffixMatch2.Success Then
                    oCleanProfileTitle2 = oSuffixMatch2.Groups(1).Value.Trim()
                End If
                CURRENT_CLICKED_PROFILE_TITLE = oCleanProfileTitle2

                ' ===== WICHTIG: KEIN spezifisches Dokument laden (wie bei CMGROUP) =====
                CURRENT_JUMP_DOC_GUID = 0
                CURRENT_DOC_GUID = 0

                ' Cursor setzen
                Me.Cursor = Cursors.WaitCursor
                Try
                    ' ===== DIREKTER AUFRUF OHNE GRID-KONTEXT =====
                    ' Load_Profil_from_Grid öffnet den Validator im Gruppen-Modus
                    Load_Profil_from_Grid(oProfileId)
                Finally
                    Me.Cursor = Cursors.Default
                End Try
            Else
                LOGGER.Debug($"TreeList_Cockpit_DoubleClick: TYPE_ID=[{oTypeIdInt}] - no action for double-click")
            End If

        Catch ex As Exception
            LOGGER.Error(ex)
            Me.Cursor = Cursors.Default
        End Try
    End Sub

    ' ===== AM ENDE DER DATEI (vor "End Class") =====
    Friend NotInheritable Class NativeMethods
        <DllImport("user32.dll")>
        Public Shared Function SetForegroundWindow(hWnd As IntPtr) As Boolean
        End Function

        <DllImport("user32.dll")>
        Public Shared Function ShowWindow(hWnd As IntPtr, nCmdShow As Integer) As Boolean
        End Function

        Public Const SW_RESTORE As Integer = 9
    End Class

End Class