# (c) Didier  LECLERC 2024 CHARGE D'ETUDES GEOMATIQUES MTE-MCTRCT/SG/DNUM/MSP/DS/GSG/PMIRG Site de Rouen
# créé sept 2024 

from qgis.PyQt import QtCore, QtGui, QtWidgets

from qgis.PyQt.QtWidgets import (QAction, QMenu , QMenuBar, QMessageBox, QFileDialog, QApplication, QDialog,
                             QTabWidget, QWidget, QSizePolicy, 
                             QTreeWidget, QTabWidget, QAbstractItemView, QTreeWidgetItemIterator, QTreeWidgetItem, QHeaderView, QComboBox, 
                             QRadioButton)

from qgis.PyQt.QtGui import ( QFont, QIcon, QColor, QCursor, QPainter, QPixmap, QTextDocument, QRegularExpressionValidator, QStandardItemModel, QStandardItem, QPageSize, QPageLayout, QFontMetrics )
from html import escape
from qgis.gui  import (  QgsCollapsibleGroupBox )
from qgis.core import ( Qgis, QgsApplication )

from qgireferentiels.bibli_qgireferentiels import ( 
                                                  returnVersion, returnAndSaveDialogParam, resizeIhm, returnIcon, genereButtonActionColor, functionFont, zMyFrenchMonth, displayMess, 
                                                  functionSavePerso, execPdf, myIconFormat, genereLabelWithDict, genereButtonWithDict, functionOpenPathReferentiel, functionDeletePathReferentiel, 
                                                  returnNombreOccurence, analyseXml, analyseXmResource, analyseXmSubResource, analyseXmDownload, analyseXmlDistribution, get_and_read_xml, 
                                                  updateLibelleQCheckBoxSelectObjets, find_private, isExisteKeyPrivateGPF, createFolder, mappingIsoTreeDistributionTreePanier,
                                                  ManagerPatienter, ManagerLog, ManagerLogPostgreSQL, find_psql
                                                  ) 

from qgis.PyQt.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog

from qgis.core import ( Qgis, QgsSettings )
from qgis.PyQt.QtCore    import ( Qt, QRegularExpression, QMarginsF )

import qgis  


import requests
import os
from contextlib import contextmanager
import time
import re
import math
import copy
import platform
from datetime import datetime
from pathlib import Path
import xml.etree.ElementTree as ET

from qgireferentiels.api.apiqgireferentiels       import ( GeoIdeDistribution )
from qgireferentiels.config                       import ( VALUEDEFAUTFILEHELP, VALUEDEFAUTFILEHELPPDF, VALUEDEFAUTFILEHELPHTML, URL_API_GPF, URL_API_GPF_PRIVATE, HTTP_PROXY_GPF, URL_CATALOGUE_DISTRIBUTION, 
                                                           URL_STATISTIQUES_DISTRIBUTION_FILE, HTTP_PROXY_GI_DISTRIBUTION, 
                                                           PP_BASE, PP_USER, PP_PASSWORD, PP_HOST, PP_PORT, PP_SCHEMA, PP_TABLE
                                                          )
from qgireferentiels.qgireferentiels_referentiels import (QGIREFERENTIELS_REFERENTIEL, QGIREFERENTIELS_REGROUPEMENT, GI_GPF_REGROUPEMENT)

class Ui_Dialog_qgireferentiels(object):
    def __init__(self):
        self.iface = qgis.utils.iface                                                          
        try:
           from qgis.PyQt.QtCore import QT_VERSION_STR
           from qgis.PyQt.QtCore import PYQT_VERSION_STR
           self._version_Qgis = qgis.utils.Qgis.QGIS_VERSION
           self._version_PyQt = PYQT_VERSION_STR
           self._version_Qt   = QT_VERSION_STR

        except ImportError:
           self._version_Qgis = ""
           self._version_PyQt = ""
           self._version_Qt   = ""

    def setupUi(self, Dialog, _qgireferentiels, _qgireferentielsToolBar):
        self.Dialog = Dialog
        self._qgireferentiels            = _qgireferentiels
        self._qgireferentielsToolBar     = _qgireferentielsToolBar
        # === GEstion Ok ou KO téléchargement lancé
        self.Dialog.downloadEnCours = False
        
        Dialog.setObjectName("Dialog")
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        #-
        mDic_LH = returnAndSaveDialogParam(self, "Load")
        self.mDic_LH = mDic_LH

        self.dicListLettre      = { 0:"QTabWidget", 1:"ColorTarget", 2:"ColorQSPlitter"}
        self.dicListLettreLabel = { 0:QtWidgets.QApplication.translate("qgidistribution_ui", "Tab"), 1:QtWidgets.QApplication.translate("qgidistribution_ui", "Color Target"), 2:QtWidgets.QApplication.translate("qgidistribution_ui", "Color QSPlitter") 
                                  }
        #--
        self.lScreenDialog, self.hScreenDialog = int(self.mDic_LH["dialogLargeur"]), int(self.mDic_LH["dialogHauteur"])
        self.displayMessage       = False if self.mDic_LH["displayMessage"] == 'dialogTitle' else True #Qmessage box (dialogBox) ou barre de progression (dialogTitle)
        self.fileHelp             = VALUEDEFAUTFILEHELP      #Type Fichier Help
        self.fileHelpPdf          = VALUEDEFAUTFILEHELPPDF   #Fichier Help  PDF
        self.fileHelpHtml         = VALUEDEFAUTFILEHELPHTML  #Fichier Help  HTML
        self.URL_API_GPF          = URL_API_GPF              #Url Api GPF
        self.URL_API_GPF_PRIVATE  = URL_API_GPF_PRIVATE              #Url Api GPF
        
        self.HTTP_PROXY_GPF       = HTTP_PROXY_GPF           #Proxy HTTP
        self.HTTPS_PROXY_GPF      = HTTP_PROXY_GPF           #Proxy HTTPS
        self.HTTP_PROXY_GI_DISTRIBUTION  = HTTP_PROXY_GI_DISTRIBUTION           #Proxy HTTP_PROXY_GI_DISTRIBUTION
        self.HTTPS_PROXY_GI_DISTRIBUTION = HTTP_PROXY_GI_DISTRIBUTION           #Proxy HTTP_PROXY_GI_DISTRIBUTION

        self.PP_BASE              = PP_BASE
        self.PP_USER              = PP_USER
        self.PP_PASSWORD          = PP_PASSWORD
        self.PP_HOST              = PP_HOST
        self.PP_PORT              = PP_PORT
        self.PP_SCHEMA            = PP_SCHEMA
        self.PP_TABLE             = PP_TABLE
        self.PP_PASSWORD          = PP_PASSWORD
        
        self.urlCatalogueDistribution = URL_CATALOGUE_DISTRIBUTION
        _pathUser                     = QgsApplication.qgisSettingsDirPath().replace("\\","/") + "qgireferentiels/log"
        createFolder(_pathUser)
        self.urlStatistiquesDistribution = _pathUser + "/" + URL_STATISTIQUES_DISTRIBUTION_FILE        
        #--
        self.colorDefaut                      = self.mDic_LH["defaut"]                      #Color QGroupBox
        self.colorQGroupBox                   = self.mDic_LH["QGroupBox"]                   #Color QGroupBox
        self.colorQTabWidget                  = self.mDic_LH["QTabWidget"]                  #Color QTabWidget
        self.policeQGroupBox                  = self.mDic_LH["QGroupBoxPolice"]             #Police QGroupBox
        self.labelBackGround                  = self.mDic_LH["QLabelBackGround"]            #Fond Qlabel
        self.colorQSPlitter                   = self.mDic_LH["ColorQSPlitter"]              #Color QSPlitter
        self.mDownLotDirect                   = True if self.mDic_LH["zoneDownLotDirect"]  in (True, "true") else False # Pagination
        self.mZoneValuePathReferentiel        = self.mDic_LH["valuePathReferentiel"]
        self.mZoneValuePathReferentielList    = self.mDic_LH["valuePathReferentielList"]
        self.mValueOrganisation               = self.mDic_LH["valueOrganisation"]   
        self.durationBarInfo                  = int(self.mDic_LH["durationBarInfo"])  #durée d'affichage des messages d'information
        self.mDateDerniere                    = True if self.mDic_LH["zoneDateDerniere"]  in (True, "true") else False
        self.mDateDerniere                    = True if self.mDic_LH["zoneDateDerniere"]  in (True, "true") else False
        self.mZoneRadioDate                   = True if self.mDic_LH["zoneRadioDate"]  in (True, "true") else False

        self.listQComboBoxProxy               = [ "Pas de proxy", "Configuration QGIS", "Personnaliser" ]

        self.mValueLoginGI              = self.mDic_LH["valueLoginGI"] 
        self.mValueMdpGI                = self.mDic_LH["valueMdpGI"]   
        self.selectQComboBox_GI_Proxy   = int(self.mDic_LH["selectQComboBox_GI_Proxy"])       
        self.label_GI_Proxy             = self.mDic_LH["label_GI_Proxy"]
        self.mArchiveBrut               = True if self.mDic_LH["selectArchiveBrute"]   in (True, "true") else False # Archive Brute

        self.mValueLoginGPF             = self.mDic_LH["valueLoginGPF"] 
        self.mValueMdpGPF               = self.mDic_LH["valueMdpGPF"]   
        self.selectQComboBox_GPF_Proxy  = int(self.mDic_LH["selectQComboBox_GPF_Proxy"])      
        self.label_GPF_Proxy            = self.mDic_LH["label_GPF_Proxy"]       
        self.mPaging                    = True if self.mDic_LH["selectPagination"]   in (True, "true") else False # Pagination

        self.valueRadioPath             = int(self.mDic_LH["valueRadioPath"])       
        self.valueRadioPathZone         =     self.mDic_LH["valueRadioPathZone"]     

        self.valueFavoriFilter          =     self.mDic_LH["valueFavoriFilter"]
        #---
        self.messWindowTitle = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS (Interface for the Géoplateforme API)", None) + "  (" + str(returnVersion()) + ")" 
        Dialog.setWindowTitle(self.messWindowTitle)
        Dialog.setWindowModality(Qt.WindowModality.WindowModal)
        Dialog.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowMaximizeButtonHint | Qt.WindowType.WindowCloseButtonHint | Qt.WindowType.WindowMinimizeButtonHint)
        Dialog.resize(QtCore.QSize(self.lScreenDialog, self.hScreenDialog))
        Dialog.setSizeGripEnabled(True)
 
        _pathIcons = os.path.dirname(__file__) + "/icons/logo"
        iconSource                     = _pathIcons + "/qgireferentiels.png"
        iconSourceTooltip              = _pathIcons + "/qgireferentiels.png"
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(iconSource), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
        Dialog.setWindowIcon(icon)
        
        # Important de n'utiliser qu'une fois à l'ouverture après plus de splitterfiltre
        self._firstSplitterfiltre       = True
        self._firstSplitterfiltreAction = True
        #-
        self.groupBox_bandeau = QtWidgets.QGroupBox(self.Dialog)
        self.groupBox_bandeau.setGeometry(QtCore.QRect(10,10,self.lScreenDialog - 20, 90))
        self.groupBox_bandeau.setObjectName("groupBox_bandeau")
        self.groupBox_bandeau.setStyleSheet("QGroupBox { border: 0px solid red }")
        #-
        self.layout_bandeau = QtWidgets.QHBoxLayout()
        self.layout_bandeau.setContentsMargins(0, 0, 0, 0)
        self.groupBox_bandeau.setLayout(self.layout_bandeau)
        #----------
        self.labelImage = QtWidgets.QLabel()
        _pathIcons = os.path.dirname(__file__) + "/icons/logo"
        iconSource          = _pathIcons + "/qgireferentiels.png"
        myDefPath = iconSource.replace("\\","/")
        carIcon = QtGui.QImage(myDefPath)
        self.labelImage.setPixmap(QtGui.QPixmap.fromImage(carIcon))
        self.labelImage.setObjectName("labelImage")
        self.layout_bandeau.addWidget(self.labelImage)
        #----------
        self.label_2 = QtWidgets.QLabel()
        font = QtGui.QFont()
        font.setPointSize(12) 
        font.setWeight(50) 
        font.setBold(True)
        self.label_2.setFont(font)
        self.label_2.setTextFormat(QtCore.Qt.TextFormat.RichText)
        self.label_2.setObjectName("label_2") 
        self.layout_bandeau.addWidget(self.label_2)
        #----------
        self.layout_bandeau.addStretch(1)
        #----------
        self.labelImage2 = QtWidgets.QLabel()
        _pathIcons = os.path.dirname(__file__) + "/icons/logo"
        iconSource          = _pathIcons + "/geoidedistribution.png"
        myDefPath = iconSource.replace("\\","/")
        carIcon = QtGui.QImage(myDefPath)
        self.labelImage2.setPixmap(QtGui.QPixmap.fromImage(carIcon))
        self.labelImage2.setObjectName("labelImage2")
        #self.layout_bandeau.addWidget(self.labelImage2)
        #----------
        self.label_3 = QtWidgets.QLabel()
        font = QtGui.QFont()
        font.setPointSize(12) 
        font.setWeight(50) 
        font.setBold(True)
        self.label_3.setFont(font)
        self.label_3.setTextFormat(QtCore.Qt.TextFormat.RichText)
        self.label_3.setObjectName("label_3") 
        #self.layout_bandeau.addWidget(self.label_3)
        #========

        # [ == Help == ]
        _icon = os.path.dirname(__file__) + "/icons/buttons/info.svg"          
        helpLibActionAndAction = QtWidgets.QApplication.translate("qgidistribution_ui",  "Online Doc", None)  
        _Listkeys   = [ "typeWidget",            "textWidget",          "nameWidget", "iconWidget", "toolTipWidget",       "actionWidget",  "autoRaise", "checkable", "qSizePolicy" ]
        _ListValues = [ QtWidgets.QToolButton(), helpLibActionAndAction, "Edition",    _icon,        helpLibActionAndAction, self.myHelpAM,  True,       False,       QSizePolicy.Policy.Fixed ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        self.helpButton = genereButtonWithDict( dicParamButton )
        pathIcon = os.path.dirname(__file__) + "/icons/buttons/info.svg" 
        self.helpButton.setIcon(QtGui.QIcon(pathIcon))
        icon_size = QtGui.QPixmap(pathIcon).size()
        self.helpButton.setIconSize(icon_size) 
        self.helpButton.resize(int(icon_size.width() ), int(icon_size.height() ))
        self.layout_bandeau.addWidget(self.helpButton)
        
        #========
        #Zone Onglets
        self.deltaHauteurTabWidget = 120
        self.tabWidget = QTabWidget(self.Dialog)
        self.tabWidget.setObjectName("tabWidget")
        self.tabWidget.setGeometry(QtCore.QRect(10,100,self.lScreenDialog - 20, self.hScreenDialog - self.deltaHauteurTabWidget))

        self.tabWidget.setStyleSheet(
             "QTabWidget::pane {border: 2px solid " + self.colorQTabWidget  + "; font-family:" + self.policeQGroupBox  +";} \
             QTabBar::tab {border: 1px solid " + self.colorQTabWidget  + "; border-bottom-color: none; font-family:" + self.policeQGroupBox  +"; \
                          border-top-left-radius: 6px; border-top-right-radius: 6px; padding-left: 20px; padding-right: 20px;} \
             QTabBar::tab:selected {background: qlineargradient(x1: 0, y1: 0, x2: 0.5, y2: 0.5, stop: 0 " + self.colorQTabWidget  + ", stop: 1 white); \
                                   text-shadow: 1px 1px 2px black;}"
        )

                                     
        #--------------------------
        #--------------------------
        self.tab_widget_distribution = QWidget()
        self.tab_widget_distribution.setObjectName("tab_widget_distribution")
        labelTab_General = QtWidgets.QApplication.translate("qgidistribution_ui", "   Warehouse visualization   ", None)
        self.tabWidget.addTab(self.tab_widget_distribution,labelTab_General)
        menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/onglets/qgireferentiels.svg")) 
        self.tabWidget.setTabIcon(self.tabWidget.indexOf(self.tab_widget_distribution), menuIcon)
        #-
        self.groupBox_tab_widget_distribution = QtWidgets.QGroupBox(self.tab_widget_distribution)
        self.groupBox_tab_widget_distribution.setGeometry(QtCore.QRect(10,10,int(self.tabWidget.width()) - 20, int(self.tabWidget.height()) - 40))
        self.groupBox_tab_widget_distribution.setObjectName("groupBox_tab_widget_distribution")
        self.groupBox_tab_widget_distribution.setStyleSheet("QGroupBox { border: 0px solid green }")
        self.layout_tab_widget_distribution = QtWidgets.QGridLayout()
        self.layout_tab_widget_distribution.setContentsMargins(0, 0, 0, 0)
        self.layout_tab_widget_distribution.setRowStretch(0, 1)
        self.layout_tab_widget_distribution.setRowStretch(1, 20)
        self.layout_tab_widget_distribution.setRowStretch(2, 2)
        self.groupBox_tab_widget_distribution.setLayout(self.layout_tab_widget_distribution)
    
        # =================================================================
        # == QSPLITTER ==
        # QSplitter    Permet d'avoir un slider et de le déplacer dynamiquement
        self.splitter = QtWidgets.QSplitter(QtCore.Qt.Orientation.Horizontal)
        # QGroupBox QSplitter 1 (Gauche comportant TOUS LES FILTRES)
        self.groupBox_QSplitter_Left = QtWidgets.QGroupBox()
        self.groupBox_QSplitter_Left.setStyleSheet("QGroupBox { border: 1px solid black; border-color:"  + self.colorQTabWidget  + "; }")
        self.layout_QSplitter_Left = QtWidgets.QGridLayout()
        self.layout_QSplitter_Left.setContentsMargins(0, 0, 0, 0)

        # QGroupBox QSplitter 2
        self.groupBox_QSplitter_Middle = QtWidgets.QGroupBox()
        self.groupBox_QSplitter_Middle.setStyleSheet("QGroupBox { border: 0px solid green }")
        self.layout_QSplitter_Middle = QtWidgets.QGridLayout()
        self.layout_QSplitter_Middle.setContentsMargins(0, 0, 0, 0)

        self.layout_QSplitter_Middle.setRowStretch(0, 50)
        self.layout_QSplitter_Middle.setRowStretch(1, 1)
        self.layout_QSplitter_Middle.setRowStretch(2, 1)
        
        self.layout_QSplitter_Middle.setColumnStretch(0, 1)
        self.layout_QSplitter_Middle.setColumnStretch(1, 1)
        self.layout_QSplitter_Middle.setColumnStretch(2, 1)
        self.layout_QSplitter_Middle.setColumnStretch(3, 1)
        self.layout_QSplitter_Middle.setColumnStretch(4, 1)
        self.layout_QSplitter_Middle.setColumnStretch(5, 1)
        self.layout_QSplitter_Middle.setColumnStretch(6, 1)

        #==========================
        #==========================
        #- Nombre d'objets sélectionnés dans le panier
        mText = ""
        mTextToolTip = QtWidgets.QApplication.translate("qgidistribution_ui", "Number of resources selected in the cart.", None)     #Nombre de ressources sélectionéns dans le panier.
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignCenter,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        self.mLabelNbBasket  = genereLabelWithDict( dicParamLabel )

        #==========================
        #Button Ajouter au panier
        self.buttonAddBasket = QtWidgets.QToolButton()
        self.buttonAddBasket.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonAddBasket.setObjectName("buttonAddBasket")
        self.buttonAddBasket.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket", None))
        _addTooltip = QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket.", None)
        self.buttonAddBasket.setToolTip(_addTooltip)
        self.buttonAddBasket.clicked.connect(lambda : self.functionApplyBasket("Add basket"))
        #==========================
        #Button Vide le panier
        self.buttonEmptyBasket = QtWidgets.QToolButton()
        self.buttonEmptyBasket.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonEmptyBasket.setObjectName("buttonEmptyBasket")
        self.buttonEmptyBasket.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Empty basket", None))
        _addTooltip = QtWidgets.QApplication.translate("qgidistribution_ui", "Empty basket.", None)
        self.buttonEmptyBasket.setToolTip(_addTooltip)
        self.buttonEmptyBasket.clicked.connect(lambda : self.functionApplyBasket("Empty basket"))
        #==========================
        #Button télécharger le panier
        self.buttonDownloadBasket = QtWidgets.QToolButton()
        self.buttonDownloadBasket.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonDownloadBasket.setObjectName("buttonDownloadBasket")
        self.buttonDownloadBasket.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Download basket", None))
        _addTooltip = QtWidgets.QApplication.translate("qgidistribution_ui", "Download basket.", None)
        self.buttonDownloadBasket.setToolTip(_addTooltip)
        self.buttonDownloadBasket.clicked.connect(lambda : self.functionApplyBasket("Download basket"))
        #==========================
        #Button Générer le fichier de téléchargemetn du panier
        self.buttonGenerateBasket = QtWidgets.QToolButton()
        self.buttonGenerateBasket.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonGenerateBasket.setObjectName("buttonGenerateBasket")
        self.buttonGenerateBasket.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Generate basket", None))
        _addTooltip = QtWidgets.QApplication.translate("qgidistribution_ui", "Generate basket.", None)
        self.buttonGenerateBasket.setToolTip(_addTooltip)
        self.buttonGenerateBasket.clicked.connect(lambda : self.functionApplyBasket("Generate basket"))

        #==========================
        #Button Save et Load xml sauvegarde panier
        self.buttonSaveLoadBasket = QtWidgets.QToolButton()
        self.buttonSaveLoadBasket.setObjectName("buttonSaveLoadBasket")
        self.buttonSaveLoadBasket.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Save / Load basket", None) + "  ")
        _addTooltip = QtWidgets.QApplication.translate("qgidistribution_ui", "Save / Load basket.", None)
        menuIcon                   = returnIcon(os.path.dirname(__file__) + ("/icons/general/basket_noir.svg")) 
        self.buttonSaveLoadBasket.setIcon(menuIcon)
        self.buttonSaveLoadBasket.setToolTip(_addTooltip)
        self.buttonSaveLoadBasket.setStyleSheet("QToolButton { font-family:" + self.policeQGroupBox  +";border: 1px solid #cccccc;}")
        self.buttonSaveLoadBasket.setAutoRaise(True)
        #
        #MenuQToolButton                        
        self.menuSaveLoadBasket = QMenu()
        self.menuSaveLoadBasket.setToolTipsVisible(True)
        self.menuSaveLoadBasket.setStyleSheet("QMenu { font-family:" + self.policeQGroupBox  +";}")
        #------------
        menuIcon                   = returnIcon(os.path.dirname(__file__) + ("/icons/general/save.svg")) 
        addLibActionSave           = QtWidgets.QApplication.translate("qgidistribution_ui", "Save basket")     
        treeAction_addTooltipSave  = QtWidgets.QApplication.translate("qgidistribution_ui", "Save Tooltip basket")
        treeActionSaveBasket       = QAction(addLibActionSave, self.menuSaveLoadBasket)
        treeActionSaveBasket.setObjectName("treeActionSaveBasket")
        treeActionSaveBasket.setIcon(menuIcon)
        self.menuSaveLoadBasket.addAction(treeActionSaveBasket)
        treeActionSaveBasket.setToolTip(treeAction_addTooltipSave)
        self.treeActionSaveBasket = treeActionSaveBasket
        treeActionSaveBasket.triggered.connect( lambda : self.functionSaveLoadBasket("SavePanier") )
        #
        self.menuSaveLoadBasket.addSeparator()
        #------------
        menuIcon                   = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/import.svg")) 
        addLibActionLoad           = QtWidgets.QApplication.translate("qgidistribution_ui", "Load basket")     
        treeAction_addTooltipLoad  = QtWidgets.QApplication.translate("qgidistribution_ui", "Load Tooltip basket")
        treeActionLoadBasket       = QAction(addLibActionLoad, self.menuSaveLoadBasket)
        treeActionLoadBasket.setObjectName("treeActionLoadBasket")
        treeActionLoadBasket.setIcon(menuIcon)
        self.menuSaveLoadBasket.addAction(treeActionLoadBasket)
        treeActionLoadBasket.setToolTip(treeAction_addTooltipLoad)
        self.treeActionLoadBasket = treeActionLoadBasket
        treeActionLoadBasket.triggered.connect( lambda : self.functionSaveLoadBasket("LoadPanier") )
       
        self.buttonSaveLoadBasket.setPopupMode(self.buttonSaveLoadBasket.ToolButtonPopupMode.InstantPopup)
        self.buttonSaveLoadBasket.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        self.buttonSaveLoadBasket.setMenu(self.menuSaveLoadBasket)
        #--                        
        
        _flagEnabled = False
        self.buttonAddBasket.setEnabled(_flagEnabled)
        self.buttonEmptyBasket.setEnabled(_flagEnabled)
        self.buttonDownloadBasket.setEnabled(_flagEnabled)
        self.buttonGenerateBasket.setEnabled(_flagEnabled)
        self.treeActionSaveBasket.setEnabled(_flagEnabled)  
       
        #==========================
        # QGroupBox QSplitter 3
        self.groupBox_QSplitter_Right = QtWidgets.QGroupBox()
        self.groupBox_QSplitter_Right.setStyleSheet("QGroupBox { border: 0px solid blue }")
        self.layout_QSplitter_Right = QtWidgets.QGridLayout()
        self.layout_QSplitter_Right.setContentsMargins(10, 10, 10, 10)
        
        self.layout_QSplitter_Right.setRowStretch(0, 1)
        self.layout_QSplitter_Right.setRowStretch(1, 1)
        self.layout_QSplitter_Right.setRowStretch(2, 10)
        self.layout_QSplitter_Right.setRowStretch(3, 1)
        self.layout_QSplitter_Right.setRowStretch(4, 30)
        self.layout_QSplitter_Right.setRowStretch(5, 1)
        self.layout_QSplitter_Right.setRowStretch(6, 1)

        self.layout_QSplitter_Right.setColumnStretch(0, 1)
        self.layout_QSplitter_Right.setColumnStretch(1, 2)
        self.layout_QSplitter_Right.setColumnStretch(2, 2)
        self.layout_QSplitter_Right.setColumnStretch(3, 0)
        
        self.groupBox_QSplitter_Right.setLayout(self.layout_QSplitter_Left)
        self.groupBox_QSplitter_Middle.setLayout(self.layout_QSplitter_Middle)
        self.groupBox_QSplitter_Left.setLayout(self.layout_QSplitter_Right)
        # [ == scrolling Attributs == ]
        self.scroll_bar_layout_QSplitter_Right = QtWidgets.QScrollArea() 
        self.scroll_bar_layout_QSplitter_Right.setStyleSheet("QScrollArea { border: 0px solid green;}")
        self.scroll_bar_layout_QSplitter_Right.setWidgetResizable(True)
        self.scroll_bar_layout_QSplitter_Right.setWidget(self.groupBox_QSplitter_Right)
        # [ == scrolling Attributs == ]
        self.scroll_bar_layout_QSplitter_Middle = QtWidgets.QScrollArea() 
        self.scroll_bar_layout_QSplitter_Middle.setStyleSheet("QScrollArea { border: 0px solid yellow;}")
        self.scroll_bar_layout_QSplitter_Middle.setWidgetResizable(True)
        self.scroll_bar_layout_QSplitter_Middle.setWidget(self.groupBox_QSplitter_Middle)
        # Ajoutez les QGroupBox et le ScrollArea au QSplitter
        self.splitter.addWidget(self.groupBox_QSplitter_Left)             # FILTRES
        self.splitter.addWidget(self.scroll_bar_layout_QSplitter_Right)   # CATALOGUE DES Plateformes
        self.splitter.addWidget(self.scroll_bar_layout_QSplitter_Middle)  # Panier
        
        self.splitter.setStyleSheet("""
           QSplitter::handle {
               width: 6px;               /* Largeur du trait de la poignée */
               height: 6px;             /* Hauteur réduite du trait */
               background-color: #f0f0f0; /* Gris très clair presque blanc */
               
           }
           QSplitter::handle:hover {
               background-color: """ + self.colorQSPlitter + """; /* Change la couleur au survol, encore plus claire */
           }
        """)
    
        # Ajouter le splitter à tab_widget_distribution
        self.layout_tab_widget_distribution.addWidget(self.splitter, 1, 0, 2, 0)

        mValueCol1 = round(float(self.mDic_LH["OpenPanelValue"][0]))   
        mValueCol2 = round(float(self.mDic_LH["OpenPanelValue"][1]))   
        mValueCol3 = round(float(self.mDic_LH["OpenPanelValue"][2]))   
        self.splitter.setSizes([ int(mValueCol1), int(mValueCol2), int(mValueCol3) ])
        # == QSPLITTER ==

        # =================================================================
        # == QSPLITTER FILTRES==
        # QSplitter    Permet d'avoir un slider et de le déplacer dynamiquement
        self.splitterfiltre = QtWidgets.QSplitter(QtCore.Qt.Orientation.Vertical)
        """
        # groupBox_QSplitterFiltre_Haut   * Plateformes
        # groupBox_QSplitterFiltre_Bas    * Emprise du référentiel
        # groupBox_QSplitterFiltre_Date   * Date
        # groupBox_QSplitterFiltre_Middle * Formats
        """
        # QGroupBox QSplitter 1
        self.groupBox_QSplitterFiltre_Haut = QtWidgets.QGroupBox()
        self.groupBox_QSplitterFiltre_Haut.setMaximumHeight(50)
        #self.groupBox_QSplitterFiltre_Haut.setTitle("Plateformes")
        self.groupBox_QSplitterFiltre_Haut.setStyleSheet("QGroupBox { border:0px solid grey }")
        self.layout_QSplitterFiltre_Haut = QtWidgets.QGridLayout()
        self.layout_QSplitterFiltre_Haut.setContentsMargins(0, 0, 0, 0)

        # QGroupBox QSplitter 2
        self.groupBox_QSplitterFiltre_Middle = QgsCollapsibleGroupBox()
        self.groupBox_QSplitterFiltre_Middle.setCollapsed(True)
        self.groupBox_QSplitterFiltre_Middle.collapsedStateChanged.connect( lambda collapsed: self.action_QgsCollapsibleGroupBox_changed( 3, collapsed ) )
        self.groupBox_QSplitterFiltre_Middle.setTitle("Formats")
        self.groupBox_QSplitterFiltre_Middle.setContentsMargins(0, 0, 0, 0)
        self.groupBox_QSplitterFiltre_Middle.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-bottom: 10px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : normal;         \
                              padding-left:    6px;            \
                              padding-top:    20px;            \
                              padding-right:   6px;            \
                              padding-bottom: 0px;            \
                              }")                              
        self.layout_QSplitterFiltre_Middle = QtWidgets.QGridLayout()
        self.layout_QSplitterFiltre_Middle.setContentsMargins(0, 0, 0, 0)

        # QGroupBox QSplitter 3
        self.groupBox_QSplitterFiltre_Bas = QgsCollapsibleGroupBox()
        self.groupBox_QSplitterFiltre_Bas.collapsedStateChanged.connect( lambda collapsed: self.action_QgsCollapsibleGroupBox_changed( 1, collapsed ) )
        self.groupBox_QSplitterFiltre_Bas.setTitle(QtWidgets.QApplication.translate("qgidistribution_ui", "Reference of the frame of reference"))
        self.groupBox_QSplitterFiltre_Bas.setContentsMargins(0, 0, 0, 0)
        self.groupBox_QSplitterFiltre_Bas.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-bottom: 10px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : normal;         \
                              padding-left:    6px;            \
                              padding-top:    20px;            \
                              padding-right:   6px;            \
                              padding-bottom: 0px;            \
                              }")                              

        self.layout_QSplitterFiltre_Bas = QtWidgets.QGridLayout()
        self.layout_QSplitterFiltre_Bas.setContentsMargins(0, 0, 0, 0)

        # QGroupBox QSplitter Date
        self.groupBox_QSplitterFiltre_Date =QgsCollapsibleGroupBox()
        self.groupBox_QSplitterFiltre_Date.setMaximumHeight(110)
        self.groupBox_QSplitterFiltre_Date.collapsedStateChanged.connect( lambda collapsed: self.action_QgsCollapsibleGroupBox_changed( 2, collapsed ) )
        self.groupBox_QSplitterFiltre_Date.setTitle("Dates")
        self.groupBox_QSplitterFiltre_Date.setContentsMargins(0, 0, 0, 0)
        self.layout_QSplitterFiltre_Date = QtWidgets.QGridLayout()
        self.layout_QSplitterFiltre_Date.setColumnStretch(0, 2)
        self.layout_QSplitterFiltre_Date.setColumnStretch(1, 2)
        self.layout_QSplitterFiltre_Date.setColumnStretch(2, 1)
        self.layout_QSplitterFiltre_Date.setColumnStretch(3, 2)
        self.layout_QSplitterFiltre_Date.setColumnStretch(4, 2)
        self.layout_QSplitterFiltre_Date.setContentsMargins(0, 0, 0, 0)

        # QGroupBox Button Appliquer (Afficher AVEC les filtres et Afficher SANS les filtres) et QCombobox et buttons gestion des filtres
        self.groupBox_Appliquer_GestionFiltres = QtWidgets.QGroupBox()
        self.groupBox_Appliquer_GestionFiltres.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 0px; \
                              margin-right: 0px; \
                              margin-bottom: 0px; \
                              font-family:" + self.policeQGroupBox  + "  ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:     6px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.layout_Appliquer_GestionFiltres = QtWidgets.QGridLayout()
        self.layout_Appliquer_GestionFiltres.setColumnStretch(0, 1)
        self.layout_Appliquer_GestionFiltres.setColumnStretch(1, 1)
        self.layout_Appliquer_GestionFiltres.setContentsMargins(0, 0, 0, 0)
        self.groupBox_Appliquer_GestionFiltres.setLayout(self.layout_Appliquer_GestionFiltres)
       
        self.groupBox_QSplitterFiltre_Haut.setLayout(self.layout_QSplitterFiltre_Haut)
        self.groupBox_QSplitterFiltre_Middle.setLayout(self.layout_QSplitterFiltre_Middle)
        self.groupBox_QSplitterFiltre_Bas.setLayout(self.layout_QSplitterFiltre_Bas)
        self.groupBox_QSplitterFiltre_Date.setLayout(self.layout_QSplitterFiltre_Date)

        # Ajoutez les QGroupBox au QSplitter
        self.splitterfiltre.addWidget(self.groupBox_QSplitterFiltre_Haut)    # PARAM
        self.splitterfiltre.addWidget(self.groupBox_QSplitterFiltre_Bas)     # ZONES GEO
        self.splitterfiltre.addWidget(self.groupBox_QSplitterFiltre_Date)    # ZONES DATES
        self.splitterfiltre.addWidget(self.groupBox_QSplitterFiltre_Middle)  # FORMAT
        # Un espace
        spacer = QtWidgets.QWidget()
        spacer.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
        self.splitterfiltre.addWidget(spacer)
        # Un espace

        self.splitterfiltre.addWidget(self.groupBox_Appliquer_GestionFiltres)         # Appliquer et GEstion Filtres
        self.splitterfiltre.setStyleSheet("""
           QSplitter::handle {
               width: 6px;               /* Largeur du trait de la poignée */
               height: 6px;             /* Hauteur réduite du trait */
               background-color: #f0f0f0; /* Gris très clair presque blanc */
               
           }
           QSplitter::handle:hover {
               background-color: """ + self.colorQSPlitter + """; /* Change la couleur au survol, encore plus claire */
           }
        """)

        # Ajouter le splitter à tab_widget_distribution
        self.layout_QSplitter_Right.addWidget(self.splitterfiltre, 0, 0, 5, 4)
        mValueCol1 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][0]))   
        mValueCol2 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][1]))   
        mValueCol3 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][2]))   
        if len(self.mDic_LH["OpenPanelValueSplitterfiltre"]) < 4 : 
           mValueCol4 = 50
        else :      
           mValueCol4 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][3]))

        # Important de n'utiliser qu'une fois à l'ouverture après plus de splitterfiltre
        if self._firstSplitterfiltre :
           sumSizes = int(mValueCol1) + int(mValueCol2) + int(mValueCol3) 
           sizeSpace = self.groupBox_QSplitter_Right.height() - sumSizes
           self.splitterfiltre.setSizes([ int(mValueCol1), int(mValueCol2), int(mValueCol3), sizeSpace ])
           self.sizes1Splitter, self.sizes2Splitter, self.sizes3Splitter, self.sizes4Splitter= int(mValueCol1), int(mValueCol2), int(mValueCol3), 0 
           self._firstSplitterfiltre = False
           
        # == QSPLITTER FILTRES==

        #--------------------------
        #--------------------------
        self.tab_widget_Perso = QWidget()
        self.tab_widget_Perso.setObjectName("tab_widget_Perso")
        labelTab_Metadata = QtWidgets.QApplication.translate("qgidistribution_ui", "  Personalization  ", None)
        self.tabWidget.addTab(self.tab_widget_Perso,labelTab_Metadata)
        menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/onglets/perso.svg")) 
        self.tabWidget.setTabIcon(self.tabWidget.indexOf(self.tab_widget_Perso), menuIcon)
        #-
        self.groupBox_tab_widget_Perso = QtWidgets.QGroupBox(self.tab_widget_Perso)
        self.groupBox_tab_widget_Perso.setGeometry(QtCore.QRect(10,10,int(self.tabWidget.width()) - 20, int(self.tabWidget.height()) - 40))
        self.groupBox_tab_widget_Perso.setObjectName("groupBox_tab_widget_Perso")
        self.groupBox_tab_widget_Perso.setStyleSheet("QGroupBox { border: 0px solid grey }")
        #-
        self.layout_tab_widget_Perso = QtWidgets.QGridLayout()
        self.layout_tab_widget_Perso.setContentsMargins(10, 10, 10, 10)
        self.tab_widget_Perso.setLayout(self.layout_tab_widget_Perso)
        #Zone Onglets
        #--------------------------

        #==========================
        # ZONE Onglet personnalisation
        #==========================
        self.groupBox_tab_widget_Perso_Zone = QtWidgets.QGroupBox()
        self.groupBox_tab_widget_Perso_Zone.setObjectName("groupBox_tab_widget_Perso_Zone")
        self.groupBox_tab_widget_Perso_Zone.setStyleSheet("QGroupBox { border:0px solid grey }")
        self.groupBox_tab_widget_Perso_Zone.setContentsMargins(0, 0, 0, 0)
        #-
        self.layout_tab_widget_Perso_Zone = QtWidgets.QGridLayout()
        self.layout_tab_widget_Perso_Zone.setContentsMargins(0, 0, 0, 0)
        self.groupBox_tab_widget_Perso_Zone.setLayout(self.layout_tab_widget_Perso_Zone)
        # [ == scrolling Attributs == ]
        self.scroll_bar_Perso_Zone = QtWidgets.QScrollArea() 
        self.scroll_bar_Perso_Zone.setStyleSheet("QScrollArea { border: 0px solid red;}")
        self.scroll_bar_Perso_Zone.setWidgetResizable(True)
        self.scroll_bar_Perso_Zone.setWidget(self.groupBox_tab_widget_Perso_Zone)
        self.layout_tab_widget_Perso.addWidget(self.scroll_bar_Perso_Zone)
        #-
        
        # == QGroupBox personnalisation ==
        self.groupBox_personnalisation = QgsCollapsibleGroupBox()
        self.groupBox_personnalisation.setObjectName("groupBox_personnalisation")
        self.groupBox_personnalisation.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.policeQGroupBox  + "  ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.groupBox_personnalisation.setTitle("personnalisation")
        self.layout_personnalisation = QtWidgets.QGridLayout()
        self.layout_personnalisation.setColumnStretch(0, 3)
        self.layout_personnalisation.setColumnStretch(1, 3)
        self.layout_personnalisation.setColumnStretch(2, 3)
        self.layout_personnalisation.setColumnStretch(3, 0)
        self.groupBox_personnalisation.setLayout(self.layout_personnalisation)
        # == QGroupBox generale ==
        self.groupBox_generale = QgsCollapsibleGroupBox()
        self.groupBox_generale.setObjectName("groupBox_generale")
        self.groupBox_generale.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.policeQGroupBox  + " ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.groupBox_generale.setTitle(QtWidgets.QApplication.translate("qgidistribution_ui", 'configuration "General"')) # 'configuration "Générale"')
        self.layout_generale = QtWidgets.QGridLayout()
        self.layout_generale.setColumnStretch(0, 3)
        self.layout_generale.setColumnStretch(1, 3)
        self.layout_generale.setColumnStretch(2, 3)
        self.layout_generale.setColumnStretch(3, 0)
        self.groupBox_generale.setLayout(self.layout_generale)
        # == QGroupBox GI Distribution ==
        self.groupBox_gidistribution = QgsCollapsibleGroupBox()
        self.groupBox_gidistribution.setObjectName("groupBox_gidistribution")
        self.groupBox_gidistribution.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.groupBox_gidistribution.setTitle('configuration "Géo-IDE Distribution"')
        self.layout_gidistribution = QtWidgets.QGridLayout()
        self.layout_gidistribution.setColumnStretch(0, 3)
        self.layout_gidistribution.setColumnStretch(1, 3)
        self.layout_gidistribution.setColumnStretch(2, 3)
        self.layout_gidistribution.setColumnStretch(3, 0)
        self.groupBox_gidistribution.setLayout(self.layout_gidistribution)
        # == QGroupBox GPF ==
        self.groupBox_gpf = QgsCollapsibleGroupBox()
        self.groupBox_gpf.setObjectName("groupBox_gpf")
        self.groupBox_gpf.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.groupBox_gpf.setTitle('configuration "Géoplateforme"')
        self.layout_gpf = QtWidgets.QGridLayout()
        self.layout_gpf.setColumnStretch(0, 3)
        self.layout_gpf.setColumnStretch(1, 3)
        self.layout_gpf.setColumnStretch(2, 3)
        self.layout_gpf.setColumnStretch(3, 0)
        self.groupBox_gpf.setLayout(self.layout_gpf)
        # == QGroupBox ADVANCED ==
        self.groupBox_advanced = QgsCollapsibleGroupBox()
        self.groupBox_advanced.setObjectName("groupBox_advanced")
        self.groupBox_advanced.setContentsMargins(10, 10, 0, 0)
        self.groupBox_advanced.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    6px;            \
                              padding-top:    0px;            \
                              padding-right:   6px;            \
                              padding-bottom: 0px;            \
                              }")
        self.groupBox_advanced.setTitle(QtWidgets.QApplication.translate("qgidistribution_ui", 'configuration "Advanced"'))
        self.layout_advanced = QtWidgets.QGridLayout()
        self.groupBox_advanced.setContentsMargins(10, 10, 0, 0)
        self.layout_advanced.setColumnStretch(0, 3)
        self.layout_advanced.setColumnStretch(1, 3)
        self.layout_advanced.setColumnStretch(2, 3)
        self.layout_advanced.setColumnStretch(3, 0)
        self.groupBox_advanced.setLayout(self.layout_advanced)
        # == QGroupBox Buttonn SAVE ==
        self.groupBoxButtonSave = QtWidgets.QGroupBox()
        self.groupBoxButtonSave.setObjectName("groupBoxButtonSave")
        self.groupBoxButtonSave.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 10px; \
                              margin-right: 0px; \
                              margin-down: 10px; \
                              }")
        self.layoutButtonSave = QtWidgets.QGridLayout()
        self.layoutButtonSave.setContentsMargins(10, 30, 10, 10)
        self.layoutButtonSave.setColumnStretch(0, 3)
        self.layoutButtonSave.setColumnStretch(1, 3)
        self.layoutButtonSave.setColumnStretch(2, 3)
        self.layoutButtonSave.setColumnStretch(3, 0)
        self.groupBoxButtonSave.setLayout(self.layoutButtonSave)
        

        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBox_personnalisation, 0, 0)
        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBox_generale, 1, 0)
        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBox_gidistribution, 2, 0)
        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBox_gpf, 3, 0)
        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBox_advanced, 4, 0)
        self.layout_tab_widget_Perso_Zone.addWidget(self.groupBoxButtonSave, 5, 0)
        #
        #self.groupBox_personnalisation.setSaveCheckedState(False)
        #self.groupBox_generale.setSaveCheckedState(True)
        #self.groupBox_gidistribution.setSaveCheckedState(True)
        #self.groupBox_gpf.setSaveCheckedState(True)
        self.groupBox_personnalisation.setCollapsed(False)
                
        #===================================================================================================
        #- layout_personnalisation
        self.labelQGroupBox = QtWidgets.QLabel()
        self.labelQGroupBox.setAlignment(Qt.AlignmentFlag.AlignRight)        
        self.labelQGroupBox.setText(QtWidgets.QApplication.translate("qgidistribution_ui", "Police :"))        
        self.labelQGroupBox.setStyleSheet("QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}")
        self.labelQGroupBox.setWordWrap(True)
        self.layout_personnalisation.addWidget(self.labelQGroupBox, 1, 0, Qt.AlignmentFlag.AlignTop)
        #-
        self.fontQGroupBox = QtWidgets.QFontComboBox()
        self.fontQGroupBox.setObjectName("fontComboBox")         
        self.fontQGroupBox.setCurrentFont(QFont(self.policeQGroupBox))         
        self.fontQGroupBox.currentFontChanged.connect(lambda : functionFont(self))
        self.zFontQGroupBox = self.policeQGroupBox  # si ouverture sans chgt et sauve
        self.layout_personnalisation.addWidget(self.fontQGroupBox, 1, 1, Qt.AlignmentFlag.AlignTop)
        #-
        layout, button_0, img_0, reset_0 = self.layout_personnalisation, QtWidgets.QPushButton(), QtWidgets.QLabel(), QtWidgets.QPushButton()
        self.button_0, self.img_0, self.reset_0 = button_0, img_0, reset_0
        genereButtonActionColor(self, layout, button_0, img_0, reset_0, "button_0", "img_0", "reset_0", 0)
        #-
        #-
        layout, button_2, img_2, reset_2 = self.layout_personnalisation, QtWidgets.QPushButton(), QtWidgets.QLabel(), QtWidgets.QPushButton()
        self.button_2, self.img_2, self.reset_2 = button_2, img_2, reset_2
        genereButtonActionColor(self, layout, button_2, img_2, reset_2, "button_2", "img_2", "reset_2", 2)

        #===================================================================================================
        #- layout_generale

        #- PATH REFERENTIEL 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "File for downloading repositories", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "File for downloading repositories", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValuePathReferentiel = genereLabelWithDict( dicParamLabel )
        self.layout_generale.addWidget(mLabelValuePathReferentiel,1 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        #_ListValues = [ CustomComboBox(), "mZoneValuePathReferentiel",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        _ListValues = [ QComboBox(), "mZoneValuePathReferentiel",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneQComboValuePathReferentiel = genereButtonWithDict( dicParamButton )
        self.mZoneQComboValuePathReferentiel = mZoneQComboValuePathReferentiel
        #self.mZoneQComboValuePathReferentiel.initCustomComboBox(self)
        
        for i in range(len(self.mZoneValuePathReferentielList)) : 
            self.mZoneQComboValuePathReferentiel.addItem( self.mZoneValuePathReferentielList[i] )
            #treeAction_addTooltipDeletePathReferentiel  = QtWidgets.QApplication.translate("qgidistribution_ui", "Clik right Delete tooltip path")
            #self.mZoneQComboValuePathReferentiel.setItemData(i, treeAction_addTooltipDeletePathReferentiel, Qt.ToolTipRole)
        
        self.mZoneQComboValuePathReferentiel.setCurrentText( str(self.mZoneValuePathReferentiel) )
        self.layout_generale.addWidget(mZoneQComboValuePathReferentiel,1,1 ,Qt.AlignmentFlag.AlignTop)
        #- PATH REFERENTIEL

        #Button Add et Delete
        self.layout_buttons_add_del = QtWidgets.QHBoxLayout()
        #Button Open Folder PATH REFERENTIEL
        self.buttonOpenPathReferentiel = QtWidgets.QToolButton()
        self.buttonOpenPathReferentiel.setObjectName("buttonOpenPathReferentiel")
        self.buttonOpenPathReferentiel.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/create.svg"))
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Add File for downloading repositories", None)
        self.buttonOpenPathReferentiel.setToolTip(mTextToolTip)
        self.buttonOpenPathReferentiel.clicked.connect(lambda : functionOpenPathReferentiel(self, self.mZoneQComboValuePathReferentiel.currentText()))
        self.layout_buttons_add_del.addWidget(self.buttonOpenPathReferentiel)
        #Button Open Folder PATH REFERENTIEL

        #Button Delete PATH REFERENTIEL
        self.buttonDeletePathReferentiel = QtWidgets.QToolButton()
        self.buttonDeletePathReferentiel.setObjectName("buttonDeletePathReferentiel")
        self.buttonDeletePathReferentiel.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/delete.svg"))
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Delete File for downloading repositories", None)
        self.buttonDeletePathReferentiel.setToolTip(mTextToolTip)
        self.buttonDeletePathReferentiel.clicked.connect(lambda : functionDeletePathReferentiel(self, self.mZoneQComboValuePathReferentiel.currentText()))
        self.layout_buttons_add_del.addWidget(self.buttonDeletePathReferentiel)
        #Button Delete PATH REFERENTIEL
        self.layout_buttons_add_del.addStretch()
        self.layout_generale.addLayout(self.layout_buttons_add_del, 1, 2, 1, 2)

        #- TELECHARGEMENT DU LOT EN DIRECT 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "DownLotDirect", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the DownLotDirect", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelDownLotDirect  = genereLabelWithDict( dicParamLabel )
        self.layout_generale.addWidget(mLabelDownLotDirect,2 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "DownLotDirect", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the DownLotDirect", None)
        _Listkeys   = [ "typeWidget",           "textWidget", "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QCheckBox() , "",        "mZoneDownLotDirect",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QCheckBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneDownLotDirect   = genereButtonWithDict( dicParamButton )
        self.mZoneDownLotDirect = mZoneDownLotDirect
        self.mZoneDownLotDirect.setChecked(True if self.mDownLotDirect else False)
        self.layout_generale.addWidget(mZoneDownLotDirect,2 ,1 ,Qt.AlignmentFlag.AlignTop)
        #- TELECHARGEMENT DU LOT EN DIRECT 

        #- ORGANISATION
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Enter an organization.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Enter an organization.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueOrganisation = genereLabelWithDict( dicParamLabel )
        self.layout_generale.addWidget(mLabelValueOrganisation,3 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.mValueOrganisation), "mValueOrganisation",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValueOrganisation = genereButtonWithDict( dicParamButton )
        self.mZoneValueOrganisation = mZoneValueOrganisation
        self.layout_generale.addWidget(mZoneValueOrganisation,3,1 ,Qt.AlignmentFlag.AlignTop)
        #- ORGANISATION

        #===================================================================================================
        #- layout_gidistribution

        #- URL GI Distribution
        icon_path = QgsApplication.iconPath("mIconWarning.svg")  
        mmText = QtWidgets.QApplication.translate("qgientrepot_ui", 'The Géo-IDE Distribution platform is only accessible to government employees with access to the RIE (Reporting Information System). If the login details are not provided, only the Géoplatform data will be accessible.', None)
        mText        = f'<img src="{icon_path}" width="16" height="16">  ' + mmText
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Warning.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignLeft,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueUrlWarning = genereLabelWithDict( dicParamLabel )
        mColorWaning = "#FFC800"
        mLabelValueUrlWarning.setStyleSheet("QLabel {  font-family:" + self.policeQGroupBox  +"; background-color : " + mColorWaning + ";}")
        self.layout_gidistribution.addWidget(mLabelValueUrlWarning,0 ,0 , 1 ,4,Qt.AlignmentFlag.AlignTop)
        #- URL GI Distribution
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Url de Géo-IDE Distribution.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Url de Géo-IDE Distribution.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueUrlGiDistribution = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelValueUrlGiDistribution,1 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.urlCatalogueDistribution), "mZoneValueUrlGiDistribution",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValueUrlGiDistribution = genereButtonWithDict( dicParamButton )
        self.mZoneValueUrlGiDistribution = mZoneValueUrlGiDistribution
        self.mZoneValueUrlGiDistribution.setEnabled(False)
        self.layout_gidistribution.addWidget(mZoneValueUrlGiDistribution,1,1 ,1 , 2, Qt.AlignmentFlag.AlignTop)
        #- URL GI Distribution

        #- LOGIN GI 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the login ID for Géo-IDE Distribution.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the login ID for Géo-IDE Distribution.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueloginGI = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelValueloginGI,2 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.mValueLoginGI), "mZoneValueloginGI",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValueloginGI = genereButtonWithDict( dicParamButton )
        self.mZoneValueloginGI = mZoneValueloginGI
        self.layout_gidistribution.addWidget(mZoneValueloginGI,2,1 ,Qt.AlignmentFlag.AlignTop)
        #- LOGIN GI 

        #- MDP GI 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the mdp for Géo-IDE Distribution.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the mdp for Géo-IDE Distribution.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValuemdpGI = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelValuemdpGI,3 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.mValueMdpGI), "mZoneValuemdpGI",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValuemdpGI = genereButtonWithDict( dicParamButton )
        self.mZoneValuemdpGI = mZoneValuemdpGI
        self.layout_gidistribution.addWidget(mZoneValuemdpGI,3,1 ,Qt.AlignmentFlag.AlignTop)
        #- MDP GI 

        #-  PROXY GI DISTRIBUTION
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy for GI Distribution.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy for GI Distribution.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelProxyGIDistribution = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelProxyGIDistribution,4 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QComboBox() ,"mZoneChoiceProxyGIDistribution",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QComboBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoiceProxyGIDistribution   = genereButtonWithDict( dicParamButton )
        mZoneChoiceProxyGIDistribution.addItems( self.listQComboBoxProxy )
        self.mZoneChoiceProxyGIDistribution = mZoneChoiceProxyGIDistribution
        self.mZoneChoiceProxyGIDistribution.setCurrentText( self.listQComboBoxProxy[ self.selectQComboBox_GI_Proxy ] )
        self.mZoneChoiceProxyGIDistribution.currentTextChanged.connect(lambda : self.functionChangeProxy( "mZoneLabelProxyGIDistribution" ))
        self.layout_gidistribution.addWidget(mZoneChoiceProxyGIDistribution,4 ,1 ,Qt.AlignmentFlag.AlignTop)
        #- 
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Test the connection for Géo-IDE Distribution.", None) 
        _Listkeys   = [ "typeWidget", "textWidget",          "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QPushButton(), mTextToolTip  ,"mZoneChoiceTestGIDistribution",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QPushButton {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoiceTestGIDistribution   = genereButtonWithDict( dicParamButton )
        self.mZoneChoiceTestGIDistribution = mZoneChoiceTestGIDistribution
        self.mZoneChoiceTestGIDistribution.clicked.connect(lambda : self.functionTestPlateforme("GIDistribution", URL_CATALOGUE_DISTRIBUTION, self.mZoneValueloginGI.text(), self.mZoneValuemdpGI.text()))
        self.layout_gidistribution.addWidget(mZoneChoiceTestGIDistribution,4 ,2 ,Qt.AlignmentFlag.AlignTop)
        #-  PROXY GI DISTRIBUTION
        
        #-  LABEL PROXY GI DISTRIBUTION PERSONNALISATION
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy label for Géo-IDE Distribution.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy label for Géo-IDE Distribution.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelLabelProxyGIDistribution = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelLabelProxyGIDistribution,5 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.HTTP_PROXY_GI_DISTRIBUTION), "mZoneLabelProxyGIDistribution",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneLabelProxyGIDistribution = genereButtonWithDict( dicParamButton )
        self.mZoneLabelProxyGIDistribution = mZoneLabelProxyGIDistribution
        self.mZoneLabelProxyGIDistribution.setText( self.label_GI_Proxy )
        self.mZoneLabelProxyGIDistribution.setEnabled(False if self.selectQComboBox_GI_Proxy in (0, 1) else True)
        self.layout_gidistribution.addWidget(mZoneLabelProxyGIDistribution,5,1 ,Qt.AlignmentFlag.AlignTop)
        #-  LABEL PROXY GI DISTRIBUTION PERSONNALISATION

        #- GI ARCHIVE BRUTE 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "ArchiveBrut", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the ArchiveBrut", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelArchiveBrut  = genereLabelWithDict( dicParamLabel )
        self.layout_gidistribution.addWidget(mLabelArchiveBrut,6 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "ArchiveBrut", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the ArchiveBrut", None)
        _Listkeys   = [ "typeWidget",           "textWidget", "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QCheckBox() , "",        "mZoneArchiveBrut",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QCheckBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneArchiveBrut   = genereButtonWithDict( dicParamButton )
        self.mZoneArchiveBrut = mZoneArchiveBrut
        self.mZoneArchiveBrut.setChecked(True if self.mArchiveBrut else False)
        self.layout_gidistribution.addWidget(mZoneArchiveBrut,6 ,1 ,Qt.AlignmentFlag.AlignTop)
        #- GI ARCHIVE BRUTE 

        #===================================================================================================
        #- layout_gpf
        
        #- URL GPF
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Url de Géoplateforme.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Url de Géoplateforme.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueUrlgpf = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelValueUrlgpf,0 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.URL_API_GPF), "mZoneValueUrlgpf",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValueUrlgpf = genereButtonWithDict( dicParamButton )
        self.mZoneValueUrlgpf = mZoneValueUrlgpf
        self.mZoneValueUrlgpf.setEnabled(False)
        self.layout_gpf.addWidget(mZoneValueUrlgpf,0,1 ,1 , 2, Qt.AlignmentFlag.AlignTop)
        #- URL GPF

        #- LOGIN GPF 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the login ID for Géoplateforme (Private).", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the login ID for Géoplateforme (Private).", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValueloginGPF = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelValueloginGPF,2 ,0 ,Qt.AlignmentFlag.AlignTop)
        mLabelValueloginGPF.setVisible(True)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), "A venir dans la prochaine version", "mZoneValueloginGPF",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.mValueLoginGPF), "mZoneValueloginGPF",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValueloginGPF = genereButtonWithDict( dicParamButton )
        self.mZoneValueloginGPF = mZoneValueloginGPF
        self.layout_gpf.addWidget(mZoneValueloginGPF,2,1 ,Qt.AlignmentFlag.AlignTop)
        self.mZoneValueloginGPF.setEnabled(True)
        #- LOGIN GPF

        # For vidéo
        #self.mZoneValueloginGI.setStyleSheet( "QLineEdit { color: #ffffff ; }")
        #self.mZoneValuemdpGI.setStyleSheet(   "QLineEdit { color: #ffffff ; }")
        #self.mZoneValueloginGPF.setStyleSheet("QLineEdit { color: #ffffff ; }")
        # For vidéo
        
        #- MDP GPF 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the mdp for Géoplateforme (Private).", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the mdp for Géoplateforme (Private).", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelValuemdpGPF = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelValuemdpGPF,3 ,0 ,Qt.AlignmentFlag.AlignTop)
        mLabelValuemdpGPF.setVisible(False)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), "A venir dans la prochaine version", "mZoneValuemdpGPF",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneValuemdpGPF = genereButtonWithDict( dicParamButton )
        self.mZoneValuemdpGPF = mZoneValuemdpGPF
        self.layout_gpf.addWidget(mZoneValuemdpGPF,3,1 ,Qt.AlignmentFlag.AlignTop)
        self.mZoneValuemdpGPF.setVisible(False)
        #- MDP GPF

        #-  PROXY GPF
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy for Géoplateforme.", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy for Géoplateforme.", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelProxygpf = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelProxygpf,4 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",           "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QComboBox()  ,"mZoneChoiceProxygpf",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QComboBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoiceProxygpf   = genereButtonWithDict( dicParamButton )
        mZoneChoiceProxygpf.addItems( self.listQComboBoxProxy )
        self.mZoneChoiceProxygpf = mZoneChoiceProxygpf
        self.mZoneChoiceProxygpf.setCurrentText( self.listQComboBoxProxy[ self.selectQComboBox_GPF_Proxy ] )
        self.mZoneChoiceProxygpf.currentTextChanged.connect(lambda : self.functionChangeProxy( "mZoneLabelProxygpf" ))
        self.layout_gpf.addWidget(mZoneChoiceProxygpf,4 ,1 ,Qt.AlignmentFlag.AlignTop)
        #- 
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Test the connection for the Géoplatforme.", None) #Tester la connexion pour la Géoplateforme.
        _Listkeys   = [ "typeWidget", "textWidget",          "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QPushButton(), mTextToolTip  ,"mZoneChoiceTestGPF",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QPushButton {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoiceTestGPF   = genereButtonWithDict( dicParamButton )
        self.mZoneChoiceTestGPF = mZoneChoiceTestGPF
        self.mZoneChoiceTestGPF.clicked.connect(lambda : self.functionTestPlateforme("GPF", URL_CATALOGUE_DISTRIBUTION, self.mZoneValueloginGI.text(), self.mZoneValuemdpGI.text()))
        self.layout_gpf.addWidget(mZoneChoiceTestGPF,4 ,2 ,Qt.AlignmentFlag.AlignTop)
        #-  PROXY GPF

        #-  LABEL PROXY GPF PERSONNALISATION
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy label for Géoplateforme (proxy + port).", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Select the proxy label for Géoplateforme.", None)
        _url1 = 'pfrie-std.proxy.e2.rie.gouv.fr'
        _url2 = 'http://pfrie-std.proxy.e2.rie.gouv.fr'
        _port = '8080'
        mTextToolTip   = "<html><div style='white-space: nowrap;'>" + mTextToolTip + "<br><br><i>Exemple : " + "<ul style='margin: 0;'><li>" + _url2 + ":" + _port + "</li></ul></i>" + "</div></html>"
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelLabelProxygpf = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelLabelProxygpf,5 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), str(self.HTTP_PROXY_GPF), "mZoneLabelProxygpf",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneLabelProxygpf = genereButtonWithDict( dicParamButton )
        self.mZoneLabelProxygpf = mZoneLabelProxygpf
        self.mZoneLabelProxygpf.setText( self.label_GPF_Proxy )
        self.mZoneLabelProxygpf.setEnabled(False if self.selectQComboBox_GPF_Proxy in (0, 1) else True)
        self.layout_gpf.addWidget(mZoneLabelProxygpf,5,1 ,Qt.AlignmentFlag.AlignTop)
        #-  LABEL PROXY GPF PERSONNALISATION

        #- PAGINATION 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Paging", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the Paging", None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignRight,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelPaging  = genereLabelWithDict( dicParamLabel )
        self.layout_gpf.addWidget(mLabelPaging,6 ,0 ,Qt.AlignmentFlag.AlignTop)
        #- 
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Paging", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "entering the Paging", None)
        _Listkeys   = [ "typeWidget",           "textWidget", "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QCheckBox() , "",        "mZonePaging",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QCheckBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZonePaging   = genereButtonWithDict( dicParamButton )
        self.mZonePaging = mZonePaging
        self.mZonePaging.setChecked(True if self.mPaging else False)
        self.layout_gpf.addWidget(mZonePaging,6 ,1 ,Qt.AlignmentFlag.AlignTop)
        #-  PAGINATION

        #===================================================================================================
        #- layout_advanced
        
        #- ADVANCED
        _text = "Définition d'un chemin spécifique à appliquer lors des téléchargements différés"
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Define a specific path to apply during deferred downloads" , None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,  True, "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabelDefault = dict(zip(_Listkeys, _ListValues))
        mLabelValueDefault = genereLabelWithDict( dicParamLabelDefault )
        self.layout_advanced.addWidget(mLabelValueDefault, 0 ,0 , Qt.AlignmentFlag.AlignVCenter  )
        mLabelValueDefault.setTextFormat(Qt.TextFormat.RichText)
        #- BUTTONS ADVANCED
        
        self.createRadioButton = RadioButtonWidget(self)
        self.layout_advanced.addWidget(self.createRadioButton.groupBox_radio, 0, 1, 1, 4)
        #- ADVANCED

        #==========================
        #Button SAVE personnalisation
        libInfo   = QtWidgets.QApplication.translate("qgidistribution_ui", "The modifications will be taken into account the next time you start QGIReferentiels.")
        libButton = QtWidgets.QApplication.translate("qgidistribution_ui", "Save settings")
        self.buttonSavePerso = QtWidgets.QToolButton()
        self.buttonSavePerso.setObjectName("buttonSaveParam")
        self.buttonSavePerso.setText(libButton)

        pathIcon = os.path.dirname(__file__) + "/icons/general/save.svg" 
        self.buttonSavePerso.setIcon(QtGui.QIcon(pathIcon))
        self.buttonSavePerso.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)  
        
        icon_size = QtGui.QPixmap(pathIcon).size()
        self.buttonSavePerso.setIconSize(QtCore.QSize(int(icon_size.width() * 0.5), int(icon_size.height() * 0.5))) 
        self.buttonSavePerso.clicked.connect(lambda : functionSavePerso(self))
        self.buttonSavePerso.setToolTip(libInfo)
        #Button SAVE personnalisation
        
        self.labelPushButton = QtWidgets.QLabel()
        self.labelPushButton.setObjectName("pushButton")
        self.labelPushButton.setAlignment(Qt.AlignmentFlag.AlignCenter)        
        self.labelPushButton.setText("<i>" + libInfo + "</i>")         
        
        #- 
        self.layout_tab_widget_Perso_Zone.setRowStretch(self.layout_tab_widget_Perso_Zone.rowCount(), 1) #Permet de pousser vers le haut les attributs
        #-
        #===================================================================================================
        #- layoutButtonSave

        self.layoutButtonSave.addWidget(self.buttonSavePerso, 0, 0, 2, 3 ,Qt.AlignmentFlag.AlignCenter)
        self.layoutButtonSave.addWidget(self.labelPushButton, 2, 0, 2, 3, Qt.AlignmentFlag.AlignCenter)
        #==========================
        #==========================
        # Gestion des TREEVIEW
        #==========================
        #==========================
        self.mTreeListeDistribution       = TREEVIEWDISTRIBUTION()  
        self.mTreeListePanier             = CustomTREEVIEWPANIER()  

        #==========================
        # ZONE Onglet VISUALISATION DE DISTRIBUTION  et GéoIDE DISTRIBUTION
        #==========================
        #------ TREEVIEW   
        self.mTreeListeDistribution.setStyleSheet(       "QTreeView  {  font-family:" + self.policeQGroupBox  +";}" )
        self.layout_QSplitter_Left.addWidget(self.mTreeListeDistribution)
        #----
 
        self.mTreeListePanier.setStyleSheet(       "QTreeView  {  font-family:" + self.policeQGroupBox  +";}" )
        self.mTreeListePanier.initPanier(self, self.mTreeListeDistribution)
        self.layout_QSplitter_Middle.addWidget(self.mTreeListePanier, 0, 0, 1, 7)
        #-
        self.layout_QSplitter_Middle.addWidget(self.mLabelNbBasket,       1, 0, 1, 7)
        self.layout_QSplitter_Middle.addWidget(self.buttonAddBasket,      2, 1)
        self.layout_QSplitter_Middle.addWidget(self.buttonEmptyBasket,    2, 2)
        self.layout_QSplitter_Middle.addWidget(self.buttonGenerateBasket, 2, 3)
        self.layout_QSplitter_Middle.addWidget(self.buttonDownloadBasket, 2, 4)
        self.layout_QSplitter_Middle.addWidget(self.buttonSaveLoadBasket, 2, 5)   

        #---- N'affiche que les plateformes
        _retXml = self.mTreeListeDistribution.initDistribution(self, _first = "FIRST")
        self.mTreeListeDistribution.afficheDistribution(self, _retXml, None) 

        #==========================
        #Barre d'outils qgireferentiels
        self.createToolBarQGIDistribution()
                
        #Réinitialise les proxy en fonction de la saisie dans l'onglet Paramètres
        return_HTTP_PROXY_GPF, return_HTTP_PROXY_GI_DISTRIBUTION = self.return_HTTP_PROXY_GPF_GIDISTRIBUTION("INITIALISATION")
        self.HTTP_PROXY_GPF       = return_HTTP_PROXY_GPF               #Proxy HTTP
        self.HTTPS_PROXY_GPF      = self.HTTP_PROXY_GPF                 #Proxy HTTPS
        self.HTTP_PROXY_GI_DISTRIBUTION  = return_HTTP_PROXY_GI_DISTRIBUTION        #Proxy HTTP_PROXY_GI_DISTRIBUTION
        self.HTTPS_PROXY_GI_DISTRIBUTION = self.HTTP_PROXY_GI_DISTRIBUTION          #Proxy HTTP_PROXY_GI_DISTRIBUTION
        #Réinitialise les proxy en fonction de la saisie dans l'onglet Paramètres

        # Affichage des paramètres
        self.filtresParametres()
        #Réinit des filtres
        self.functionSaveDeleteInitFilter( "InitFilter" )        
        self.buttonSaveFilter.setEnabled(False)
        #==========================
        self.retranslateUi(Dialog)
        #self.groupBox_QSplitterFiltre_Date.setCollapsed(True)
        self.groupBox_QSplitterFiltre_Date.setCollapsed(False)
    #= Fin setupUi
    
    #==========================
    def action_QgsCollapsibleGroupBox_changed(self, index, collapsed):
        self.groupBox_QSplitterFiltre_Date.setMaximumHeight(110)

        # Important de n'utiliser qu'une fois à l'ouverture après plus de splitterfiltre
        if self._firstSplitterfiltreAction :
           mValueCol1 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][0]))   
           mValueCol2 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][1]))   
           mValueCol3 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][2]))   
           if len(self.mDic_LH["OpenPanelValueSplitterfiltre"]) < 4 : 
              mValueCol4 = 50
           else :      
              mValueCol4 = round(float(self.mDic_LH["OpenPanelValueSplitterfiltre"][3]))
           tailles = [ mValueCol1, mValueCol2, mValueCol3, mValueCol4, 0 ]  
           self.splitterfiltre.setSizes(tailles)
           self._firstSplitterfiltreAction = False
           return

        """
        # groupBox_QSplitterFiltre_Haut   * Plateformes             * index 0
        # groupBox_QSplitterFiltre_Bas    * Emprise du référentiel  * index 1
        # groupBox_QSplitterFiltre_Date   * Date                    * index 2
        # groupBox_QSplitterFiltre_Middle * Formats                 * index 3
        """
        groupboxes = [
           (self.groupBox_QSplitterFiltre_Haut,   0, 26,                                         26),
           (self.groupBox_QSplitterFiltre_Bas,    1, int(self.groupBox_QSplitter_Right.height() / 2), 26),
           (self.groupBox_QSplitterFiltre_Date,   2, 50,                                         10),
           (self.groupBox_QSplitterFiltre_Middle, 3, int(self.groupBox_QSplitter_Right.height() / 2), 26)
        ]
       
        
        countFerme = 0
        ifCountFerme = False  # Emprise et Format fermés
        tailles = []
        for gb, _index, taille_maxi, taille_mini in groupboxes:
            if hasattr(gb, 'isCollapsed') and gb.isCollapsed(): # Fermé
                tailles.append(taille_mini)
                if _index in [1, 3] : countFerme +=1
                if _index in [1, 3] : ifCountFerme = True
                border_style = "None"
            else:
                tailles.append(taille_maxi)
                border_style = "solid"        

            if _index == 1 : tree = self.mZoneFiltreParametresZone
            if _index == 3 : tree = self.mZoneFiltreParametresFormat
            if _index in [1, 3] : 
               _NormalBold  = "bold" if tree.ifUneSeuleCaseACocher(tree) else "normal"
            else :    
               _NormalBold  = "normal"
            if _index > 0 :    
               gb.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-bottom: 00px; \
                              font-family:" + self.policeQGroupBox  +" ; \
                              border-style: "  + border_style  + ";      \
                              border-width:1px;      \
                              border-color:"  + self.colorQTabWidget  + ";      \
                              font-weight : "  + _NormalBold  + ";      \
                              padding-left:    6px;            \
                              padding-top:     6px;            \
                              padding-right:   6px;            \
                              padding-bottom:  0px;            \
                              } \
                              QGroupBox::title { \
                              subcontrol-origin: margin; \
                              subcontrol-position: top left; \
                              padding-left: 20px; \
                              }")                            

            if _index in [2] : 
               gb = self.groupBox_QSplitterFiltre_Date   
                       
               _NormalBold  = "bold" if self.createRadioButtonDate.ifUneDateSaisie() else "normal"    

               if hasattr(gb, 'isCollapsed') and gb.isCollapsed(): # Fermé
                  self.groupBox_QSplitterFiltre_Date.setMaximumHeight(20)
                  border_style = "None"
               else:
                  self.groupBox_QSplitterFiltre_Date.setMaximumHeight(110)
                  border_style = "solid"        
                 
               gb.setStyleSheet("QGroupBox {   \
                                       margin-top: 10px; \
                                       margin-left: 10px; \
                                       margin-right: 10px; \
                                       margin-bottom: 0px; \
                                       font-family:" + self.policeQGroupBox  +" ; \
                                       border-style: "  + border_style  + ";      \
                                       font-weight : "  + _NormalBold  + ";      \
                                       border-width:1px ; \
                                       border-color:"  + self.colorQTabWidget  + ";      \
                                       padding-left:    6px;            \
                                       padding-top:     6px;            \
                                       padding-right:   6px;            \
                                       padding-bottom:  0px;            \
                                       } \
                                       QGroupBox::title { \
                                       subcontrol-origin: margin; \
                                       subcontrol-position: top left; \
                                       padding-left: 20px; \
                                       }") 

        # Pour pousser tout vers le haut
        taille_spacer = self.groupBox_QSplitter_Right.height() if ifCountFerme and countFerme != 1 else 0
        tailles.append(taille_spacer)
        # Pour pousser tout vers le haut
        self.splitterfiltre.setSizes(tailles)
        return

    #==========================
    def resizeEvent(self, event):
        resizeIhm(self, self.Dialog.width(), self.Dialog.height())

    #==========================
    def hideEvent(self, event):
        returnAndSaveDialogParam(self, "Save")

    #==========================
    def closeEvent(self, event):
        returnAndSaveDialogParam(self, "Save")

    #==========================
    def resizeEvent(self, event):
        resizeIhm(self, self.Dialog.width(), self.Dialog.height())

    #==========================
    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(self.messWindowTitle)
        
        _versionComplement  = "" if self._version_Qgis == "" else " -- Version Qgis : " +  self._version_Qgis
        _versionComplement += "" if self._version_PyQt == "" else " -- Version PyQt : " +  self._version_PyQt
        _versionComplement += "" if self._version_Qt   == "" else " -- Version Qt : "   +  self._version_Qt

        self.zMessTitle_label_2    =  QtWidgets.QApplication.translate("qgidistribution_ui", "QGIReferentiels", None) # + _versionComplement
        self.zMessTitle_label_3    =  QtWidgets.QApplication.translate("qgidistribution_ui", "GEOdistribution", None)   
        self.label_2.setText(self.zMessTitle_label_2)
        self.label_3.setText(self.zMessTitle_label_3)

        if self.valueRadioPath == 1 : 
           self.createRadioButton.pathDefault.setChecked(True)
        elif self.valueRadioPath == 2 : 
           self.createRadioButton.pathForce.setChecked(True)

        self.createRadioButton.mZonepathForce.setText( self.valueRadioPathZone )
        self.createRadioButton.mZonepathForce.setEnabled(False if self.valueRadioPath == 1 else True)

    #===============================              
    def return_HTTP_PROXY_GPF_GIDISTRIBUTION(self, typeInitOrTest)  :
        if typeInitOrTest   == "INITIALISATION" : 
           _selectQComboBox_GPF_Proxy = self.selectQComboBox_GPF_Proxy 
           _selectQComboBox_GI_Proxy  = self.selectQComboBox_GI_Proxy 
        elif typeInitOrTest == "TEST PLATEFORME" :
           _selectQComboBox_GPF_Proxy = self.listQComboBoxProxy.index( self.mZoneChoiceProxygpf.currentText() )
           _selectQComboBox_GI_Proxy  = self.listQComboBoxProxy.index( self.mZoneChoiceProxyGIDistribution.currentText() )
         
        if   _selectQComboBox_GI_Proxy  == 0 :  
           return_HTTP_PROXY_GI_DISTRIBUTION = ""      
        elif _selectQComboBox_GI_Proxy  == 1 :        
           return_HTTP_PROXY_GI_DISTRIBUTION = self.return_Proxy_Qgis("GI_DISTRIBUTION")    
        elif _selectQComboBox_GI_Proxy  == 2 :
           return_HTTP_PROXY_GI_DISTRIBUTION = self.mZoneLabelProxyGIDistribution.text().strip()
        else :         
           return_HTTP_PROXY_GI_DISTRIBUTION = ""
                
        if _selectQComboBox_GPF_Proxy == 0:
            return_HTTP_PROXY_GPF = ""
        elif _selectQComboBox_GPF_Proxy == 1:
            proxy = self.return_Proxy_Qgis("GPF")
            if not (proxy is None or proxy == "") :
               # Vérifie si l'URL commence par http:// ou https://
               if not re.match(r"^https?://", proxy):
                   # Ajoute http:// si le préfixe est manquant
                   proxy = "http://" + proxy
            return_HTTP_PROXY_GPF = proxy
        elif _selectQComboBox_GPF_Proxy == 2:
            proxy = self.mZoneLabelProxygpf.text().strip()
            if not (proxy is None or proxy == "") :
               # Vérifie si l'URL commence par http:// ou https://
               if not re.match(r"^https?://", proxy):
                   # Ajoute http:// si le préfixe est manquant
                   proxy = "http://" + proxy
                   # Met à jour le champ avec l'URL corrigée
                   self.mZoneLabelProxygpf.setText(proxy)
            return_HTTP_PROXY_GPF = proxy
        else:
            return_HTTP_PROXY_GPF = ""
            
        return return_HTTP_PROXY_GPF, return_HTTP_PROXY_GI_DISTRIBUTION

    #===============================              
    def return_Proxy_Qgis( self, _plateforme )  :
        settings = QgsSettings()
        try :
           proxy_host = settings.value("proxy/proxyHost", "", type=str)  # Adresse du proxy
           proxy_port = settings.value("proxy/proxyPort", 0, type=int)  # Port du proxy
        except :
        
           proxy_host = str(self.HTTP_PROXY_GPF) if _plateforme == "GPF" else str(self.HTTP_PROXY_GI_DISTRIBUTION) 
           proxy_port = "8080"
        
        return str(proxy_host) + ":" + str(proxy_port)

    #===============================              
    def filtresParametres(self) :
        #-
        #-  TITRE
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Parameters", None)
        mTextToolTip = ""
        #-
        # OPTIONS FILTRES
        # Id, [ libelle, code ]
        self.mDicQComBox = QGIREFERENTIELS_REFERENTIEL
        #- 
        _Listkeys   = [ "typeWidget",           "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QComboBox()  ,"mZoneLang",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QComboBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneLang   = genereButtonWithDict( dicParamButton )
        mZoneLang.addItems( [value[0] for value in self.mDicQComBox["LANG"]] )
        self.mZoneLang = mZoneLang
        self.mZoneLang.setVisible(False)
        #self.layout_QSplitterFiltre_Haut.addWidget(mZoneLang,1 ,0 ,1 ,4 )
        #-  LANG

        #-  PLATEFORME
        _Listkeys   = [ "typeWidget",           "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QComboBox()  ,"mZoneChoicePlateforme",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QComboBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoicePlateforme   = genereButtonWithDict( dicParamButton )
        
        # Test de connexion sur GI Distribution pour alimenter la QComBoBox
        if self.functionTestPlateformeGIDistributionForQcomboBox(URL_CATALOGUE_DISTRIBUTION, self.mZoneValueloginGI.text(), self.mZoneValuemdpGI.text()) :         
           mZoneChoicePlateforme.addItems( [value[0] for value in self.mDicQComBox["PLATEFORME"]] )
        else :   
           mZoneChoicePlateforme.addItem( "Géoplateforme" )
           
        self.mZoneChoicePlateforme = mZoneChoicePlateforme
        self.mZoneChoicePlateforme.currentTextChanged.connect(lambda : self.functionSaveDeleteInitFilter( "mZoneChoicePlateforme_currentTextChanged" ))
        self.layout_QSplitterFiltre_Haut.addWidget(mZoneChoicePlateforme,1 ,0 ,1 ,4)
        #-  PLATEFORME

        #- Les filtres dates 
        self.createRadioButtonDate = RadioButtonDate(self)
        self.layout_QSplitterFiltre_Date.addWidget(self.createRadioButtonDate.sous_groupBox_radio_date, 0, 0, 1, 4)
        
        #==========================
        #QComboBox Save et Load xml sauvegarde des filtres
        _Listkeys   = [ "typeWidget",          "nameWidget",         "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ filtreQComboBox(), "mZoneQComboSaveLoadFilter",  mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QComboBox {  font-family:" + self.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneQComboSaveLoadFilter = genereButtonWithDict( dicParamButton )
        self.mZoneQComboSaveLoadFilter = mZoneQComboSaveLoadFilter
        #Button AppliquerAll and Appliquer
        self.layout_buttons_Appliquer = QtWidgets.QHBoxLayout()

        #Button Add et Delete
        self.layout_buttons_Save_del_filter = QtWidgets.QHBoxLayout()
        self.layout_buttons_Save_del_filter.addWidget(self.mZoneQComboSaveLoadFilter)
        #Button Save Filtre
        self.buttonSaveFilter = QtWidgets.QToolButton()
        self.buttonSaveFilter.setObjectName("buttonSaveFilter")
        self.buttonSaveFilter.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/general/save.svg"))
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Save Filter.", None)
        self.buttonSaveFilter.setToolTip(mTextToolTip)
        self.layout_buttons_Save_del_filter.addWidget(self.buttonSaveFilter)
        self.buttonSaveFilter.setEnabled(False)
        #Button Save Filtre

        #Button Delete
        self.buttonDeleteFilter = QtWidgets.QToolButton()
        self.buttonDeleteFilter.setObjectName("buttonDeleteFilter")
        self.buttonDeleteFilter.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/delete.svg"))
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Delete Filter.", None)
        self.buttonDeleteFilter.setToolTip(mTextToolTip)
        self.layout_buttons_Save_del_filter.addWidget(self.buttonDeleteFilter)
        self.buttonDeleteFilter.setEnabled(False)
        #--                        
        #Button Favori
        self.buttonFavori = QtWidgets.QToolButton()
        self.buttonFavori.setObjectName("buttonFavori")
        self.buttonFavori.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favori.svg"))
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Favori Filter.", None)
        self.buttonFavori.setToolTip(mTextToolTip)
        self.layout_buttons_Save_del_filter.addWidget(self.buttonFavori)
        self.buttonFavori.setEnabled(True)
        #QComboBox Save et Load xml sauvegarde des filtres
        self.initQComboSaveLoadFilter()
        self.mZoneQComboSaveLoadFilter.setCurrentText(self.valueFavoriFilter)

        #-  TreeviewFiltreParametresFORMAT
        #-
        mZoneFiltreParametresFormat = TreeviewFiltreParametres("FORMATS")
        self.mZoneFiltreParametresFormat = mZoneFiltreParametresFormat
        self.mZoneFiltreParametresFormat.setStyleSheet(   "QTreeView  {  font-family:" + self.policeQGroupBox  +";}" )
        self.mZoneFiltreParametresFormat.setObjectName("mZoneFiltreParametresFormat") 
        self.mZoneFiltreParametresFormat.afficheFiltreParametres(self, self.mDicQComBox)
        self.layout_QSplitterFiltre_Middle.addWidget(mZoneFiltreParametresFormat,1 ,0 , 1, 4)

        #-  TreeviewFiltreParametresZONE
        #-
        mZoneFiltreParametresZone = TreeviewFiltreParametres("ZONES")
        self.mZoneFiltreParametresZone = mZoneFiltreParametresZone
        self.mZoneFiltreParametresZone.setStyleSheet(   "QTreeView  {  font-family:" + self.policeQGroupBox  +";}" )
        self.mZoneFiltreParametresZone.setObjectName("mZoneFiltreParametresZone") 
        self.mZoneFiltreParametresZone.afficheFiltreParametres(self, self.mDicQComBox)
        self.layout_QSplitterFiltre_Bas.addWidget(mZoneFiltreParametresZone,1 ,0, 1, 4 )

        #-  TreeviewFiltreParametres
        #---
        # Important la déclaration
        self.referencesFiltres = { "mZoneFiltreParametresZone" : (self.mZoneFiltreParametresZone, ["ZONE","REGIONMETRO", "REGIONOUTREMER", "NATIONAL", "FRANCEENTIERE", "RACINE"]), "mZoneFiltreParametresFormat" : (self.mZoneFiltreParametresFormat, ["FORMAT"]) } 
        #-
        # Connection des boutons de filtres
        self.buttonSaveFilter.clicked.connect(lambda : self.functionSaveDeleteInitFilter("SaveFilter"))
        self.buttonDeleteFilter.clicked.connect(lambda : self.functionSaveDeleteInitFilter("DeleteFilter"))
        self.buttonFavori.clicked.connect(lambda : self.functionSaveDeleteInitFilter("Favori"))
        self.mZoneQComboSaveLoadFilter.currentTextChanged.connect(lambda : self.functionSaveDeleteInitFilter( "InitFilter" ))
        # Connection des boutons de filtres
        #==========================
        #Button Appliquez
        self.buttonAppliquer = QtWidgets.QToolButton()
        self.buttonAppliquer.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonAppliquer.setObjectName("buttonAppliquer")
        self.buttonAppliquer.setText(QtWidgets.QApplication.translate("qgientrepot_ui", "Apply", None))
        _addTooltip = QtWidgets.QApplication.translate("qgientrepot_ui", "Display catalogs by applying filters.", None)
        self.buttonAppliquer.setToolTip(_addTooltip)
        self.buttonAppliquer.clicked.connect(lambda : self.functionApplyParam(self.mDicQComBox))
        #Button Appliquez
        #- 
        #==========================
        #Button Afficher tout le catalogue
        self.buttonAfficherAll = QtWidgets.QToolButton()
        self.buttonAfficherAll.setStyleSheet(   "QToolButton  {  font-family:" + self.policeQGroupBox  +";}" )
        self.buttonAfficherAll.setObjectName("buttonAfficherAll")
        self.buttonAfficherAll.setText(QtWidgets.QApplication.translate("qgientrepot_ui", "buttonAfficherAll", None))
        _addTooltip = QtWidgets.QApplication.translate("qgientrepot_ui", "Display all catalogs without filters.", None)
        self.buttonAfficherAll.setToolTip(_addTooltip)
        self.buttonAfficherAll.clicked.connect(lambda : self.functionApplyParam(self.mDicQComBox, "ALL"))
        #-
        self.layout_QSplitter_Right.addWidget(self.groupBox_Appliquer_GestionFiltres, 6, 0, 1, 4)
        #Button Appliquez
        self.layout_Appliquer_GestionFiltres.addWidget(self.buttonAfficherAll, 0, 0, Qt.AlignmentFlag.AlignCenter)
        self.layout_Appliquer_GestionFiltres.addWidget(self.buttonAppliquer  , 0, 1, Qt.AlignmentFlag.AlignCenter)
        #Button Delete
        self.layout_buttons_Save_del_filter.addStretch()
        self.layout_Appliquer_GestionFiltres.addLayout(self.layout_buttons_Save_del_filter, 1, 0, 1, 2)
        #==========================
        #- 
        return

    #===============================              
    def functionTestPlateformeGIDistributionForQcomboBox(self, url, username, password) :
        #Récupère les proxy en fonction des données de l'IHM personnalisation
        return_HTTP_PROXY_GPF, return_HTTP_PROXY_GI_DISTRIBUTION = self.return_HTTP_PROXY_GPF_GIDISTRIBUTION("TEST PLATEFORME")
        _HTTP_PROXY_GPF       = return_HTTP_PROXY_GPF                       #Proxy HTTP
        _HTTPS_PROXY_GPF      = _HTTP_PROXY_GPF                             #Proxy HTTPS
        _HTTP_PROXY_GI_DISTRIBUTION  = return_HTTP_PROXY_GI_DISTRIBUTION    #Proxy HTTP_PROXY_GI_DISTRIBUTION
        _HTTPS_PROXY_GI_DISTRIBUTION = _HTTP_PROXY_GI_DISTRIBUTION          #Proxy HTTP_PROXY_GI_DISTRIBUTION
        
        zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)

        try:
           os.environ["HTTP_PROXY"]  = _HTTP_PROXY_GI_DISTRIBUTION
           os.environ["HTTPS_PROXY"] = _HTTPS_PROXY_GI_DISTRIBUTION
           os.environ["http_proxy"]  = _HTTP_PROXY_GI_DISTRIBUTION
           os.environ["https_proxy"] = _HTTPS_PROXY_GI_DISTRIBUTION
           
           # Récupérer le fichier XML depuis le serveur
           response = requests.get(url, auth=(username, password))
           response.raise_for_status()
           return True

        except requests.exceptions.RequestException as e:
           return False

        except Exception as e:
           return False

        except :
           return False

        return False

    #===============================              
    def functionTestPlateforme(self, action, url, username, password) :
        #Récupère les proxy en fonction des données de l'IHM personnalisation
        return_HTTP_PROXY_GPF, return_HTTP_PROXY_GI_DISTRIBUTION = self.return_HTTP_PROXY_GPF_GIDISTRIBUTION("TEST PLATEFORME")
        _HTTP_PROXY_GPF       = return_HTTP_PROXY_GPF                       #Proxy HTTP
        _HTTPS_PROXY_GPF      = _HTTP_PROXY_GPF                             #Proxy HTTPS
        _HTTP_PROXY_GI_DISTRIBUTION  = return_HTTP_PROXY_GI_DISTRIBUTION    #Proxy HTTP_PROXY_GI_DISTRIBUTION
        _HTTPS_PROXY_GI_DISTRIBUTION = _HTTP_PROXY_GI_DISTRIBUTION          #Proxy HTTP_PROXY_GI_DISTRIBUTION
        
        if action == "GIDistribution" :
           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Warning" , None)

           try:
              os.environ["HTTP_PROXY"]  = _HTTP_PROXY_GI_DISTRIBUTION
              os.environ["HTTPS_PROXY"] = _HTTPS_PROXY_GI_DISTRIBUTION
              os.environ["http_proxy"]  = _HTTP_PROXY_GI_DISTRIBUTION
              os.environ["https_proxy"] = _HTTPS_PROXY_GI_DISTRIBUTION
              
              # Récupérer le fichier XML depuis le serveur
              response = requests.get(url, auth=(username, password))
              response.raise_for_status()

              zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "Successful connection to Géo-IDE Distribution." , None)
              QMessageBox.information(self, zTitre, zMess1)

           except requests.exceptions.RequestException as e:
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "The test failed." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on Géo-IDE Distribution." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An exception was thrown of type exceptions.RequestException:" , None)           
              zMess1 += "\n" + f"{e}"
              QMessageBox.warning(self, zTitre, zMess1)

           except Exception as e:
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "The test failed." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on Géo-IDE Distribution." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An exception was thrown of type exceptions:" , None)           
              zMess1 += "\n" + f"{e}"
              QMessageBox.warning(self, zTitre, zMess1)

           except :
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "The test failed." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on Géo-IDE Distribution." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A general exception was thrown." , None)           
              QMessageBox.warning(self, zTitre, zMess1)

        elif action == "GPF" :
           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Warning" , None)
           _lang = 'FR'
           _zone = None
           _format = None
           try:
              self.instanceGeoIdeDistributionTest = GeoIdeDistribution(self.URL_API_GPF, self.URL_API_GPF_PRIVATE, self.mValueLoginGPF, _HTTP_PROXY_GPF, _HTTPS_PROXY_GPF, _HTTP_PROXY_GI_DISTRIBUTION, _HTTPS_PROXY_GI_DISTRIBUTION)
              #===============================
              ret = self.instanceGeoIdeDistributionTest.get_capabilities(50, 1, _lang, _zone, _format)
              if ret == None : 
                 zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "The test failed." , None)           
                 zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on the GéoPlatforme." , None)           
                 QMessageBox.warning(self, zTitre, zMess1)
              else :
                 zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "Successful connection to the GéoPlateforme." , None)
                 QMessageBox.information(self, zTitre, zMess1)

           except Exception as _err:
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "The test failed." , None)           
              zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on the GéoPlatforme." , None)           
              QMessageBox.warning(self, zTitre, zMess1)
        return

    #===============================              
    def functionChangeProxy(self, action) :
        if action == "mZoneLabelProxyGIDistribution" :
           self.mZoneLabelProxyGIDistribution.setEnabled(False if self.listQComboBoxProxy.index( self.mZoneChoiceProxyGIDistribution.currentText() ) in (0, 1) else True)
        elif action == "mZoneLabelProxygpf" :    
           self.mZoneLabelProxygpf.setEnabled(False if self.listQComboBoxProxy.index( self.mZoneChoiceProxygpf.currentText() ) in (0, 1) else True)
        return
    
    #===============================              
    def functionApplyBasket(self, action) :
        self.mTreeListePanier.addBasket(self.mTreeListeDistribution)
        
        if action == "Add basket" :
           self.mTreeListePanier.addBasket(self.mTreeListeDistribution)
        elif action == "Empty basket" :
           #Vide le panier
           self.mTreeListePanier.clear()
           self.mTreeListePanier.desactiveQCheckBoxBasket(self.mTreeListeDistribution)
        elif action == "Download basket" :
           self.mTreeListePanier.traitement_DOWNLOAD_DIRECT_PANIER(self)
        elif action == "Generate basket" :
           self.mTreeListePanier.traitement_DOWNLOAD_SAVE_PANIER(self)
               
        updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
        return

    #===============================              
    def controlDateIHMPourValidation(self, ) :
        if self.createRadioButtonDate.radio_date_aucune.isChecked() :
           _radio = 1 
        elif self.createRadioButtonDate.radio_date_annee.isChecked() :
           _radio = 2 
        elif self.createRadioButtonDate.radio_date_periode.isChecked() :
           _radio = 3 
        else :
           _radio = 1 

        _millesime = True if self.createRadioButtonDate.mZoneChoiceDateDer.isChecked() else False        
        if _radio == 1 :   # Pas de date
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, None, None, _millesime
        elif _radio == 2 : # Année
           if self.createRadioButtonDate.mZoneDateAnnee.text() == "" or self.createRadioButtonDate.mZoneDateAnnee.text() == None :
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)
              zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "You forgot to enter the year." , None)
              # Vous avez oublié de saisir l'année.
              displayMess(self.Dialog, (2 if self.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.durationBarInfo)
              return None, None, None, None
           
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = self.createRadioButtonDate.mZoneDateAnnee.text(), None, None, None
        elif _radio == 3 : # Période
           if self.createRadioButtonDate.mZoneDateFrom.text() == "" or self.createRadioButtonDate.mZoneDateFrom.text() == None or self.createRadioButtonDate.mZoneDateTo.text() == "" or self.createRadioButtonDate.mZoneDateTo.text() == None:
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)
              zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "You forgot to enter the start year and/or end year of the period." , None)
              # Vous avez oublié de saisir l'année de début et/ou l'année de fin de la période.
              displayMess(self.Dialog, (2 if self.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.durationBarInfo)
              return None, None, None, None
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, self.createRadioButtonDate.mZoneDateFrom.text(), self.createRadioButtonDate.mZoneDateTo.text(), _millesime
        else :
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, None, None, _millesime

        return _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime
        
    #===============================              
    def functionApplyParam(self, _mDicQComBox, _all = None) :
        if _all != "ALL" :
           #Controle des dates
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = self.controlDateIHMPourValidation()
           #if _return_date_annee == None and _return_date_from == None and _return_date_to == None and _return_date_millesime in [None, False] : return # Cas où il manque une année 
    
        #Vide le panier
        #self.mTreeListePanier.clear()
        updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
        
        self._mDicQComBox = _mDicQComBox
        self.quellePlateforme = [ value for key, value in self._mDicQComBox["PLATEFORME"] if key == self.mZoneChoicePlateforme.currentText() ][0]
        
        _lang, _zone, _format = returnParametres(self)
        if _zone == "" : _zone = None 
        _retXml         = None
        xmlDistribution = None
        
        self.mTreeListeDistribution.clear()

        # Contrôle Saisie de l'organisation
        if self.mZoneValueOrganisation.text().strip() == "" or self.mZoneValueOrganisation.text().strip() is None : 
           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)
           zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "You must enter an organization in the 'Settings' tab to continue." , None)
           displayMess(self.Dialog, (2 if self.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.durationBarInfo)
           return

        _title = QtWidgets.QApplication.translate("qgidistribution_ui",  "PLUGIN QGIREFERENTIELS", None)
        # Gestion Catalogue Géo-IDE Distribution
        _geoide_distrib_http_user = self.mValueLoginGI
        _geoide_distrib_http_pass = self.mValueMdpGI 
        _fileXmlDistribution = get_and_read_xml(self,  URL_CATALOGUE_DISTRIBUTION, _geoide_distrib_http_user, _geoide_distrib_http_pass, self.HTTP_PROXY_GPF, self.HTTPS_PROXY_GPF, self.HTTP_PROXY_GI_DISTRIBUTION, self.HTTPS_PROXY_GI_DISTRIBUTION )
        #if _fileXmlDistribution == None : return     # Arrêt si pb de connexion
        
        #===============================
        # Gestion des dates              
        _return_date_from, _return_date_to, _return_date_millesime = self.returnDateFiltreParametres()
        if _return_date_from ==  None and _return_date_to == None and _return_date_millesime in [None, False] :
           _dateFrom, _dateTo, _return_date_millesime = None, None, None
        else :    
           _dateFrom, _dateTo, _return_date_millesime = _return_date_from, _return_date_to, _return_date_millesime
                 
        #Button Afficher avec Filtres
        if _all == None :
           _sauteStep = True
           if (_zone == None or _zone == "") and (_format == None or _format == "") :                 # cas ou format et zone non sélectionné
              if ( (_return_date_from != None) or (_return_date_millesime  not in [None, False]) ) :  # cas ou une date ou millésime est sélectionné 
                 # relance l'affichage 
                 _title = QtWidgets.QApplication.translate("qgidistribution_ui",  "PLUGIN QGIREFERENTIELS", None)
              
                 _sauteStep = False
                 if (self.quellePlateforme == "ALL" or self.quellePlateforme == "GPF") : _retXml = self.mTreeListeDistribution.initDistribution(self,  _lang = _lang, _dateFrom = _dateFrom, _dateTo = _dateTo)
                 
                 #GI DISTRI
                 if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                    self._first = None # Permet de passer dans alimenteArboDistribution
                    self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _format = _format)
                    xmlDistribution = analyseXmlDistribution(self, _fileXmlDistribution, _dateFrom = _dateFrom, _dateTo = _dateTo, _return_date_millesime = _return_date_millesime)
                    #print(xmlDistribution)
                 self.mTreeListeDistribution.afficheDistribution(self, _retXml, xmlDistribution, _plateforme = self.quellePlateforme)

           if _sauteStep :
              if _zone == "" or _zone == None : 
                 if not (_format == "" or _format == None) : 
                    #_mess =  QtWidgets.QApplication.translate("qgidistribution_ui",  "You have not entered any geographic area(s).", None) + "<br><br>" + QtWidgets.QApplication.translate("qgidistribution_ui",  "Do you want to continue ?", None)
                    #if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes|QMessageBox.StandardButton.No) ==  QMessageBox.StandardButton.No : return
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "GPF") : _retXml = self.mTreeListeDistribution.initDistribution(self,  _lang = _lang, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
                    
                    #GI DISTRI
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                       self._first = None # Permet de passer dans alimenteArboDistribution
                       self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _format = _format)
                       xmlDistribution = analyseXmlDistribution(self, _fileXmlDistribution, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo, _return_date_millesime = _return_date_millesime)
              else : 
                 if _format == "" or _format == None :
                    #_mess =  QtWidgets.QApplication.translate("qgidistribution_ui",  "You have not entered any format(s).", None) + "<br><br>" + QtWidgets.QApplication.translate("qgidistribution_ui",  "Do you want to continue ?", None)
                    #if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes|QMessageBox.StandardButton.No) ==  QMessageBox.StandardButton.No : return
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "GPF") :  _retXml = self.mTreeListeDistribution.initDistribution(self,  _lang = _lang, _zone = _zone, _dateFrom = _dateFrom, _dateTo = _dateTo)
                    
                    #GI DISTRI
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                       self._first = None # Permet de passer dans alimenteArboDistribution
                       self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _zone = _zone)
                       xmlDistribution = analyseXmlDistribution(self, _fileXmlDistribution, _zone = _zone, _dateFrom = _dateFrom, _dateTo = _dateTo, _return_date_millesime = _return_date_millesime)
                 else :  
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "GPF") : _retXml = self.mTreeListeDistribution.initDistribution(self,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
                    
                    #GI DISTRI
                    if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                       self._first = None # Permet de passer dans alimenteArboDistribution
                       self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _zone = _zone, _format = _format)
                       xmlDistribution = analyseXmlDistribution(self, _fileXmlDistribution, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo, _return_date_millesime = _return_date_millesime)

              self.mTreeListeDistribution.afficheDistribution(self, _retXml, xmlDistribution, _plateforme = self.quellePlateforme)
              
           else : # Cas ou rien n'est sélectionné et donc efface
              #---- N'affiche que les plateformes
              _retXml = self.mTreeListeDistribution.initDistribution(self, _first = "FIRST")
              self.mTreeListeDistribution.afficheDistribution(self, _retXml, None) 
                 
        #Button Afficher tout le catalogue
        if _all == "ALL" :
           _mess =  QtWidgets.QApplication.translate("qgidistribution_ui",  "You will display all catalogs without filters.", None) + "<br><br>" + QtWidgets.QApplication.translate("qgidistribution_ui",  "Do you want to continue ?", None)
           if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes|QMessageBox.StandardButton.No) ==  QMessageBox.StandardButton.No : return

           #Nécessaire pour instancier la variable instanceGeoIdeDistributionTelechargement
           self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _format = _format)
           
           # Désactive les filtres
           self.desactiveAll(self.mZoneFiltreParametresFormat)
           self.desactiveAll(self.mZoneFiltreParametresZone)
           
           self.createRadioButtonDate.radio_date_aucune.setChecked(True)
           self.createRadioButtonDate.mZoneDateAnnee.setText("")
           self.createRadioButtonDate.mZoneDateFrom.setText("")
           self.createRadioButtonDate.mZoneDateTo.setText("")
           self.createRadioButtonDate.mZoneChoiceDateDer.setChecked(False)
           # Désactive les filtres
           
           if (self.quellePlateforme == "ALL" or self.quellePlateforme == "GPF") :_retXml = self.mTreeListeDistribution.initDistribution(self)
           
           #GI DISTRI
           if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
              self._first = None # Permet de passer dans alimenteArboDistribution
              xmlDistribution = analyseXmlDistribution(self, _fileXmlDistribution, _dateFrom = _dateFrom, _dateTo = _dateTo, _return_date_millesime = None)

           if _retXml != None :
              self.mTreeListeDistribution.afficheDistribution(self, _retXml, xmlDistribution, _plateforme = self.quellePlateforme)         
           else :
              # Obligatoire pour traiter GI Distribution sans GPF
              if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                 self._first = None # Permet de passer dans alimenteArboDistribution
                 if (self.quellePlateforme == "ALL" or self.quellePlateforme == "MTE") : 
                    self.mTreeListeDistribution.initDistributionGIDistributionFiltre(self,  _lang = _lang, _zone = _zone, _format = _format)
                 self.mTreeListeDistribution.afficheDistribution(self, _retXml, xmlDistribution, _plateforme = self.quellePlateforme)         
        
        self.xmlDistributionReturnFunctionApplyParam = xmlDistribution
        return 

    #===============================              
    def functionSaveLoadBasket(self, _action) :
        if _action == "SavePanier" :
           InitDir  = str(self.mZoneQComboValuePathReferentiel.currentText())
           _text = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Save basket" , None)
           fileName = QFileDialog.getSaveFileName(self, _text, InitDir, "Fichier de sauvegarde du panier (*.xml)" )[0]
           if fileName == "" : return

           tree = ET.Element("QGIRéférentiels")

           # écrire chaque item
           def write_item(item, parent):
               xml_item = ET.SubElement(parent, "Item")
               xml_item.set("text", item.text(0)) 
               xml_item.set("col2", item.text(1)) 
               xml_item.set("col3", item.text(2)) 
               xml_item.set("iconpath", item.text(3)) 
               xml_item.set("lot", item.text(4)) 

               # Récursivement ajouter les enfants
               for i in range(item.childCount()):
                   write_item(item.child(i), xml_item)

           # Parcourir tous les éléments racines
           for i in range(self.mTreeListePanier.topLevelItemCount()):
               write_item(self.mTreeListePanier.topLevelItem(i), tree)

           tree_element = ET.ElementTree(tree)
           tree_element.write(fileName, encoding="utf-8", xml_declaration=True)

           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)

           zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)           
           zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The file " , None)
           zMess1 += fileName           
           zMess1 += "\n\n" + QtWidgets.QApplication.translate("qgidistribution_ui", " has been created." , None)           
           displayMess(self.Dialog, (2 if self.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.durationBarInfo)
        
        elif _action == "LoadPanier" :
           InitDir  = str(self.mZoneQComboValuePathReferentiel.currentText())
           _text = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Load basket" , None)
           _filter = QtWidgets.QApplication.translate("qgidistribution_ui", "Cart backup file (*.xml)" , None)
           fileName = QFileDialog.getOpenFileName(self, _text, InitDir, _filter )[0]
           if fileName == "" : return

           self.mTreeListePanier.clear()

           try:
              tree = ET.parse(fileName)
              root = tree.getroot()
           except ET.ParseError as e:
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "XML error" , None)           
              zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The XML file is invalid:" , None)
              zMess1 += "\n\n" + f"{str(e)}"           
              QMessageBox.critical(self, zTitre, zMess1)
              updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
              return
           except Exception as e:
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Error" , None)           
              zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An error occurred while opening the file:" , None)
              zMess1 += "\n\n" + f"{str(e)}"           
              QMessageBox.critical(self, zTitre, zMess1)
              updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
              return           

           def add_item_to_tree(item, parent=None):
               # Créer un QTreeWidgetItem pour cet élément
               qtree_item = QTreeWidgetItem(parent, [item.attrib["text"], item.attrib["col2"], item.attrib["col3"], item.attrib["iconpath"], item.attrib["lot"]])
               
               if item.attrib["col2"].upper() == "PLATEFORME" : 
                  if item.attrib["col3"].upper() == "GPF" : 
                     menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf.svg"), 25)  
                  elif item.attrib["col3"].upper() == "GPFPRIVATE" : 
                     menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf_private.svg"), 25)  
                  elif item.attrib["col3"].upper() == "GI" :   
                     menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/distribution.svg"), 25)  
                  qtree_item.setIcon(0, menuIcon)
               else :
                  if item.attrib["col3"].upper() == "RESSOURCE" or item.attrib["col3"].upper() == "RESSOURCEGIDISTRIBUTION" : 
                     menuIcon = returnIcon(item.attrib["iconpath"], 25)  
                     qtree_item.setIcon(0, menuIcon)

               if item.attrib["col3"].upper() not in ["RESSOURCE", "RESSOURCEGIDISTRIBUTION"] :
                  qtree_item.setExpanded(True)

               # Ajouter récursivement les enfants
               for child in item:
                   add_item_to_tree(child, qtree_item)

           try:
              # Ajouter tous les éléments racines du XML
              for item in root:
                  add_item_to_tree(item, self.mTreeListePanier)
           except :
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Error" , None)           
              zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An error occurred while reading the XML file" , None)
              QMessageBox.critical(self, zTitre, zMess1)
              updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
              return

        updateLibelleQCheckBoxSelectObjets(self, self.mTreeListeDistribution, self.mTreeListePanier)
        mappingIsoTreeDistributionTreePanier(self, self.mTreeListeDistribution, self.mTreeListePanier)
        return

    #===============================              
    def functionSaveDeleteInitFilter(self, _action):
        if _action == "mZoneChoicePlateforme_currentTextChanged":
           self.buttonSaveFilter.setEnabled(True)
           return

        _pathUserFilter = Path(QgsApplication.qgisSettingsDirPath().replace("\\", "/") + "qgireferentiels/filtres")
        createFolder(_pathUserFilter)
        self.fileNameFilter = Path(_pathUserFilter, "qgireferentielfiltres.xml")

        if _action == "SaveFilter":
           # Boîte de dialogue pour nom du filtre
           boiteDialogueSaveFilter = BoiteDialogue(self)
           boiteDialogueSaveFilter.setWindowTitle(QtWidgets.QApplication.translate("qgientrepot_ui", "Please enter a filter Name", None))
           _pathIcons = os.path.dirname(__file__) + "/icons/logo"
           icon = QtGui.QIcon()
           icon.addPixmap(QtGui.QPixmap(_pathIcons + "/qgireferentiels.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
           boiteDialogueSaveFilter.setWindowIcon(icon)
           boiteDialogueSaveFilter.exec()
           textNameFilter = boiteDialogueSaveFilter.textNameFilter
           if textNameFilter is None: return
           if self.fileNameFilter == "": return

           self._mZoneQComboSaveLoadFilterEnCours = self.mZoneQComboSaveLoadFilter.currentText()          
           # Fonction récursive pour écrire les items
           def write_item(item, parent_xml_element, _colonneNiveau3):
               check_state = item.checkState(0)
               if check_state in (Qt.CheckState.Checked, Qt.CheckState.PartiallyChecked):
                  xml_item = ET.SubElement(parent_xml_element, "Item")
                  xml_item.set("libelle", item.text(0))
                  xml_item.set("code", item.text(1))
                  xml_item.set("niveau", item.text(2))
                  for i in range(item.childCount()):
                      write_item(item.child(i), xml_item, _colonneNiveau3)

           # Chargement ou création XML
           if os.path.exists(self.fileNameFilter):
              try:
                 tree = ET.parse(self.fileNameFilter)
                 root = tree.getroot()
              except ET.ParseError as e:
                 zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
                 zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Error" , None)           
                 zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The XML file is invalid:" , None)
                 zMess1 += "\n\n" + f"{str(e)}"           
                 QMessageBox.critical(self, zTitre, zMess1)
                 return
              except Exception as e:
                 zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
                 zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Error" , None)           
                 zMess1 += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An error occurred while opening the file:" , None)
                 zMess1 += "\n\n" + f"{str(e)}"           
                 QMessageBox.critical(self, zTitre, zMess1)
                 return
           else:
              root = ET.Element("QGIRéférentiels_Filtres")
              tree = ET.ElementTree(root)

           _firstUniqueQuestion = True
           for ref_name, tree_widget_tuple in self.referencesFiltres.items():
               tree_widget, colonneNiveau3 = tree_widget_tuple

               # Recherche ou création de <Référence>
               ref_element = next((ref for ref in root.findall("Référence") if ref.get("nom") == ref_name), None)
               if ref_element is None:
                  ref_element = ET.SubElement(root, "Référence", nom=ref_name)

               # Suppression d'un filtre existant
               for child in list(ref_element):  # on fait une copie avec list() pour éviter les problèmes en modifiant pendant la boucle
                   if child.tag == "Filtre" and child.get("nom") == textNameFilter:
                      if _firstUniqueQuestion:
                          _title = QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Warning", None)
                          _mess  = QtWidgets.QApplication.translate("qgidistribution_ui", "The filter " , None)           
                          _mess += f"{textNameFilter}"           
                          _mess += QtWidgets.QApplication.translate("qgidistribution_ui", " already exists." , None)
                          _mess += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "Do you want to replace it ?" , None)

                          if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) == QMessageBox.StandardButton.No:
                             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                             return
                      ref_element.remove(child)
                      break

               # Création <Filtre>
               nom_filtre = ET.SubElement(ref_element, "Filtre", nom=textNameFilter)

               for i in range(tree_widget.topLevelItemCount()):
                   top_item = tree_widget.topLevelItem(i)
                   write_item(top_item, nom_filtre, colonneNiveau3)

               _firstUniqueQuestion = False

           #====================
           # Gestion Plateforme
           self.gestionFiltrePlateforme( "SaveFilter", root, textNameFilter) 
           #====================

           #====================
           # Gestion Dates
           self.gestionFiltreDates( "SaveFilter", root, textNameFilter) 
           #====================

           tree.write(self.fileNameFilter, encoding="utf-8", xml_declaration=True)
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        elif _action == "DeleteFilter":
             textNameFilterDelete = self.retourneTexteQcomboBoxSansIconeFavori(self.mZoneQComboSaveLoadFilter.currentText())
             if textNameFilterDelete == "Aucun": return
             tree = ET.parse(self.fileNameFilter)
             root = tree.getroot()
             filtre_supprime = False

             for ref_name, tree_widget_tuple in self.referencesFiltres.items():
                 ref_element = next((ref for ref in root.findall("Référence") if ref.get("nom") == ref_name), None)
                 if ref_element is None: continue

                 filtre_to_delete = next((filtre for filtre in ref_element.findall("Filtre") if filtre.get("nom") == textNameFilterDelete), None)
                 if filtre_to_delete is not None:
                    ref_element.remove(filtre_to_delete)
                    filtre_supprime = True

             #====================
             # Gestion Plateforme
             self.gestionFiltrePlateforme( "DeleteFilter", root, textNameFilterDelete) 
             #====================

             #====================
             # Gestion Dates
             self.gestionFiltreDates( "DeleteFilter", root, textNameFilterDelete) 
             #====================

             if filtre_supprime:
                tree.write(self.fileNameFilter, encoding="utf-8", xml_declaration=True)

             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        elif _action == "InitFilter":
             if not os.path.exists(self.fileNameFilter):return
        
             textNameFilterInit = self.retourneTexteQcomboBoxSansIconeFavori(self.mZoneQComboSaveLoadFilter.currentText())
             tree = ET.parse(self.fileNameFilter)
             root = tree.getroot()

             #---------------------------------------------------------
             # Fonction pour forcer la mise à jour des états des parents
             def update_parent_checkstate(item):
                 parent = item.parent()
                 if parent is None:
                     return
                 checked = 0
                 unchecked = 0
                 for i in range(parent.childCount()):
                     state = parent.child(i).checkState(0)
                     if state == Qt.CheckState.Checked:
                         checked += 1
                     elif state == Qt.CheckState.Unchecked:
                         unchecked += 1
                 if checked == parent.childCount():
                     parent.setCheckState(0, Qt.CheckState.Checked)
                 elif unchecked == parent.childCount():
                     parent.setCheckState(0, Qt.CheckState.Unchecked)
                 else:
                     parent.setCheckState(0, Qt.CheckState.PartiallyChecked)
                 update_parent_checkstate(parent)

             #---------------------------------------------------------
             # Fonction pour ouvrir les branches cochées et fermer les autres
             def expand_checked_and_collapse_unchecked(tree_widget):
                 def recurse(item):
                     any_checked = False
                     for i in range(item.childCount()):
                         child = item.child(i)
                         if recurse(child):
                             any_checked = True
                     is_checked = item.checkState(0) == Qt.CheckState.Checked
                     item.setExpanded(is_checked or any_checked)
                     return is_checked or any_checked
                 for i in range(tree_widget.topLevelItemCount()):
                     top = tree_widget.topLevelItem(i)
                     recurse(top)

             # Activation des bonnes zones
             for ref_name, tree_widget_tuple in self.referencesFiltres.items():
                 tree_widget, colonneNiveau3 = tree_widget_tuple
                 ref_element = next((ref for ref in root.findall("Référence") if ref.get("nom") == ref_name), None)
                 if ref_element is None: continue

                 # Désactivation totale si "Aucun"
                 if textNameFilterInit == "Aucun":
                     for i in range(tree_widget.topLevelItemCount()):
                         item_lvl1 = tree_widget.topLevelItem(i)
                         item_lvl1.setCheckState(0, Qt.CheckState.Unchecked)
                         for j in range(item_lvl1.childCount()):
                             item_lvl2 = item_lvl1.child(j)
                             item_lvl2.setCheckState(0, Qt.CheckState.Unchecked)
                             for k in range(item_lvl2.childCount()):
                                 item_lvl3 = item_lvl2.child(k)
                                 item_lvl3.setCheckState(0, Qt.CheckState.Unchecked)
                                 update_parent_checkstate(item_lvl3)
                     expand_checked_and_collapse_unchecked(tree_widget)


                     # Si Aucun, remet les deux plateformes dans la QComboBox
                     # Théoriquement 'Géo-IDE Distribution / Géoplateforme'
                     self.mZoneChoicePlateforme.setCurrentText( [value[0] for value in self.mDicQComBox["PLATEFORME"]][0] )

                     continue

                 filtre_a_appliquer = next((filtre for filtre in ref_element.findall("Filtre") if filtre.get("nom") == textNameFilterInit), None)
                 if filtre_a_appliquer is None: continue

                 zones_a_cocher = []
                 def collect_zones(elem):
                     if elem.tag == "Item" and elem.get("niveau") in colonneNiveau3 :
                        zones_a_cocher.append(elem.get("libelle"))
                     for child in elem.findall("Item"):
                         collect_zones(child)

                 for item in filtre_a_appliquer.findall("Item"):
                     collect_zones(item)

                 # Parcours et activation
                 for i in range(tree_widget.topLevelItemCount()):
                     def apply_check(item):
                         if item.text(0) in zones_a_cocher:
                            item.setCheckState(0, Qt.CheckState.Checked)
                         else:
                            item.setCheckState(0, Qt.CheckState.Unchecked)
                         for j in range(item.childCount()):
                             apply_check(item.child(j))
                     apply_check(tree_widget.topLevelItem(i))

                 expand_checked_and_collapse_unchecked(tree_widget)
             
             #====================
             # Gestion Plateforme
             self.gestionFiltrePlateforme( "textNameFilterInit", root, textNameFilterInit) 
             #====================

             #====================
             # Gestion Dates
             self.gestionFiltreDates( "textNameFilterInit", root, textNameFilterInit) 
             #====================

             #-----------------
             #gestion du bouton sauvegarde si je modifie par un clic un filtre existant
             self.buttonSaveFilter.setEnabled(False)
    
             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
             QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        # Rafraîchissement combo / boutons
        if _action != "InitFilter" and _action != "Favori":
           self.initQComboSaveLoadFilter()
           if _action != "DeleteFilter":
              self.mZoneQComboSaveLoadFilter.setCurrentText(textNameFilter)
           self.reinitAffichageSaveAndDeleteFilterifExisteCaseCochee(self)
           
        if _action == "Favori":
            mSettings = QgsSettings()
            mSettings.beginGroup("QGIREFERENTIELS")
            mSettings.beginGroup("Generale")
            mDicAutre = {}
            mDicAutre["valueFavoriFilter"] = self.retourneTexteQcomboBoxSansIconeFavori(self.mZoneQComboSaveLoadFilter.currentText())    
            self.valueFavoriFilter         = self.retourneTexteQcomboBoxSansIconeFavori(self.mZoneQComboSaveLoadFilter.currentText()) 
            _texteCourantQcomboBox         = self.mZoneQComboSaveLoadFilter.currentText()  

            for key, value in mDicAutre.items():
                mSettings.setValue(key, value)
            mSettings.endGroup()

            # Réinitialsie le contenu de la QComBox pour le gras par défaut
            self.initQComboSaveLoadFilter(self.valueFavoriFilter)
            self.mZoneQComboSaveLoadFilter.setCurrentText(self.valueFavoriFilter)

            # Icone favori       
            self.buttonFavori.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favoridefaut.svg"))

        if _action == "SaveFilter":
           #-----------------
           #gestion du bouton sauvegarde si je modifie par un clic un filtre existant
           self.buttonSaveFilter.setEnabled(False)

        return

    #====================
    # Gestion Plateforme
    #===============================              
    def gestionFiltrePlateforme(self, _action, root, textNameFilter) :
        id_quellePlateforme = [ value for key, value in self.mDicQComBox["PLATEFORME"] if key == self.mZoneChoicePlateforme.currentText() ][0]
        ref_name = "Plateformes"
        ref_element = next((ref for ref in root.findall("Référence") if ref.get("nom") == ref_name), None)

        if _action == "SaveFilter":
           # Recherche ou création de <Référence>
           if ref_element is None:
              ref_element = ET.SubElement(root, "Référence", nom=ref_name)
           # Recherche du <Filtre> existant
           nom_filtre = next((f for f in ref_element.findall("Filtre") if f.get("nom") == textNameFilter), None)
           if nom_filtre is None:
              nom_filtre = ET.SubElement(ref_element, "Filtre", nom=textNameFilter)
              xml_item = ET.SubElement(nom_filtre, "Item")
           else:
              xml_item = nom_filtre.find("Item")
              if xml_item is None:
                 xml_item = ET.SubElement(nom_filtre, "Item")
           xml_item.set("plateforme_selectionnee", id_quellePlateforme)

        elif _action == "DeleteFilter":
           if ref_element is not None:
               filtres = ref_element.findall("Filtre")
               for f in filtres:
                   if f.get("nom") == textNameFilter:
                       ref_element.remove(f)
                       break

        elif _action == "textNameFilterInit":
           if ref_element is not None:
              filtres = ref_element.findall("Filtre")
              for f in filtres:
                  if f.get("nom") == textNameFilter:
                      item = f.find("Item")
                      if item is not None:
                          valeur_plateforme = item.get("plateforme_selectionnee")
                          valeur_plateforme = valeur_plateforme if valeur_plateforme in [ value for key, value in self.mDicQComBox["PLATEFORME"] ] else 'ALL'
                          lib_quellePlateforme = [ key for key, value in self.mDicQComBox["PLATEFORME"] if value == valeur_plateforme ][0]
                          self.mZoneChoicePlateforme.setCurrentText(lib_quellePlateforme)

        return
    # Gestion Plateforme
    #====================

    #====================
    # Gestion Dates
    #===============================              
    def gestionFiltreDates(self, _action, root, textNameFilter) :
        #Lecture des infos via IHM
        if self.createRadioButtonDate.radio_date_aucune.isChecked() :
           _radio = 1 
        elif self.createRadioButtonDate.radio_date_annee.isChecked() :
           _radio = 2 
        elif self.createRadioButtonDate.radio_date_periode.isChecked() :
           _radio = 3 
        else :
           _radio = 1 

        _millesime = True if self.createRadioButtonDate.mZoneChoiceDateDer.isChecked() else False        

        if _radio == 1 :   # Pas de date
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, None, None, _millesime
        elif _radio == 2 : # Année
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = self.createRadioButtonDate.mZoneDateAnnee.text(), None, None, None
        elif _radio == 3 : # Période
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, self.createRadioButtonDate.mZoneDateFrom.text(), self.createRadioButtonDate.mZoneDateTo.text(), _millesime
        else :
           _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, None, None, _millesime

        ref_name = "Dates"
        ref_element = next((ref for ref in root.findall("Référence") if ref.get("nom") == ref_name), None)

        if _action == "SaveFilter":
           # Recherche ou création de <Référence>
           if ref_element is None:
              ref_element = ET.SubElement(root, "Référence", nom=ref_name)
           # Recherche du <Filtre> existant
           nom_filtre = next((f for f in ref_element.findall("Filtre") if f.get("nom") == textNameFilter), None)
           if nom_filtre is None:
              nom_filtre = ET.SubElement(ref_element, "Filtre", nom=textNameFilter)
              xml_item = ET.SubElement(nom_filtre, "Item")
           else:
              xml_item = nom_filtre.find("Item")
              if xml_item is None:
                 xml_item = ET.SubElement(nom_filtre, "Item")
           xml_item.set("Radio_date",     str(_radio))
           xml_item.set("Date_annee",     str(_return_date_annee))
           xml_item.set("Date_from",      str(_return_date_from))
           xml_item.set("Date_to",        str(_return_date_to))
           xml_item.set("Date_millesime", str(_return_date_millesime))

        elif _action == "DeleteFilter":
           if ref_element is not None:
               filtres = ref_element.findall("Filtre")
               for f in filtres:
                   if f.get("nom") == textNameFilter:
                       ref_element.remove(f)
                       break

        elif _action == "textNameFilterInit":
           self.createRadioButtonDate.radio_date_aucune.setChecked(True)
           self.createRadioButtonDate.mZoneDateAnnee.setText("")
           self.createRadioButtonDate.mZoneDateFrom.setText("")
           self.createRadioButtonDate.mZoneDateTo.setText("")
           self.createRadioButtonDate.mZoneChoiceDateDer.setChecked(False)
        
           if ref_element is not None:
              filtres = ref_element.findall("Filtre")
              for f in filtres:
                  if f.get("nom") == textNameFilter:
                      item = f.find("Item")
                      if item is not None:
                         _Radio_date = item.get("Radio_date")
                         if _Radio_date == "1" : 
                            self.createRadioButtonDate.radio_date_aucune.setChecked(True)
                         elif _Radio_date == "2" : 
                            self.createRadioButtonDate.radio_date_annee.setChecked(True)
                         elif _Radio_date == "3" : 
                            self.createRadioButtonDate.radio_date_periode.setChecked(True)
                         else :
                            self.createRadioButtonDate.radio_date_aucune.setChecked(True)

                         self.createRadioButtonDate.mZoneDateAnnee.setText("")
                         self.createRadioButtonDate.mZoneDateFrom.setText("")
                         self.createRadioButtonDate.mZoneDateTo.setText("")
                         self.createRadioButtonDate.mZoneChoiceDateDer.setChecked(False)
                         #-
                         _Date_annee = item.get("Date_annee")
                         if _Date_annee != "None" : self.createRadioButtonDate.mZoneDateAnnee.setText(_Date_annee)
                         #-
                         _Date_from = item.get("Date_from")
                         if _Date_from != "None" : self.createRadioButtonDate.mZoneDateFrom.setText(_Date_from)
                         #-
                         _Date_to = item.get("Date_to")
                         if _Date_to != "None" : self.createRadioButtonDate.mZoneDateTo.setText(_Date_to)
                         #-
                         _Date_millesime = item.get("Date_millesime")
                         if _Date_millesime != "None" : self.createRadioButtonDate.mZoneChoiceDateDer.setChecked(True if _Date_millesime == "True" else False)
        return
    # Gestion Dates
    #====================

    #===============================              
    def reinitAffichageSaveAndDeleteFilterifExisteCaseCochee(self, _referenceSelf) :
        #gestion des boutons SaveFilter et DeleteFilter
        #-----------------
        #Button Save Filtre
        if _referenceSelf.ifExisteCaseCochee() : 
           _referenceSelf.buttonSaveFilter.setEnabled(True)
        else :    
           _referenceSelf.buttonSaveFilter.setEnabled(False)
        #Button Delete
        if _referenceSelf.mZoneQComboSaveLoadFilter.count() > 1 :
           if _referenceSelf.retourneTexteQcomboBoxSansIconeFavori(_referenceSelf.mZoneQComboSaveLoadFilter.currentText()) == "Aucun" :
              _referenceSelf.buttonDeleteFilter.setEnabled(False)
           else :          
              _referenceSelf.buttonDeleteFilter.setEnabled(True)
        else :    
           _referenceSelf.buttonDeleteFilter.setEnabled(False)
        #-----------------
        #Button Favori
        if _referenceSelf.valueFavoriFilter == _referenceSelf.retourneTexteQcomboBoxSansIconeFavori(_referenceSelf.mZoneQComboSaveLoadFilter.currentText()) :
           _referenceSelf.buttonFavori.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favoridefaut.svg"))
        else : 
           _referenceSelf.buttonFavori.setIcon(QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favori.svg"))
        
    #===============================              
    def ifExisteCaseCochee(self) :
        _pathUserFilter = Path(QgsApplication.qgisSettingsDirPath().replace("\\","/") + "qgireferentiels/filtres")
        createFolder(_pathUserFilter)
        self.fileNameFilter = Path(_pathUserFilter, "qgireferentielfiltres.xml")
        if self.fileNameFilter == "" : return

        # Parcours des QTreeWidgets
        for ref_name, tree_widget_tuple in self.referencesFiltres.items():
            tree_widget    = tree_widget_tuple[0]
            iterator = QTreeWidgetItemIterator(tree_widget)
            while iterator.value():
               item = iterator.value()
               if item.checkState(0) in (Qt.CheckState.Checked, Qt.CheckState.PartiallyChecked):
                  return True
               iterator += 1
        return False            

    #===============================              
    def returnListeNameFiltre(self) :
        _pathUserFilter = Path(QgsApplication.qgisSettingsDirPath().replace("\\","/") + "qgireferentiels/filtres")
        createFolder(_pathUserFilter)
        self.fileNameFilter = Path(_pathUserFilter, "qgireferentielfiltres.xml")
        if self.fileNameFilter == "" : return

        if not os.path.exists(self.fileNameFilter) : return ["Aucun"]

        tree = ET.parse(self.fileNameFilter)
        root = tree.getroot()
        noms_filtres = []
        
        for ref in root.findall("Référence"):
            for filtre in ref.findall("Filtre"):
                nom = filtre.get("nom")
                if nom : 
                   if nom not in noms_filtres : noms_filtres.append(nom)
        noms_filtres  = sorted(noms_filtres, key=lambda s: s.lower(), reverse=False)           
        noms_filtres.insert(0, "Aucun")
        return noms_filtres

    #===============================              
    def initQComboSaveLoadFilter(self, _valueFavori = None) :
        _returnListeNameFiltre = self.returnListeNameFiltre()
        _valueComparaison = self.valueFavoriFilter if _valueFavori is None else _valueFavori
        model = QStandardItemModel()
        iconeFavori      = QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favoridefaut.svg")
        iconeFavoriblanc = QtGui.QIcon(os.path.dirname(__file__)+"/icons/buttons/favoriblanc.svg")

        for name in _returnListeNameFiltre:
            item = QStandardItem(name)
            if name == self.retourneTexteQcomboBoxSansIconeFavori(_valueComparaison) :
               item.setText(f"{name}")
               item.setIcon(iconeFavori)
            else:
               item.setFont(QFont())
               item.setIcon(iconeFavoriblanc)
            model.appendRow(item)

        self.mZoneQComboSaveLoadFilter.setModel(model)
        return

    #===============================              
    def retourneTexteQcomboBoxSansIconeFavori(self, chaine) :
       return chaine
       sous_chaine = self.iconeFavori
       index = chaine.find(sous_chaine)
       if index == -1 : return chaine 
       return chaine[index + len(sous_chaine):]

    #===============================              
    def findCode(self, _ChaineRecherche):
        ret = None    
        for _key, _value in self.mDicQComBox.items() :
            for _valueFind in _value : 
               if _valueFind[0] == _ChaineRecherche:
                  ret = _valueFind[1]
                  break
        return ret         

    #===============================              
    def returnCodeWithListCurrentText(self, _Liste, _typeFormat = None):
        # Si _typeFormat = "FORMAT", je prends les deux valeurs dans la liste pour avoir le libellé et le type de format
        _typeFormat = _typeFormat.upper()
        ret = []    
        for _key, _value in self.mDicQComBox.items() :
            if _typeFormat == _key :
               for _valueFind in _value : 
                  for _valueFindListe in _Liste : 
                     if _typeFormat == "" :
                        if _valueFind[1] == _valueFindListe:
                           ret.append( _valueFind[0] )
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "FORMAT" :
                        if _valueFind[1] == _valueFindListe:
                           ret.append( _valueFind[0] )
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "ZONE" :
                        if _valueFind[1] == _valueFindListe:
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "REGIONMETRO" :
                        if _valueFind[1] == _valueFindListe:
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "REGIONOUTREMER" :
                        if _valueFind[1] == _valueFindListe:
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "NATIONAL" :
                        if _valueFind[0].upper() == _valueFindListe:
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "FRANCEENTIERE" :
                        if _valueFind[0].upper() == _valueFindListe:
                           ret.append( _valueFind[1] )
                     elif _typeFormat == "MONDE" :
                        if _valueFind[0] == _valueFindListe:
                           ret.append( _valueFind[1] )
        return ret 

    #===============================              
    def returnDateFiltreParametres(self):
        if self.createRadioButtonDate.radio_date_aucune.isChecked() :
           _radio = 1 
        elif self.createRadioButtonDate.radio_date_annee.isChecked() :
           _radio = 2 
        elif self.createRadioButtonDate.radio_date_periode.isChecked() :
           _radio = 3 
        else :
           _radio = 1 

        _millesime = True if self.createRadioButtonDate.mZoneChoiceDateDer.isChecked() else False        
        if _radio == 1 :   # Pas de date
           _return_date_from, _return_date_to, _return_date_millesime = None, None, _millesime
        elif _radio == 2 : # Année
           if self.createRadioButtonDate.mZoneDateAnnee.text() == "" or self.createRadioButtonDate.mZoneDateAnnee.text() == None :
              _return_date_annee, _return_date_from, _return_date_to, _return_date_millesime = None, None, None, _millesime
              return None, None, None
           
           _return_date_from, _return_date_to, _return_date_millesime = self.createRadioButtonDate.mZoneDateAnnee.text(), self.createRadioButtonDate.mZoneDateAnnee.text(), None
           _return_date_from, _return_date_to = _return_date_from + "-01-01", _return_date_to + "-12-31"
        elif _radio == 3 : # Période
           if self.createRadioButtonDate.mZoneDateFrom.text() == "" or self.createRadioButtonDate.mZoneDateFrom.text() == None or self.createRadioButtonDate.mZoneDateTo.text() == "" or self.createRadioButtonDate.mZoneDateTo.text() == None:
              return None, None, None
           _return_date_from, _return_date_to, _return_date_millesime = self.createRadioButtonDate.mZoneDateFrom.text(), self.createRadioButtonDate.mZoneDateTo.text(), _millesime
           _return_date_from, _return_date_to = _return_date_from + "-01-01", _return_date_to + "-12-31"
        else :
           _return_date_from, _return_date_to, _return_date_millesime = None, None, _millesime

        return _return_date_from, _return_date_to, _return_date_millesime

    #===============================              
    def returnListTreeviewFiltreParametres(self, _TreeviewFiltreParametres, _type):
        _returnList = []
        iterator = QTreeWidgetItemIterator( _TreeviewFiltreParametres )
        while iterator.value():
             item = iterator.value()
             itemlib      = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
             itemid       = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)
             itemtype     = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)
             if itemtype in ["ZONE", "REGIONMETRO", "REGIONOUTREMER", "FORMAT"] :
                 if _type == itemtype.upper() and item.checkState(0) == QtCore.Qt.CheckState.Checked : _returnList.append(itemid)
             elif itemtype in ["NATIONAL", "FRANCEENTIERE"] :
                 if _type == itemtype.upper() and item.checkState(0) == QtCore.Qt.CheckState.Checked : _returnList.append(itemtype)
             else : 
                 if _type == itemid.upper()   and item.checkState(0) == QtCore.Qt.CheckState.Checked : _returnList.append(itemid)
             iterator += 1
        return _returnList         

    #===============================              
    def desactiveAll(self, _TreeviewFiltreParametres):
        iterator = QTreeWidgetItemIterator( _TreeviewFiltreParametres )
        while iterator.value():
             item = iterator.value()
             item.setCheckState(0, QtCore.Qt.CheckState.Unchecked)
             #Réduit tout
             item.setExpanded(False)
             iterator += 1
        return  
        
    #==========================
    def createToolBarQGIDistribution(self):
        #Barre d'outils qgireferentiels
        self.mMenuBarQGIDistribution = QMenuBar()  
        self.mMenuBarQGIDistribution.setContentsMargins(0, 0, 0, 0)
        self.layout_tab_widget_distribution.addWidget(self.mMenuBarQGIDistribution, 0, 0, 1, 2)
        self.mMenuBarQGIDistribution.setMinimumSize(23, 23)
        self.mMenuBarQGIDistribution.setStyleSheet("QMenuBar { border: 0px solid red;}")
        self.mMenuBarQGIDistributionGrid = QtWidgets.QHBoxLayout()
        self.mMenuBarQGIDistributionGrid.setContentsMargins(0, 0, 0, 0)
        self.mMenuBarQGIDistribution.setLayout(self.mMenuBarQGIDistributionGrid)

        #==========================
        #==========================
        # [ == PrintLogLocal == ]
        _icon = os.path.dirname(__file__) + "/icons/buttons/print.svg"          
        openPrintLogLocalLibActionAndAction = QtWidgets.QApplication.translate("qgientrepot_ui",  "Print Log", None)  
        _Listkeys   = [ "typeWidget",            "textWidget",          "nameWidget", "iconWidget", "toolTipWidget",       "actionWidget",                                                                "autoRaise", "checkable", "qSizePolicy" ]
        _ListValues = [ QtWidgets.QToolButton(), openPrintLogLocalLibActionAndAction, "openBasket",    _icon,        openPrintLogLocalLibActionAndAction, lambda : self.actionContextuelToolBarQGIDistribution("PrintLogLocal"),  False,       False,       QSizePolicy.Policy.Fixed ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        self.printLogLocal = genereButtonWithDict( dicParamButton )

        #- Nombre d'objets sélectionnés dans le panier
        mText = ""
        mTextToolTip = QtWidgets.QApplication.translate("qgidistribution_ui", "Number of resources selected in the lot.", None)     #Nombre de ressources sélectionéns dans le panier.
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignCenter,  True,        mTextToolTip,   "QLabel {  font-family:" + self.policeQGroupBox  +"; background-color:" + self.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        self.mLabelNbOpenBasket  = genereLabelWithDict( dicParamLabel )
        self.mLabelNbOpenBasket.setVisible(False)
        
        # [ == OpenImport == ]
        _icon = os.path.dirname(__file__) + "/icons/general/basket_noir.svg"          
        openImportLibActionAndAction = QtWidgets.QApplication.translate("qgientrepot_ui",  "Open basket", None)  
        _Listkeys   = [ "typeWidget",            "textWidget",          "nameWidget", "iconWidget", "toolTipWidget",       "actionWidget",                                                                "autoRaise", "checkable", "qSizePolicy" ]
        _ListValues = [ QtWidgets.QToolButton(), openImportLibActionAndAction, "openBasket",    _icon,        openImportLibActionAndAction, lambda : self.actionContextuelToolBarQGIDistribution("openBasket"),  False,       False,       QSizePolicy.Policy.Fixed ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        self.openBasket = genereButtonWithDict( dicParamButton )
        
        
        #Version 1.0.0
        self.openBasket.setVisible(True)
        
        self.mMenuBarQGIDistributionGrid.addWidget(self.printLogLocal)        
        self.mMenuBarQGIDistributionGrid.addStretch(1)    
        self.mMenuBarQGIDistributionGrid.addWidget(self.mLabelNbOpenBasket)        
        self.mMenuBarQGIDistributionGrid.addWidget(self.openBasket)        
        #self.importButton.setEnabled(False)        
        #Barre d'outils qgireferentiels

    #==========================
    def showEvent(self, event):
        if self._qgireferentiels        != None : self._qgireferentiels.setEnabled(False)
        if self._qgireferentielsToolBar != None : self._qgireferentielsToolBar.setEnabled(False)
        return

    #==========================
    def hideEvent(self, event):
        if self._qgireferentiels        != None : self._qgireferentiels.setEnabled(True)
        if self._qgireferentielsToolBar != None : self._qgireferentielsToolBar.setEnabled(True)
        
    #==========================
    def actionContextuelToolBarQGIDistribution(self, _button):
        if _button == "openBasket" :
           #-----------------------------
           # Save mDic_LH["OpenPanelValue"]
           mDicAutre          = {}
           mSettings = QgsSettings()
           mSettings.beginGroup("QGIREFERENTIELS")
           mSettings.beginGroup("Generale")

           if self.splitter.sizes()[2] != 0  : 
              mDicAutre["OpenPanelValue"]   = self.splitter.sizes()
              #---- SAVE 
              for key, value in mDicAutre.items():
                  mSettings.setValue(key, value)
              #---- SAVE 
              _size1 = self.splitter.sizes()[0]
              _size2 = self.splitter.sizes()[1] + self.splitter.sizes()[2] 
              _size3 = 0 
              self.mLabelNbOpenBasket.setVisible(True)                 
           else :
              valueOpenPanelValue        = [self.Dialog.width()/3, self.Dialog.width()/3, self.Dialog.width()/3] #Robustesse
              mDicAutre["OpenPanelValue"]   = valueOpenPanelValue
              #---- LOAD 
              for key, value in mDicAutre.items():
                 if not mSettings.contains(key) :
                    mSettings.setValue(key, value)
                 else :
                    mDicAutre[key] = mSettings.value(key)
              #---- LOAD 
              _size1 = round(float(mDicAutre["OpenPanelValue"][0]))
              
              #Cas ou SAVE avec 0   
              _size3 = round(float(mDicAutre["OpenPanelValue"][2]))
              if _size3 == 0 :    
                 _size2 = round(float(mDicAutre["OpenPanelValue"][1])) / 2 
                 _size3 = _size2 
              else :       
                 _size2 = round(float(mDicAutre["OpenPanelValue"][1]))

              self.mLabelNbOpenBasket.setVisible(False)                 

           self.splitter.setSizes([ int(_size1), int(_size2), int(_size3) ]) 
           # Save mDic_LH["OpenPanelValue"]
        elif _button == "PrintLogLocal" :
           _FileLocal = self.urlStatistiquesDistribution          
           if not os.path.exists(_FileLocal) :
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Warning" , None)
              zMess1 = QtWidgets.QApplication.translate("qgidistribution_ui", "The log file does not exist." , None)
              displayMess(self.Dialog, (2 if self.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.durationBarInfo)
              return

           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )

           with open(_FileLocal, 'r', encoding='utf-8') as f:
               lignes = f.readlines()

           # Transformation en Html
           date_du_jour = datetime.now().strftime("%d/%m/%Y")
           html = f"<html><body><h2 style='text-align: center;'>Journalisation des téléchargements via QGIRéférentiels - {date_du_jour}</h2>"
           html += "<table cellspacing='0' cellpadding='4' style='border-collapse: collapse; width: 100%;'>"
           for ligne in lignes:
               colonnes = ligne.strip().split(";")
               colonnes = colonnes[:-3] # J'enlève les trois dernières colonnes
               colonnes = colonnes[:4] + colonnes[5:]  # on saute la 5e

               # Gestion de la 7 ème colonne, pour la mettre en dessous
               if len(colonnes) >= 7:
                  ligne_main = colonnes[:5] + colonnes[6:]  # on saute la 7e
                  ligne_supp = colonnes[5]                  # la 7e qu'on mettra à part
               else:
                  ligne_main = colonnes
                  ligne_supp = ""

               # Première ligne 
               html += "<tr style='border-bottom: none;'>"
               for col in ligne_main:
                   html += f"<td style='border: 1px solid #999; text-align: center;'>{col}</td>"
               html += "</tr>"
               # Deuxième ligne : 7e colonne 
               html += f"<tr><td colspan='{len(ligne_main)}' style='background-color: #f2f2f2; padding: 6px 10px; font-style: italic; font-size: 90%;'>{ligne_supp}</td></tr>"
           html += "</table></body></html>"

           docQTextDocument = QTextDocument()
           docQTextDocument.setHtml(html)

           printer = QPrinter()
           printer = QPrinter(QPrinter.PrinterMode.HighResolution)
           printer.setOutputFormat(QPrinter.OutputFormat.NativeFormat)
           printer.setPageOrientation(QPageLayout.Orientation.Landscape)
           layout = QPageLayout(QPageSize(QPageSize.PageSizeId.A4), QPageLayout.Orientation.Landscape, QMarginsF(0, 0, 0, 0), QPageLayout.Unit.Millimeter)
           printer.setPageLayout(layout)
           #-
           printDialog = QPrintPreviewDialog(printer)
           zTitle = QtWidgets.QApplication.translate("qgidistribution_ui",  "Print Log", None)  
           printDialog.setWindowTitle(zTitle)
           #-
           printDialog.paintRequested.connect(docQTextDocument.print)
           printDialog.setWindowFlags(Qt.WindowType.WindowMaximizeButtonHint | Qt.WindowType.WindowCloseButtonHint | Qt.WindowType.WindowMinimizeButtonHint) 
           #-
           _pathIcons = os.path.dirname(__file__) + "/icons/logo"
           iconSource                     = _pathIcons + "/qgireferentiels.png"
           icon = QtGui.QIcon()
           icon.addPixmap(QtGui.QPixmap(iconSource),  QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
           printDialog.setWindowIcon(icon)
           #-
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           printDialog.exec()

    #==========================
    def myHelpAM(self):
        #-
        if self.fileHelp == "pdf" :
           valueDefautFileHelp = self.fileHelpPdf
        elif self.fileHelp == "html" :
           valueDefautFileHelp  = self.fileHelpHtml
        else :
           valueDefautFileHelp  = self.fileHelpHtml
        execPdf(valueDefautFileHelp)
        return
        
#===============================
# Affiche image               
#===============================
def displayPicture(self, _logo) :
     _labelImage = QtWidgets.QLabel()
     iconSource  = _logo
     myDefPath   = iconSource.replace("\\","/")
     carIcon     = QtGui.QImage(myDefPath)
     _labelImage.setPixmap(QtGui.QPixmap.fromImage(carIcon))
     _labelImage.setObjectName("_labelImage")
     return _labelImage
        
#===============================
# Retourne tous les paramètres des filtres              
#===============================
def returnParametres(self) :
     #=====
     #- Ajouter pour d'autres paramètres
     _lang      = self.findCode( self.mZoneLang.currentText() )
     #=====
     #
     _formatListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresFormat, "FORMAT")
     _formatListe = self.returnCodeWithListCurrentText(_formatListe, "FORMAT")
     _format      = ",".join( _formatListe ) if None not in _formatListe else None
     if _format == "" : _format = None
     # Juste pour test mDicReturn =  print({ "LANG" : _lang, "ZONE" : _zone, "FORMAT" : _format })

     _zone = ""
     #=====
     # DEPARTEMENTS
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "ZONE")
     _zoneListe = self.returnCodeWithListCurrentText(_zoneListe, "ZONE")
     _zone      = ",".join( _zoneListe ) if None not in _zoneListe else ""

     if _zone == "" or _zone == None : 
        _zone = ""
     else :  
        if "FRA, FXX, WLD" not in _zoneListe :   
           _zoneListe.append( "FRA, FXX, WLD" ) 
        _zone      = ",".join( _zoneListe ) 
     
     #=====
     # REGIONS METRO
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "REGIONMETRO")
     _zoneREGIONMETRO = ",".join( _zoneListe ) if None not in _zoneListe else ""
     if _zoneREGIONMETRO != "" :
        _zone = _zoneREGIONMETRO if _zone == "" else _zoneREGIONMETRO + "," + _zone 
     
     #=====
     # REGIONS REGIONOUTREMER
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "REGIONOUTREMER")
     _zoneREGIONOUTREMER      = ",".join( _zoneListe ) if None not in _zoneListe else ""
     if _zoneREGIONOUTREMER != "" :
         _zone = _zoneREGIONOUTREMER if _zone == "" else _zoneREGIONOUTREMER + "," + _zone 

     #=====
     # REGIONS FRANCE
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "NATIONAL")
     _zoneListe = self.returnCodeWithListCurrentText(_zoneListe, "NATIONAL")
     _zoneNATIONAL      = ",".join( _zoneListe ) if None not in _zoneListe else ""
     if _zoneNATIONAL != "" :
         _zone = _zoneNATIONAL if _zone == "" else _zoneNATIONAL + "," + _zone 

     #=====
     # REGIONS FRANCEENTIERE
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "FRANCEENTIERE")
     _zoneListe = self.returnCodeWithListCurrentText(_zoneListe, "FRANCEENTIERE")
     _zoneFRANCEENTIERE      = ",".join( _zoneListe ) if None not in _zoneListe else ""
     if _zoneFRANCEENTIERE != "" :
         _zone = _zoneFRANCEENTIERE if _zone == "" else _zoneFRANCEENTIERE + "," + _zone 

     #=====
     # REGIONS MONDE
     _zoneListe = self.returnListTreeviewFiltreParametres(self.mZoneFiltreParametresZone, "MONDE")
     _zoneListe = self.returnCodeWithListCurrentText(_zoneListe, "MONDE")
     _zoneMONDE      = ",".join( _zoneListe ) if None not in _zoneListe else ""
     if _zoneMONDE != "" :
        _zone = _zoneMONDE if _zone == "" else _zoneMONDE + "," + _zone 

     return _lang, _zone, _format

#========================================================     
#========================================================     
# Class pour le tree View FILTRE PARAMETRES
class TreeviewFiltreParametres(QTreeWidget):
    customMimeType = "text/plain"
    #===============================              
    def __init__(self, _typeWidget, *args):
        QTreeWidget.__init__(self, *args)
        super().__init__()
        self._typeWidget = _typeWidget
        self.setColumnCount(3)
        self.hideColumn (1)   # For hide ID
        self.hideColumn (2)   # For hide ID
        self.setHeaderLabels(["libellé", "Code", "Niveau"])
        self.header().hide()        
        self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) 
        self._loading = False # Permet de ne pas lancer la fonction au chargement 
        self.itemChanged.connect(lambda : self.on_item_changed_qchekcbox_for_save_delete_filtre(self.selfQgeoDistribution))  
        return

    #===============================
    def on_item_changed_qchekcbox_for_save_delete_filtre(self, _selfQgeoDistribution):
        if self._loading : return
        if _selfQgeoDistribution.mZoneFiltreParametresZone.objectName() == "mZoneFiltreParametresZone" :
           if _selfQgeoDistribution.groupBox_QSplitterFiltre_Bas.isCollapsed():
              border_style_zone = "None"
           else:
              border_style_zone = "solid"  
           _NormalBoldZone  = "bold" if self.ifUneSeuleCaseACocher(_selfQgeoDistribution.mZoneFiltreParametresZone) else "normal"
           _selfQgeoDistribution.groupBox_QSplitterFiltre_Bas.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + _selfQgeoDistribution.policeQGroupBox  +" ; \
                              border-style: "  + border_style_zone  + ";      \
                              border-width:1px;      \
                              border-color:"  + _selfQgeoDistribution.colorQTabWidget  + ";      \
                              font-weight : "  + _NormalBoldZone  + ";      \
                              padding-left:    6px;            \
                              padding-top:    20px;            \
                              padding-right:   6px;            \
                              padding-bottom: 0px;            \
                              } \
                              QGroupBox::title { \
                              subcontrol-origin: margin; \
                              subcontrol-position: top left; \
                              padding-left: 20px; \
                              }")
           
        if _selfQgeoDistribution.mZoneFiltreParametresFormat.objectName() == "mZoneFiltreParametresFormat" :
           if _selfQgeoDistribution.groupBox_QSplitterFiltre_Middle.isCollapsed():
              border_style_format = "None"
           else:
              border_style_format = "solid"        
           _NormalBoldFormat  = "bold" if self.ifUneSeuleCaseACocher(_selfQgeoDistribution.mZoneFiltreParametresFormat) else "normal"
           _selfQgeoDistribution.groupBox_QSplitterFiltre_Middle.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + _selfQgeoDistribution.policeQGroupBox  +" ; \
                              border-style: "  + border_style_format  + ";      \
                              border-width:1px;      \
                              border-color:"  + _selfQgeoDistribution.colorQTabWidget  + ";      \
                              font-weight : "  + _NormalBoldFormat  + ";      \
                              padding-left:    6px;            \
                              padding-top:    20px;            \
                              padding-right:   6px;            \
                              padding-bottom: 0px;            \
                              } \
                              QGroupBox::title { \
                              subcontrol-origin: margin; \
                              subcontrol-position: top left; \
                              padding-left: 20px; \
                              }")                            

        #-----------------
        #gestion des boutons SaveFilter et DeleteFilter
        _selfQgeoDistribution.reinitAffichageSaveAndDeleteFilterifExisteCaseCochee(_selfQgeoDistribution) 
        return
        
    #===============================
    def afficheFiltreParametres(self, _selfQgeoDistribution, _mDicQComBox):
       self.selfQgeoDistribution = _selfQgeoDistribution 
       self.header().setStretchLastSection(False)
       self.header().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
       self.alimenteArbo( _mDicQComBox )
       return  

    #===============================
    def ifUneSeuleCaseACocher(self, _tree):
        iterator = QTreeWidgetItemIterator(_tree)
        while iterator.value():
           item = iterator.value()
           if item.checkState(0) in (Qt.CheckState.Checked, Qt.CheckState.PartiallyChecked):
              return True
           iterator += 1
        return False

    #===============================              
    def alimenteArbo(self, _mDicQComBox):
       #===============================              
       #===============================              
       self._loading = True
       # Bloque les signaux    
       self.blockSignals(True) 

       if self._typeWidget == "ZONES" : 
          entete = QtWidgets.QApplication.translate("qgientrepot_ui", "Zones géographiques", None)
          self.setHeaderLabels(["", "Code", "Niveau"])
          for key, value in _mDicQComBox.items() :
              # Exemple 
              if key == "RACINE" :
                 #je boucle sur les libellés et les codes
                 for elemKeyValue in value :
                     if elemKeyValue[0].upper() != "FORMATS" :
                        _lisInfosBranche = [ elemKeyValue[1], elemKeyValue[0], "RACINE" ] 
                        itemNode = self.getOrCreateProviderNode( _lisInfosBranche )

                        if elemKeyValue[0].upper() == "ZONES" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the department(s) to download (classification of departments by region)", None) 
                        elif elemKeyValue[0].upper() == "REGIONS" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the region(s) to download", None) 
                        elif elemKeyValue[0].upper() == "OUTREMER" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the outre-mer regions", None) 
                        elif elemKeyValue[0].upper() == "NATIONAL" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the France metropolitaine", None) 
                        elif elemKeyValue[0].upper() == "FRANCEENTIERE" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the France entiere", None) 
                        elif elemKeyValue[0].upper() == "MONDE" :
                           libTooltip = QtWidgets.QApplication.translate("qgidistribution_ui",  "Select the World", None) 
                        else :
                           libTooltip = "" 
                        itemNode.setToolTip(0, libTooltip)
 
                        menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25) 
                        #itemNode.setIcon(0, menuIcon)

       elif self._typeWidget == "FORMATS" : 
          entete = QtWidgets.QApplication.translate("qgientrepot_ui", "Formats", None)
          self.setHeaderLabels(["", "Code", "Niveau"])
          for key, value in _mDicQComBox.items() :
              if key == "RACINE" :
                 #je boucle sur les libellés et les codes
                 for elemKeyValue in value :
                     if elemKeyValue[0].upper() == "FORMATS" :
                        _lisInfosBrancheFormat = [ elemKeyValue[1], elemKeyValue[0], "RACINE" ] 
                        _lisInfosBrancheFormat = [ "Tous", elemKeyValue[0], "RACINE" ] 
                        itemNode = self.getOrCreateProviderNode( _lisInfosBrancheFormat )
                        menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25) 
                        #itemNode.setIcon(0, menuIcon)
    
       #===============================              
       #===============================
       #dupplique le dictionnaire pour les départements
       _mDicQComBoxDept       = copy.deepcopy(QGIREFERENTIELS_REFERENTIEL)
       _mDicQComBoxRegion     = copy.deepcopy(QGIREFERENTIELS_REFERENTIEL)
       _mDicQComBoxSousRegion = copy.deepcopy(QGIREFERENTIELS_REFERENTIEL)
       _mDicQComBoxOutremer   = copy.deepcopy(QGIREFERENTIELS_REFERENTIEL)
                     
       for key, value in _mDicQComBox.items() :
           # Exemple 
           # "ZONE": [ ("France", "FRA, FXX, WLD") , ("Ain (01)", "D001"), .........
           # [ Libellé, Code, Niveau ] 
           # [ Ain (01), D001, ZONE ]
           
           #========= 
           #========= 
           # LES DEPARTEMENTS PAR REGIONS
           # "REGION": [ ("Auvergne-Rhône-Alpes", ["D001", "D003", "D007", "D015", "D026", "D038", "D042", "D043", "D063", "D073", "D074"]),
           if self._typeWidget == "ZONES" :
              if key == "RACINE" :
                 # Je prends la première valeur dans le tuple soit ['Départements regroupés par régions', 'Zones', 'RACINE']
                 _lisInfosBranche = [ value[0][1], value[0][0], "RACINE" ]
                 itemNode = self.returnNode( _lisInfosBranche )
                 
                 #===============================              
                 #je boucle sur les libellés et les codes pour les REGIONS
                 for keyRegion, valueRegion in _mDicQComBoxRegion.items() :
                     if keyRegion == "REGION" :
                        for elemKeyValueRegion in valueRegion :
                           region_name      = elemKeyValueRegion[0]  # Nom de la région
                                                               # ("Auvergne-Rhône-Alpes",       "84", ["D001", "D003", "D007", "D015", "D026", "D038", "D042", "D043", "D063", "D073", "D074"])
                           region_List_Dept = ",".join( elemKeyValueRegion[2] )  # Liste des codes départements

                           _lisInfosBranche = [ region_name, region_List_Dept, "REGION" ]
                           child_item_Region = QTreeWidgetItem( _lisInfosBranche )
                           child_item_Region.setCheckState(0, Qt.CheckState.Unchecked)
                           child_item_Region.setFlags(child_item_Region.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
                           menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/page.svg")) 
                           child_item_Region.setIcon(0, menuIcon)
                           itemNode.addChild(child_item_Region)
                          
                           # Extraction des départements associés à cette région
                           listDept = region_List_Dept.split(",")  # Liste des codes des départements pour cette région

                           if listDept != None : 
                              # Boucle pour ajouter les départements correspondants
                              for dept_key, dept_value in _mDicQComBoxDept.items():
                                  if dept_key == "ZONE":
                                     for elemKeyValueDept in dept_value:
                                         dept_name = elemKeyValueDept[0]
                                         dept_code = elemKeyValueDept[1]

                                         if dept_code in listDept:
                                            _lisInfosBranche = [dept_name, dept_code, "ZONE"]
                                            child_item_Dept = QTreeWidgetItem(_lisInfosBranche)
                                            child_item_Dept.setCheckState(0, Qt.CheckState.Unchecked)
                                            child_item_Dept.setFlags(child_item_Dept.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
                                            menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/page.svg"))
                                            #child_item_Dept.setIcon(0, menuIcon)
                                            child_item_Region.addChild(child_item_Dept)                    
           #========= 
           #========= 
           # LES REGIONS ET FRANCE DEUXIEME NIVEAU
           # "RACINEDEUXIEMENIVEAU" : [ ("Regions", "Métropolitaines"), ("Regions", "Outre-mer"), ("National", "Métropolitaine"), ("National", "Entière (avec DROM)") ],

           if self._typeWidget == "ZONES" :
              if key == "SOUSRACINE" :
                 for valueSousRacine in value :
                     # Je prends la DEUXIEME valeur dans le tuple soit ['Régions', 'Régions', 'RACINE']
                     _lisInfosBranche = [ valueSousRacine[1], valueSousRacine[0], "RACINE" ]
                     itemNode = self.returnNodeSousRacine( _lisInfosBranche )

                     region_name      = valueSousRacine[1]
                     region_List_Dept = valueSousRacine[0]
                     
                     _code = "SOUSRACINE"
                     if region_name == "Métropolitaine" : 
                        _code = "NATIONAL" 
                     elif region_name == "Entière (avec DROM)" : 
                        _code = "FRANCEENTIERE"  
                     else :
                        _code = "SOUSRACINE"  

                     _lisInfosBranche = [ region_name, region_List_Dept, _code ]
                     child_item_DeuxiemeNiveau = QTreeWidgetItem( _lisInfosBranche )
                     child_item_DeuxiemeNiveau.setCheckState(0, Qt.CheckState.Unchecked)
                     child_item_DeuxiemeNiveau.setFlags(child_item_DeuxiemeNiveau.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
                     menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.svg")) 
                     child_item_DeuxiemeNiveau.setIcon(0, menuIcon)
                     itemNode.addChild(child_item_DeuxiemeNiveau)

                     #===============================              
                     #je boucle sur les libellés et les codes pour les REGIONS
                     for keyRegion, valueRegion in _mDicQComBoxRegion.items() :
                        #========= 
                        #========= 
                        # LES REGIONS UNIQUEMENT
                        # "REGION": [ ("Auvergne-Rhône-Alpes", ["D001", "D003", "D007", "D015", "D026", "D038", "D042", "D043", "D063", "D073", "D074"]),
                        if keyRegion == "REGION" and region_name == "Métropolitaines" :
                           for elemKeyValueRegion in valueRegion :
                              if elemKeyValueRegion[1] not in ["R01", "R02", "R03", "R04", "R05"] : 
                                 region_name      = elemKeyValueRegion[0]  # Nom de la région
                                                                     # ("Auvergne-Rhône-Alpes",       "84", ["D001", "D003", "D007", "D015", "D026", "D038", "D042", "D043", "D063", "D073", "D074"])
                                 region_List_Dept = elemKeyValueRegion[1]  # Liste des codes départements

                                 _lisInfosBranche = [ region_name, region_List_Dept, "REGIONMETRO" ]
                                 child_item_Region = QTreeWidgetItem( _lisInfosBranche )
                                 child_item_Region.setCheckState(0, Qt.CheckState.Unchecked)
                                 child_item_Region.setFlags(child_item_Region.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
                                 menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/page.svg")) 
                                 child_item_Region.setIcon(0, menuIcon)
                                 child_item_DeuxiemeNiveau.addChild(child_item_Region)
                        #========= 
                        #========= 
                        # OUTREMER UNIQUEMENT
                        # "OUTREMER": [ ("Guadeloupe",                 "01", ["D971"]),
                        if keyRegion == "REGION" and region_name == "Outre-mer" :
                           for elemKeyValueRegion in valueRegion :
                              if elemKeyValueRegion[1] in ["R01", "R02", "R03", "R04", "R05"] : 
                                 region_name      = elemKeyValueRegion[0]  # Nom de la région
                                                                     # ("Auvergne-Rhône-Alpes",       "84", ["D001", "D003", "D007", "D015", "D026", "D038", "D042", "D043", "D063", "D073", "D074"])
                                 region_List_Dept = elemKeyValueRegion[1]  # Liste des codes départements

                                 _lisInfosBranche = [ region_name, region_List_Dept, "REGIONOUTREMER" ]
                                 child_item_Region = QTreeWidgetItem( _lisInfosBranche )
                                 child_item_Region.setCheckState(0, Qt.CheckState.Unchecked)
                                 child_item_Region.setFlags(child_item_Region.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
                                 menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/page.svg")) 
                                 child_item_Region.setIcon(0, menuIcon)
                                 child_item_DeuxiemeNiveau.addChild(child_item_Region)

           #========= 
           #========= 
           #========= 
           if self._typeWidget == "FORMATS" :
              if key == "FORMAT" :
                 _lisInfosBranche = _lisInfosBrancheFormat 
                 itemNode = self.returnNode( _lisInfosBranche )
                 
                 #je boucle sur les libellés et les codes
                 for elemKeyValue in value :
                    _lisInfosBranche = [ elemKeyValue[0], elemKeyValue[1], "FORMAT" ]
                    child_item = QTreeWidgetItem( _lisInfosBranche )
                    child_item.setCheckState(0, Qt.CheckState.Unchecked)
                    child_item.setFlags(child_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
                    menuIcon = returnIcon( myIconFormat( elemKeyValue[1].upper() ), 25 ) 
                    child_item.setIcon(0, menuIcon)
                    itemNode.addChild(child_item)
                    
       self._loading = False
       # DeBloque les signaux    
       self.blockSignals(False) 
       
    #===============================
    def getOrCreateProviderNode(self, _lisInfosBranche):
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        z = 1
        for i in range(self.topLevelItemCount()) :
            item = self.topLevelItem(i)
            
            item.setCheckState(0, Qt.CheckState.Unchecked)
            item.setFlags(item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  

            z += 1
            if item.text(0) == _lisInfosBranche[0] :
                return item

        # Retourne le noeud créé
        type_item = QTreeWidgetItem(self,  _lisInfosBranche )
        
        type_item.setCheckState(0, Qt.CheckState.Unchecked)
        type_item.setFlags(type_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)  
        
        self.addTopLevelItem(type_item)
        return type_item 

    #===============================
    def returnNode(self, _lisInfosBranche):
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        z = 1
        type_item = None
        for i in range(self.topLevelItemCount()) :
            item = self.topLevelItem(i)
            z += 1
            if item.text(0) == _lisInfosBranche[0] :
                return item

        return type_item  

    #===============================
    def returnNodeSousRacine(self, _lisInfosBranche):
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        z = 1
        type_item = None
        for i in range(self.topLevelItemCount()) :
            item = self.topLevelItem(i)
            z += 1
            if item.text(1) == _lisInfosBranche[1] :
                return item

        return type_item  
        
#========================================================     
#========================================================     
# Class pour le tree View API GPF
class TREEVIEWDISTRIBUTION(QTreeWidget):
    customMimeType = "text/plain"
   #===============================              
    def __init__(self, *args):
        QTreeWidget.__init__(self, *args)
        super().__init__()
        self.setColumnCount(4)
        self.hideColumn (1)   # For hide ID
        self.hideColumn (2)   # For hide ID
        self.hideColumn (3)   # For hide ID
        self.setHeaderLabels([QtWidgets.QApplication.translate("qgidistribution_ui","Downloadable data" , None), "Action"])
        self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)  
        self.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
        self.customContextMenuRequested.connect(self.menuContextuelTreeviewDistribution) 
        # Instancie l'historique du json
        self.Xml_Histo = {}
        self._mDicQComBoxDept     = copy.deepcopy(QGIREFERENTIELS_REFERENTIEL)

        self.itemDoubleClicked.connect(self.actionDoubleClicked)
        self.itemChanged.connect(self.on_item_changed_qchekcbox)  
        return

    #===============================              
    def initDistribution(self, _selfQgeoDistribution, _lang = 'FR', _zone = None, _format = None, _first = None, _dateFrom = None, _dateTo = None):
        self.selfQgeoDistribution    = _selfQgeoDistribution 
        self.URL_API_GPF             = self.selfQgeoDistribution.URL_API_GPF
        self.URL_API_GPF_PRIVATE     = self.selfQgeoDistribution.URL_API_GPF_PRIVATE
        self.HTTP_PROXY_GPF          = self.selfQgeoDistribution.HTTP_PROXY_GPF
        self.HTTPS_PROXY_GPF         = self.selfQgeoDistribution.HTTPS_PROXY_GPF
        self.HTTP_PROXY_GI_DISTRIBUTION  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
        self.HTTPS_PROXY_GI_DISTRIBUTION = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
        self.mValueLoginGPF          = self.selfQgeoDistribution.mValueLoginGPF
        
        self._first = _first
        
        # Pour ne pas afficher et interroger la plateforme
        if self._first == "FIRST" : return
        
        self.instanceGeoIdeDistribution = GeoIdeDistribution(self.URL_API_GPF, self.URL_API_GPF_PRIVATE, self.mValueLoginGPF, self.HTTP_PROXY_GPF, self.HTTPS_PROXY_GPF, self.HTTP_PROXY_GI_DISTRIBUTION, self.HTTPS_PROXY_GI_DISTRIBUTION)

        self.url_api_getCapabilities = self.instanceGeoIdeDistribution.url_api_getCapabilities
        self.url_api_getResource     = self.instanceGeoIdeDistribution.url_api_getResource
        self.url_api_getDownload     = self.instanceGeoIdeDistribution.url_api_getDownload

        ret = None
        page_size_xml, nb_occurence, nb_page = 10, 0, 0

        try:
           #===============================
           # Gestion de la pagination
           ret = self.instanceGeoIdeDistribution.get_capabilities(50, 1, _lang, _zone, _format, _dateFrom, _dateTo)
           #print(ret.text)  
            
           if ret == None :
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)
              
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on the GeoPlatforme." , None)           
              displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.selfQgeoEntrepot.Dialog.durationBarInfo)
              return     # Arrêt si pb de connexion
           
           dicXml, page_size_xml, nb_occurence, nb_page = analyseXml(ret.text )
           
           # Création des niveaux de pagination des services
           _dicXmlHisto       = {}
           _dicXml            = {}
           dicXml             = {}

           integerPageEncours = 1
           _param_nb_occurence = 50
           nb_occurence_En_Cours = nb_occurence
           while integerPageEncours <= nb_page :
              if integerPageEncours == 1  :
                 if nb_page == 1  :
                    nb_occurence_En_Cours = nb_occurence
                 else :   
                    nb_occurence_En_Cours = _param_nb_occurence
              elif integerPageEncours < nb_page :
                 nb_occurence_En_Cours = nb_occurence - (integerPageEncours * _param_nb_occurence)
              else :    
                 nb_occurence_En_Cours = nb_occurence - ( (integerPageEncours - 1 ) * _param_nb_occurence)
              
              # Gestion des données PRIVATE
              if isExisteKeyPrivateGPF(self.mValueLoginGPF) : 
                 ret = self.instanceGeoIdeDistribution.get_capabilities_private(_param_nb_occurence, integerPageEncours, _lang, _zone, _format, _dateFrom, _dateTo)
                 if ret is not None : 
                    _dicXmlPrivate, page_size_xml, nb_occurence, _nb_page = analyseXml(ret.text )
                 else :
                    _dicXmlPrivate = None   

              # Gestion des données PUBLIC
              ret = self.instanceGeoIdeDistribution.get_capabilities(_param_nb_occurence, integerPageEncours, _lang, _zone, _format, _dateFrom, _dateTo)
              _dicXml, page_size_xml, nb_occurence, _nb_page = analyseXml(ret.text )
              
              if isExisteKeyPrivateGPF(self.mValueLoginGPF) : 
                 # Concatener les deux dictionnaires (public et privé)
                 if _dicXmlPrivate != None : 
                    _dicXml = {**_dicXml, **_dicXmlPrivate}
                 # Gestion des données PRIVATE

              if len(_dicXmlHisto) == 0 : 
                 _dicXmlHisto = _dicXml 
              else : 
                 _dicXmlHisto = dicXml 
              # Concatener les deux dictionnaires
              #print(_dicXml, "\n\n")
              dicXml = {**_dicXmlHisto, **_dicXml}

              integerPageEncours += 1
           #===============================

        except Exception as _err:
           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Attention" , None)
           zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "A connection problem occurred on the GeoPlatforme." , None)           
           zMess1  += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "An exception was thrown:" , None)           
           zMess1  += "\n" + str(_err)           
           
           displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Warning, self.selfQgeoEntrepot.Dialog.durationBarInfo)
           print("Une exception a été levée :", _err)
           return None

        #Analyse du xml
        if ret != None :
           sorted_dicXml   = dict(sorted(dicXml.items(), key=lambda item: item[1][0]))
           dicXml          = sorted_dicXml
           return dicXml
        else :   
           return None

    #===============================              
    def initDistributionGIDistributionFiltre(self, _selfQgeoDistribution, _lang = 'FR', _zone = None, _format = None, _first = None):
        self.selfQgeoDistribution    = _selfQgeoDistribution 
        self.URL_API_GPF             = self.selfQgeoDistribution.URL_API_GPF
        self.URL_API_GPF_PRIVATE     = self.selfQgeoDistribution.URL_API_GPF_PRIVATE
        self.HTTP_PROXY_GPF          = self.selfQgeoDistribution.HTTP_PROXY_GPF
        self.HTTPS_PROXY_GPF         = self.selfQgeoDistribution.HTTPS_PROXY_GPF
        self.HTTP_PROXY_GI_DISTRIBUTION  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
        self.HTTPS_PROXY_GI_DISTRIBUTION = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
        self._first = None

        self.instanceGeoIdeDistributionTelechargement = GeoIdeDistribution(self.URL_API_GPF, self.URL_API_GPF_PRIVATE, self.mValueLoginGPF, self.HTTP_PROXY_GPF, self.HTTPS_PROXY_GPF, self.HTTP_PROXY_GI_DISTRIBUTION, self.HTTPS_PROXY_GI_DISTRIBUTION)
        return

    #===============================
    def afficheDistribution(self, _selfQgeoEntrepot, _retXml, _retXmlDistribution, _plateforme = "ALL"):
       self.selfQgeoEntrepot = _selfQgeoEntrepot 
       self.header().setStretchLastSection(False)
       self.header().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)

       # Pour ne pas afficher et interroger la plateforme 
       if self._first == "FIRST" : return
       
       _createOrDeleteRegroupement = self.createOrDeleteRegroupement("CREATE")
       if (_plateforme == "ALL" or _plateforme == "GPF") : self.alimenteArboGPF( _retXml, _createOrDeleteRegroupement )
       if (_plateforme == "ALL" or _plateforme == "MTE") : self.alimenteArboDISTRIBUTION( _retXmlDistribution, _createOrDeleteRegroupement )
       self.createOrDeleteRegroupement("DELETE")
       return  

    #===============================
    def createOrDeleteRegroupement(self, _createOrDelete):
        self.mDicRegroupement = QGIREFERENTIELS_REGROUPEMENT
        regroupements         = self.mDicRegroupement["REGROUPEMENT"]

        z = 1
        if _createOrDelete.upper() == "CREATE" : 
           # Ajout des noeuds pour chaque regroupement, sauf "Autres"
           for groupe, code_regroupement in regroupements:
               groupe_item = self.getOrCreateProviderNode( [ f"{groupe}", "REGROUPEMENT", "NOEUD" ] )
               menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25)
               groupe_item.setIcon(0, menuIcon)
               z += 1
           return self.mDicRegroupement["REGROUPEMENT"]
                   
        elif _createOrDelete.upper() == "DELETE" :
           # Parcourir les nœuds racine SENS INVERSE et supprimer ceux qui n'ont pas d'enfants
           for i in reversed(range(self.topLevelItemCount())):
               item = self.topLevelItem(i)
               if item.childCount() == 0:
                   # Supprimer l'élément racine sans enfants
                   self.takeTopLevelItem(i)
        return 

    #===============================
    def alimenteArboGPF(self, _retXml, _createOrDeleteRegroupement):
       if _retXml is None : 
          return
       
       regroupementsGPF          = self.createRegroupementGPF(_retXml, _createOrDeleteRegroupement)
       regroupements = regroupementsGPF
       z = 1

       # Ajout des noeuds pour chaque regroupement
       for groupe, items in regroupements.items():
           groupe_item = self.getOrCreateProviderNode( [ f"{groupe}", "REGROUPEMENT", "NOEUD" ] )
           menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25)
           groupe_item.setIcon(0, menuIcon)
           z += 1
           
           zChild = 1
           # Ajout des items dans le groupe
           for libelle, data in items:
               # Gestion du tuple ou dictionnaire pour data
               if isinstance(data, dict) :
                  _lisInfosBranche = [libelle, data["dossier_racine"], data["dossier_racine"]]
                  _toolTip = data["dossier_racine"]
               else :
                  _lisInfosBranche = [libelle, data[0]               , data[1]]
                  _toolTip = data[1]

               type_item = QTreeWidgetItem(
                   [f"{zChild} - {_lisInfosBranche[1]}", _lisInfosBranche[0], "NOEUD"]
               )
               if find_private(libelle) : 
                  menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf_private.svg"), 25)
               else :   
                  menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf.svg"), 25)
               type_item.setIcon(0, menuIcon)
               type_item.setToolTip(0, _toolTip)
               groupe_item.addChild(type_item)
               zChild += 1
       return

    #===============================
    def createRegroupementGPF(self, _retXml, _createOrDeleteRegroupement):
       regroupements = {}  # Dictionnaire pour organiser les regroupements

       for libelle, data in _retXml.items():
           libelle_find_regroupement = data[0]
           # Trouve le regroupement correspondant
           groupe = None
           for regroupement, code_regroupement in _createOrDeleteRegroupement:
               #print("libelle_find_regroupement, regroupement", libelle_find_regroupement, regroupement)
               if libelle_find_regroupement.startswith(regroupement):
                   groupe = regroupement
                   break
          
           # Organise les items par regroupement
           if groupe:
               if groupe not in regroupements:
                   regroupements[groupe] = []
               regroupements[groupe].append((libelle, data))
           else:
               # Non regroupés
               if "Autres" not in regroupements:
                   regroupements["Autres"] = []
               regroupements["Autres"].append((libelle, data))
       return regroupements

    #===============================
    def getOrCreateProviderNode(self, _lisInfosBranche):
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        for i in range(self.topLevelItemCount()) :
            item = self.topLevelItem(i)
            if item.text(0) == _lisInfosBranche[0] :
               type_item = item
               return type_item
               
        # Retourne le noeud créé
        type_item = QTreeWidgetItem(self, [_lisInfosBranche[0], _lisInfosBranche[1], _lisInfosBranche[2]])
        self.addTopLevelItem(type_item)
        return type_item

    #===============================              
    def alimenteArboDISTRIBUTION(self, _retXmlDistribution, _createOrDeleteRegroupement):
        """
        BDO_0M50_MND_TIF_LAMB93_R075-ED22.7z.034 : 
        {'dossier_racine': '02-BDO-RVB', 'dossier_parent': 'MONODALLES_REGIONALES', 
        'zone': 'R075', 'url': 'http://geoide-distribution.e2.rie.gouv.fr/02-BDO-RVB/MONODALLES_REGIONALES/BDO_0M50_MND_TIF_LAMB93_R075-ED22.7z.034', 
        'format': 'TIF', 'edition': 'ED22'}
        """
        z = 1
        # Parcourir les nœuds racines pour trouver les regroupements
        for i in range(self.topLevelItemCount()):
             itemDISTRIBUTION = self.topLevelItem(i)
             comparaisonRegroupement = itemDISTRIBUTION.text(0)

             if itemDISTRIBUTION is None: return
             if _retXmlDistribution is None: return

             # Parcourir les données du dictionnaire
             for key, value in _retXmlDistribution.items():
                 dossierRacine = f'{value["dossier_racine"]}'
                 dossierParent = f'{value["dossier_parent"]}'
                 
                 #GI_GPF_REGROUPEMENT = { "REGROUPEMENT":   [ ("BD ORTHO®", "-BDO-"), ("BD FORET®", "-BDF"), ("SCAN", "-SCAN") ] }
                 findNoeudRegroupement = "Autres" 
                 for keyRegroupGiGPF, valueRegroupGiGPF in GI_GPF_REGROUPEMENT["REGROUPEMENT"] :  
                     if valueRegroupGiGPF in dossierRacine :  
                        findNoeudRegroupement = keyRegroupGiGPF
                        break

                 if comparaisonRegroupement == findNoeudRegroupement :
                    itemDISTRIBUTION = self.topLevelItem(i)
                    # Ajouter ou récupérer le nœud `dossier_parent`
                    parent_node = self.getOrCreateChildDISTRIBUTION(itemDISTRIBUTION, dossierRacine, "dossierRacine", iconGItooltip = returnIcon(os.path.dirname(__file__) + ("/icons/logo/distribution.svg"), 25))
        return
       
    #===============================
    def getOrCreateChildDISTRIBUTION(self, parent_item, node_name, node_info, tooltip=None, iconGItooltip = None, _ressourceGI = None, _iconPath = None, _millesime = None ):
       caractereMillesime = " ★ "
       
       # Vérifie les enfants existants
       for i in range(parent_item.childCount()):
           child_item = parent_item.child(i)

           if child_item.text(0) == node_name:
               return child_item

       # Crée un nouveau nœud si aucun nœud correspondant n'est trouvé
       _ressourceGI = _ressourceGI if _ressourceGI is not None else ""
       new_node = QTreeWidgetItem(parent_item, [node_name, node_info, _ressourceGI, _iconPath])
       #if node_info != "dossierRacine" and  node_info != "dossierParent" :
       if node_info != "dossierRacine"  :
          
          #Version avec panier
          new_node.setCheckState(0, Qt.CheckState.Unchecked)
          new_node.setFlags(new_node.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
          #Version avec panier

       # Ajouter une icône et une info-bulle si nécessaire
       menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25) if iconGItooltip == None else iconGItooltip
       new_node.setIcon(0, menuIcon)

       # Gestion de la visualisation du millésime
       # Pour test au cas où
       #if _millesime == 'True' :
       #   new_node.setBackground(0, QtGui.QBrush(QtGui.QColor("#FFF9C4")))
       # Gestion de la visualisation du millésime
                                 
       if tooltip:
           new_node.setToolTip(0, tooltip)

       # Ajouter le nœud à l'arborescence
       parent_item.addChild(new_node)
       return new_node

    #===============================
    def integrer_icone_svg(svg_principal_path, icone_path, output_path, scale=0.2, x_offset=5, y_offset=5):
       # Parse les deux fichiers SVG
       tree_main = ET.parse(svg_principal_path)
       root_main = tree_main.getroot()
       
       tree_icon = ET.parse(icone_path)
       root_icon = tree_icon.getroot()

       # Crée un groupe (g) pour appliquer l'échelle et le positionnement
       g = ET.Element('g')
       g.attrib['transform'] = f'translate({x_offset},{y_offset}) scale({scale})'

       # Copie les enfants du SVG icône dans le groupe
       for child in root_icon:
           g.append(child)

       # Ajoute le groupe au SVG principal
       root_main.append(g)

       # Sauvegarde du SVG modifié
       tree_main.write(output_path)
       return

    #===============================
    def getOnlyChildDISTRIBUTION(self, parent_item, node_name, node_info, tooltip=None, iconGItooltip = None):

       # Vérifie les enfants existants
       for i in range(parent_item.childCount()):
           child_item = parent_item.child(i)
           if child_item.text(0) == node_name:
               return child_item
       return 
       
    #===============================              
    def actionDoubleClicked(self, item, column):
        if item == None          : return 
        if item.childCount() > 0 : return
        
        itemlib        = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)  # Libellé
        itemIdResource = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)  # id Resource
        itemNiveau     = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)  # "PAGENOEUD" ou "NOEUD" ou "RESSOURCE" ou "SUBRESSOURCE"
        #=====
        #- Ajouter pour d'autres paramètres
        _lang      = self.selfQgeoEntrepot.findCode( self.selfQgeoEntrepot.mZoneLang.currentText() )

        #=====
        #
        _lang, _zone, _format = returnParametres(self.selfQgeoEntrepot)

        #===============================
        # Gestion des dates              
        _return_date_from, _return_date_to, _return_date_millesime = self.selfQgeoEntrepot.returnDateFiltreParametres()
        if _return_date_from ==  None and _return_date_to == None and _return_date_millesime in [None, False] :
           _dateFrom, _dateTo, _return_date_millesime = None, None, None
        else :    
           _dateFrom, _dateTo, _return_date_millesime = _return_date_from, _return_date_to, _return_date_millesime
        #Juste pour test mDicReturn = { "LANG" : _lang, "ZONE" : _zone, "FORMAT" : _format }
        #print({ "LANG" : _lang, "ZONE" : _zone, "FORMAT" : _format })
        #---- 
        if itemNiveau == "NOEUD" :
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
           #===============================
           # self.itemIdResourceEnCours  = l'id de la ressource cliqué
           # ET itemIdResource    = la page en cours d'affichage
           self.itemIdResourceEnCours = itemIdResource
           #===============================

           #print("NOEUD ", { "LANG" : _lang, "ZONE" : _zone, "FORMAT" : _format })
           if find_private(itemIdResource) : 
              # Gestion des données PRIVATE
              ret = self.instanceGeoIdeDistribution.get_resources_directe_private( itemIdResource,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
           else :   
              # Gestion des données PUBLIC
              ret = self.instanceGeoIdeDistribution.get_resources_directe( itemIdResource,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
           #print(ret.text)
           dicXmlResource, page_size_xml, nb_occurence, nb_page = analyseXmResource( self, ret.text, _return_date_millesime = _return_date_millesime )

           #===============================
           # Gestion de la pagination               
           # A paramètrer plus tard sans la boite de dialogue des paramètres d'affichage'
           entry_en_Cours    = 50 if nb_occurence > 50 else nb_occurence
           _nb_page_en_cours = math.ceil(nb_occurence / entry_en_Cours) if entry_en_Cours != 0 else 0  
           page_en_Cours     = 25 if _nb_page_en_cours    > 25 else _nb_page_en_cours
           # A paramètrer plus tard sans la boite de dialogue des paramètres d'affichage'

           if self.selfQgeoEntrepot.mPaging :
              # Création des niveaux de pagination
              integerPageEncours = 1
              while integerPageEncours <= _nb_page_en_cours :
                 child_item = QTreeWidgetItem( ["Page " + str(integerPageEncours) , str(integerPageEncours), "PAGE"] )
                 menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/page.svg")) 
                 child_item.setIcon(0, menuIcon)
                 item.addChild(child_item)
                 integerPageEncours += 1
           else : 
              # Création des ressources sans pagination
              #Cherche l'item du service 
              iterator = QTreeWidgetItemIterator( self )
              while iterator.value():
                  item = iterator.value()
                  itemlib      = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
                  itemid       = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)

                  if str(itemid) == str(itemIdResource) :
                     parent_item = item
                  iterator += 1
              #Cherche l'item du service 

              #Boucle sur le nombre de page 
              for numberPage in range(1, _nb_page_en_cours + 1) :
                  if find_private(itemIdResource) : 
                     # Gestion des données PRIVATE
                     ret = self.instanceGeoIdeDistribution.get_resources_directe_private( self.itemIdResourceEnCours , numberPage, entry_en_Cours,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
                  else :   
                     # Gestion des données PUBLIC
                     ret = self.instanceGeoIdeDistribution.get_resources_directe( self.itemIdResourceEnCours , numberPage, entry_en_Cours,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)

                  dicXmlResource, page_size_xml, nb_occurence, nb_page = analyseXmResource( self, ret.text, _return_date_millesime = _return_date_millesime )

                  if (parent_item.childCount() == 0 and numberPage == 1) or (parent_item.childCount() >= 0 and numberPage > 1) :  # Evite de réouvrir si déjà calculé
                    for keyResource, valueResource in dicXmlResource.items():
                       # Créer un élément enfant avec le label
                       _ressourceIcon = valueResource[1]
                       _ressourceIcon = "INDETERMINE" if _ressourceIcon is None else _ressourceIcon
                       child_item = QTreeWidgetItem( [valueResource[0], keyResource, "RESSOURCE", myIconFormat( _ressourceIcon.upper() )] )
                       icon = returnIcon( myIconFormat( _ressourceIcon.upper() ), 25)
                       child_item.setIcon(0, icon)

                       # For millésime
                       #Pour test au cas où
                       #_return_date_millesime_valueResource = valueResource[2]
                       #if _return_date_millesime_valueResource == True :
                       #   child_item.setBackground(0, QtGui.QBrush(QtGui.QColor("#FFF9C4")))
                       
                       #Version avec panier
                       child_item.setCheckState(0, Qt.CheckState.Unchecked)
                       child_item.setFlags(child_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
                       parent_item.addChild(child_item)
                       parent_item.setCheckState(0, Qt.CheckState.Unchecked)
                       parent_item.setFlags(parent_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
                       #Version avec panier
                  
              QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
              QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        elif itemNiveau == "PAGE" :
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
           #print("PAGE ", { "LANG" : _lang, "ZONE" : _zone, "FORMAT" : _format })
           
           if find_private(self.itemIdResourceEnCours) : 
              # Gestion des données PRIVATE
              ret = self.instanceGeoIdeDistribution.get_resources_directe_private( self.itemIdResourceEnCours,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
           else :   
              # Gestion des données PUBLIC
              ret = self.instanceGeoIdeDistribution.get_resources_directe( self.itemIdResourceEnCours,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)

           #print("PAGE ", ret.text)
           dicXmlResource, page_size_xml, nb_occurence, nb_page = analyseXmResource( self, ret.text, _return_date_millesime = _return_date_millesime )
           #===============================
           #===============================
           # Gestion de la pagination               
           # Deuxième interrogation avec le paramètre de pagination
           entry_en_Cours    = 50 if nb_occurence > 50 else nb_occurence

           if find_private(self.itemIdResourceEnCours) : 
              # Gestion des données PRIVATE
              ret = self.instanceGeoIdeDistribution.get_resources_directe_private( self.itemIdResourceEnCours, itemIdResource, entry_en_Cours, _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)
           else :   
              # Gestion des données PUBLIC
              ret = self.instanceGeoIdeDistribution.get_resources_directe( self.itemIdResourceEnCours , itemIdResource, entry_en_Cours,  _lang = _lang, _zone = _zone, _format = _format, _dateFrom = _dateFrom, _dateTo = _dateTo)

           # self.itemIdResource  = l'id de la ressource cliqué
           # ET itemIdResource    = la page en cours d'affichage
           #print(ret.text)

           dicXmlResource, page_size_xml, nb_occurence, nb_page = analyseXmResource( self, ret.text, _return_date_millesime = _return_date_millesime )
           # Deuxième interrogation avec le paramètre de pagination
           # A paramètrer plus tard sans la boite de dialogue des paramètres d'affichage'

           iterator = QTreeWidgetItemIterator( self )
           while iterator.value():
                item = iterator.value()
                itemlib      = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
                itemid       = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)

                if str(itemid) == str(itemIdResource) :
                   parent_item = item

                   if parent_item.childCount() == 0 :
    
                      for keyResource, valueResource in dicXmlResource.items():
                          # Créer un élément enfant avec le label
                          _ressourceIcon = valueResource[1]
                          _ressourceIcon = "INDETERMINE" if _ressourceIcon is None else _ressourceIcon
                          icon = returnIcon( myIconFormat( _ressourceIcon.upper() ), 25)
                          child_item = QTreeWidgetItem( [valueResource[0], keyResource, "RESSOURCE", myIconFormat( _ressourceIcon.upper() )] )
                          child_item.setIcon(0, icon)

                          # For millésime
                          #Pour test au cas où
                          #_return_date_millesime_valueResource = valueResource[2]
                          #if _return_date_millesime_valueResource == True :
                          #   child_item.setBackground(0, QtGui.QBrush(QtGui.QColor("#FFF9C4")))
                       
                          #Version avec panier
                          child_item.setCheckState(0, Qt.CheckState.Unchecked)
                          child_item.setFlags(child_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
                          parent_item.addChild(child_item)
                          parent_item.setCheckState(0, Qt.CheckState.Unchecked)
                          parent_item.setFlags(parent_item.flags() | Qt.ItemFlag.ItemIsAutoTristate | Qt.ItemFlag.ItemIsUserCheckable)
                          #Version avec panier
                    
                iterator += 1
           
        elif itemNiveau == "RESSOURCE" :
           if find_private(itemIdResource) : 
              # Gestion des données PRIVATE
              ret = self.instanceGeoIdeDistribution.get_subResources_directe_private( itemIdResource )
           else :   
              # Gestion des données PUBLIC
              ret = self.instanceGeoIdeDistribution.get_subResources_directe( itemIdResource )

           dicXmlSubResource, page_size_xml, nb_occurence, nb_page = analyseXmSubResource( ret.text )
           if len(dicXmlSubResource) == 0 : return
            
           iterator = QTreeWidgetItemIterator( self )
           while iterator.value():
                item = iterator.value()
                itemlib      = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
                itemid       = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)

                if itemid == itemIdResource :
                   parent_item = item

                   if parent_item.childCount() == 0 :
    
                      for keyResource, valueResource in dicXmlSubResource.items():
                          # 
                          #node = QTreeWidgetItem()
                          # Créer un élément enfant avec le label
                          child_item = QTreeWidgetItem( [valueResource, keyResource, "SUBRESSOURCE"] )
                          parent_item.addChild(child_item)
                    
                iterator += 1

        # [ Géo-IDE Distribution ] dossierRacine
        # Pour le double clique Géo-IDE Distribution Exemple "02-BDO-RVB" sous "BD ORTHO"
        # Permet de ne pas afficher le triangle découvrant la sous arborescence       
        elif itemIdResource == "dossierRacine" :
           z = 1
           # Parcourir les nœuds racines pour trouver les regroupements
           for i in range(self.topLevelItemCount()):
                itemDISTRIBUTION = self.topLevelItem(i)
                comparaisonRegroupement = itemDISTRIBUTION.text(0)

                if itemDISTRIBUTION is None: return
                # Parcourir les données du dictionnaire
                for key, value in self.selfQgeoEntrepot.xmlDistributionReturnFunctionApplyParam.items():
                    dossierRacine = f'{value["dossier_racine"]}'
                    dossierParent = f'{value["dossier_parent"]}'

                    #GI_GPF_REGROUPEMENT = { "REGROUPEMENT":   [ ("BD ORTHO®", "-BDO-"), ("BD FORET®", "-BDF"), ("SCAN", "-SCAN") ] }
                    findNoeudRegroupement = "Autres" 
                    for keyRegroupGiGPF, valueRegroupGiGPF in GI_GPF_REGROUPEMENT["REGROUPEMENT"] :  
                        if valueRegroupGiGPF in dossierRacine :  
                           findNoeudRegroupement = keyRegroupGiGPF
                           break
                        
                    if comparaisonRegroupement == findNoeudRegroupement :
                       itemDISTRIBUTION = self.topLevelItem(i)
                    
                       # Ajouter ou récupérer le nœud `dossier_parent`
                       parent_node = self.getOnlyChildDISTRIBUTION(itemDISTRIBUTION, dossierRacine, "dossierRacine", iconGItooltip = returnIcon(os.path.dirname(__file__) + ("/icons/logo/distribution.svg"), 25))
                       if parent_node.text(0) == itemlib :
                          # Ajouter un nœud pour chaque clé du dictionnaire sous `dossierRacine`
                          parent_node_racine = self.getOrCreateChildDISTRIBUTION(parent_node, dossierParent, "dossierParent", iconGItooltip = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25))

        # [ Géo-IDE Distribution ] dossierParent
        # Pour le double clique Géo-IDE Distribution Exemple "MONODALLES REGIONALES" sous "02-BDO-RVB" sous "BD ORTHO"       
        # Permet de ne pas afficher le triangle découvrant la sous arborescence       
        elif itemIdResource == "dossierParent" :
           z = 1
           # Parcourir les nœuds racines pour trouver les regroupements
           for i in range(self.topLevelItemCount()):
                itemDISTRIBUTION = self.topLevelItem(i)
                comparaisonRegroupement = itemDISTRIBUTION.text(0)

                if itemDISTRIBUTION is None: return
                # Parcourir les données du dictionnaire
                for key, value in self.selfQgeoEntrepot.xmlDistributionReturnFunctionApplyParam.items():
                    dossierRacine = f'{value["dossier_racine"]}'
                    dossierParent = f'{value["dossier_parent"]}'
                    
                    #GI_GPF_REGROUPEMENT = { "REGROUPEMENT":   [ ("BD ORTHO®", "-BDO-"), ("BD FORET®", "-BDF"), ("SCAN", "-SCAN") ] }
                    findNoeudRegroupement = "Autres" 
                    for keyRegroupGiGPF, valueRegroupGiGPF in GI_GPF_REGROUPEMENT["REGROUPEMENT"] :  
                        if valueRegroupGiGPF in dossierRacine :  
                           findNoeudRegroupement = keyRegroupGiGPF
                           break
                                            
                    if comparaisonRegroupement == findNoeudRegroupement :
                       itemDISTRIBUTION = self.topLevelItem(i)
                    
                       # Récupérer le nœud `dossier_parent`
                       parent_node = self.getOnlyChildDISTRIBUTION(itemDISTRIBUTION, dossierRacine, "dossierRacine", iconGItooltip = returnIcon(os.path.dirname(__file__) + ("/icons/logo/distribution.svg"), 25))
                       # Récupérer le nœud  `dossierRacine`
                       parent_node_racine = self.getOnlyChildDISTRIBUTION(parent_node, dossierParent, "dossierParent", iconGItooltip = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25))

                       #print( parent_node.text(0) , " --- ", item.parent().data(0, QtCore.Qt.ItemDataRole.DisplayRole) )
                       if parent_node.text(0) == item.parent().data(0, QtCore.Qt.ItemDataRole.DisplayRole) :  # Libellé n-1 :
                          if parent_node_racine.text(0) == itemlib :
                             # Ajouter un nœud pour chaque clé du dictionnaire sous `dossierRacine`
                             #child_node_name = key
                             child_node_name = key.rsplit('.', 1)[0] # Enlève le .001 etc ...
                             child_info = f'{value["format"]} - {value["zone"]} - {value["edition"]}'
                             _millesime = f'{value["Millesime"]}'
                             extentionFormat = child_info.split("-")[0].strip()
                             _ressourceIcon = "INDETERMINE" if extentionFormat is None else extentionFormat
                             icon = returnIcon( myIconFormat( _ressourceIcon.upper() ), 25)                    
                             self.getOrCreateChildDISTRIBUTION(parent_node_racine, child_node_name, child_info, tooltip=value["url"].rsplit('.', 1)[0], iconGItooltip = icon, _ressourceGI = "RESSOURCEGIDISTRIBUTION", _iconPath = myIconFormat( _ressourceIcon.upper() ), _millesime = _millesime )
        

        mappingIsoTreeDistributionTreePanier(self.selfQgeoDistribution, self.selfQgeoDistribution.mTreeListeDistribution, self.selfQgeoDistribution.mTreeListePanier)

        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        return
 
    #===============================              
    def menuContextuelTreeviewDistribution(self, point):
        index = self.indexAt(point)
        if not index.isValid():
           return
        if self.selfQgeoDistribution.downloadEnCours :
           zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
           zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "A download is already in progress." , None)           
           zMess1  += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "Please wait for it to complete before restarting another one." , None)           
           displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoEntrepot.Dialog.durationBarInfo)
           return

        #-------
        if index.data(0) != None : 
           item = self.itemFromIndex(index)
           #item = self.currentItem()
           itemlib         = index.siblingAtColumn(0).data()
           itemIdResource  = index.siblingAtColumn(1).data()
           itemNiveau      = index.siblingAtColumn(2).data()
           self.itemlibLot = index.siblingAtColumn(0).data()
           itemData      = [itemlib, itemIdResource, itemNiveau]
 
           if item != None :
              #============
              if itemNiveau == "RESSOURCE" :
                 if find_private(itemIdResource) : 
                    # Gestion des données PRIVATE
                    ret = self.instanceGeoIdeDistribution.get_donwload_directe_private( itemIdResource )
                 else :   
                    # Gestion des données PUBLIC
                    ret = self.instanceGeoIdeDistribution.get_donwload_directe( itemIdResource )

                 if ret == None : return
                 dicXmlDownload = analyseXmDownload( ret.text )  
                 self.dicXmlDownload = dicXmlDownload  

                 self.treeMenu = QMenu(self)
                 self.treeMenu.setToolTipsVisible(True)
                 
                 # Add for sur Panier
                 if (item.flags() & Qt.ItemFlag.ItemIsEnabled) :   
                    menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/create.svg")) 
                    addLibActionAndActionAddBasket    = QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket")     
                    treeAction_addTooltipAddBasket    = QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket")
                    treeActionAddBasket               = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltipAddBasket, self.treeMenu)
                    self.treeMenu.addAction(treeActionAddBasket)
                    treeActionAddBasket.setToolTip(treeAction_addTooltipAddBasket)
                    treeActionAddBasket.triggered.connect( lambda : self.selfQgeoDistribution.mTreeListePanier.addBasketMenuContextuel( item ) )
                    #
                    self.treeMenu.addSeparator()

                 # GPF Le lot à télécharger en DIFFERE si > 1
                 __keyGPF = [ _key for _key in dicXmlDownload.keys() ][0].rsplit('.', 1)[0] # première clé dans le dictionnaire sans le .001
                 #nbOccurenceReferentiel = returnNombreOccurence( str(os.path.basename( __keyGPF )), dicXmlDownload, GPF = "GPF" )
                 nbOccurenceReferentiel = len(dicXmlDownload)
                 if nbOccurenceReferentiel > 1 : 

                    if self.selfQgeoDistribution.mDownLotDirect : # Gestion du téléchargement du LOT en direct  
                       menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/downloadingdirect.svg")) 
                       __keyDirectGPF = [ _key for _key in dicXmlDownload.keys() ][0].rsplit('.', 1)[0] # première clé dans le dictionnaire sans le .001
                       addLibActionAndActionDirect    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Download direct GPF", None) + " - " + str(os.path.basename( __keyDirectGPF ) )      
                       treeAction_addTooltipDirect    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndActionDirect, None)
                       treeActionDirect               = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltipDirect, self.treeMenu)
                       self.treeMenu.addAction(treeActionDirect)
                       treeActionDirect.setToolTip(treeAction_addTooltipDirect)
                       treeActionDirect.triggered.connect(lambda : self.actionContextuel(__keyDirectGPF, "DOWNLOAD DIRECT GPF", nbOccurenceReferentiel = nbOccurenceReferentiel))
                       #
                       self.treeMenu.addSeparator()

                 menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/exportall.svg")) 
                 __keyDownloadLot = [ _key for _key in dicXmlDownload.keys() ][0].rsplit('.', 1)[0] # première clé dans le dictionnaire sans le .001
                 addLibActionAndAction    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Save Download lot GPF", None) + " - " + str(os.path.basename( __keyDownloadLot ) )      
                 treeAction_addTooltip    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndAction, None)
                 treeAction          = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltip, self.treeMenu)
                 self.treeMenu.addAction(treeAction)
                 treeAction.setToolTip(treeAction_addTooltip)
                 treeAction.triggered.connect(lambda : self.actionContextuel(__keyDownloadLot, "SAVE DOWNLOAD LOT GPF", nbOccurenceReferentiel = nbOccurenceReferentiel))
                 #
                 self.treeMenu.addSeparator()
                 #

                 #-
                 for _key, _value in dicXmlDownload.items() :
                    menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/downloading.svg")) 
                    __key = os.path.basename( _key ) 
                    addLibActionAndAction    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Download", None) + " - " + str(__key)      
                    treeAction_addTooltip    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndAction, None)
                    treeAction          = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltip, self.treeMenu)
                    self.treeMenu.addAction(treeAction)
                    treeAction.setToolTip(treeAction_addTooltip)
                    treeAction.triggered.connect(lambda _, val=_value: self.actionContextuel(val))
                 #
                 self.treeMenu.exec(self.mapToGlobal(point))

              elif itemNiveau == "RESSOURCEGIDISTRIBUTION" :
                 self.treeMenu = QMenu(self)
                 self.treeMenu.setToolTipsVisible(True)

                 # Add for sur Panier
                 if (item.flags() & Qt.ItemFlag.ItemIsEnabled) :   
                    menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/create.svg")) 
                    addLibActionAndActionAddBasket    = QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket")     
                    treeAction_addTooltipAddBasket    = QtWidgets.QApplication.translate("qgidistribution_ui", "Add basket")
                    treeActionAddBasket               = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltipAddBasket, self.treeMenu)
                    self.treeMenu.addAction(treeActionAddBasket)
                    treeActionAddBasket.setToolTip(treeAction_addTooltipAddBasket)
                    treeActionAddBasket.triggered.connect( lambda : self.selfQgeoDistribution.mTreeListePanier.addBasketMenuContextuel( item ) )
                    #
                    self.treeMenu.addSeparator()
                 
                 # Le lot à télécharger en DIFFERE si > 1
                 __key = item.toolTip(0)

                 nbOccurenceReferentiel = returnNombreOccurence( str(os.path.basename( __key )), self.selfQgeoDistribution.xmlDistributionReturnFunctionApplyParam )
                 #nbOccurenceReferentiel = len(dicXmlDownload)
                 if nbOccurenceReferentiel > 1 : 

                    if self.selfQgeoDistribution.mDownLotDirect : # Gestion du téléchargement du LOT en direct  
                       menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/downloadingdirect.svg")) 
                       __keyDirect = item.toolTip(0)
                       addLibActionAndActionDirect    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Download direct", None) + " - " + str(os.path.basename( __key ).rsplit('.', 1)[0] )      
                       treeAction_addTooltipDirect    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndActionDirect, None)
                       treeActionDirect               = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltipDirect, self.treeMenu)
                       self.treeMenu.addAction(treeActionDirect)
                       treeActionDirect.setToolTip(treeAction_addTooltipDirect)
                       treeActionDirect.triggered.connect(lambda : self.actionContextuelGIDistribution(__keyDirect, "DOWNLOAD DIRECT GI", nbOccurenceReferentiel = nbOccurenceReferentiel))
                       #
                       self.treeMenu.addSeparator()

                 menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/exportall.svg")) 
                 __keyDownloadLot = item.toolTip(0)
                 addLibActionAndAction    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Save Download lot", None) + " - " + str(os.path.basename( __key ).rsplit('.', 1)[0] )      
                 treeAction_addTooltip    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndAction, None)
                 treeAction          = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltip, self.treeMenu)
                 self.treeMenu.addAction(treeAction)
                 treeAction.setToolTip(treeAction_addTooltip)
                 treeAction.triggered.connect(lambda : self.actionContextuelGIDistribution(__keyDownloadLot, "SAVE DOWNLOAD LOT", nbOccurenceReferentiel = nbOccurenceReferentiel))
                 #
                 self.treeMenu.addSeparator()
                 #

                 # Toutes les ressources à télécharger
                 #-
                 for _key, _value in self.selfQgeoDistribution.xmlDistributionReturnFunctionApplyParam.items() :
                    # Test si le libellé du lot correspond à chaque ressource du lot sans les .001
                    if os.path.basename( item.toolTip(0) ) == os.path.basename( _key ).rsplit('.', 1)[0] : # Enlève le .001 etc ...  
                       menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/downloading.svg")) 
                       __key = os.path.basename( _key ) 
                       addLibActionAndAction    = QtWidgets.QApplication.translate("qgidistribution_ui",  "Download", None) + " - " + str(__key)      
                       treeAction_addTooltip    = QtWidgets.QApplication.translate("qgidistribution_ui", addLibActionAndAction, None)
                       treeAction          = QAction(QtGui.QIcon(menuIcon), treeAction_addTooltip, self.treeMenu)
                       self.treeMenu.addAction(treeAction)
                       #Affichage des données brutes 
                       if _value['Etat'].upper() == 'GI_BRUTE' : 
                          font = QtGui.QFont(self.selfQgeoDistribution.policeQGroupBox)
                          font.setItalic(True)
                          treeAction.setFont(font)
                       treeAction.setToolTip(treeAction_addTooltip)
                       treeAction.triggered.connect(lambda _, val=_value['url']: self.actionContextuelGIDistribution(val, "DOWNLOAD ONLY"))
                 #
                 
                 self.treeMenu.exec(self.mapToGlobal(point))
        return
 
    #===============================              
    def actionContextuel(self, itemDataDownload, _action = None, nbOccurenceReferentiel = None):
        _local_file_destination      = self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )
        _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( itemDataDownload )))
        _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination
        _geoide_distrib_rate      = 1024
        self._managerLog           = ManagerLog(self.selfQgeoDistribution.urlStatistiquesDistribution)           
        self._managerLogPostgreSQL = ManagerLogPostgreSQL(PP_BASE, PP_USER, PP_PASSWORD, PP_HOST, PP_PORT, PP_SCHEMA, PP_TABLE, self.selfQgeoDistribution.mValueOrganisation)           
        _psql = '"' + find_psql() + '"'

        # Téléchargement direct seul
        if _action == None : 
           self.selfQgeoDistribution.downloadEnCours = True
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
           #----------
           self.traitement_DOWNLOAD_DIRECT_GPF(1, _geoide_distrib_rate, itemDataDownload, "Unique")
           #----------
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           self.selfQgeoDistribution.downloadEnCours = False

        if _action == "SAVE DOWNLOAD LOT GPF" :
           self.selfQgeoDistribution.downloadEnCours = True
           #boite de dialogue Fichiers
           _path= self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText()
           InitDir = _path.replace("\\","/")
           if not InitDir.endswith("/") : InitDir += "/"                   
           TypeList = "Fichier de téléchargement différé d'un lot Windows (*.bat);;Fichier de téléchargement différé d'un lot Linux (*.sh)"
           fileName = QFileDialog.getSaveFileName(self, "Fichier de téléchargement d'un lot :",InitDir,TypeList)[0]
           fileName = str(fileName).strip()

           if fileName == "" : 
              self.selfQgeoDistribution.downloadEnCours = False
              return   
           else : 
              with open(fileName, "wb") as telechargementFile :
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
                 
                 if fileName.rsplit('.', 1)[1] == "sh" :  # LINUX 
                    _psql = '"psql"'
                    mEntete =   "#!/bin/bash" + "\n" 
                    mEntete +=  "# Téléchargement : " +  itemDataDownload + "\n" 
                    mEntete +=  "# " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                    telechargementFile.write( mEntete.encode("utf-8") ) 

                    mdownload  =  '\nexport HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                    mdownload  += '\nexport HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF
                    mdownload  += '\nexport http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                    mdownload  += '\nexport https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF

                    mdownload  += '\npathFilePSQL=' + _psql
                    mdownload  += '\nPP_HOST='     + self.selfQgeoDistribution.PP_HOST
                    mdownload  += '\nPP_PORT='     + self.selfQgeoDistribution.PP_PORT
                    mdownload  += '\nPP_BASE='     + self.selfQgeoDistribution.PP_BASE
                    mdownload  += '\nPP_USER='     + self.selfQgeoDistribution.PP_USER
                    #mdownload  += '\nPP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                    mdownload  += '\nPP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                    mdownload  += '\nPP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                    mdownload  += '\nPGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                    _organisation, _machine = self.return_info_PostgreSQL_Differe()
                    # - 
                    telechargementFile.write( mdownload.encode("utf-8") ) 
                    #

                    _itemDataDownload = itemDataDownload
                    _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           
                    
                    for i in range(1, nbOccurenceReferentiel + 1) :
                       itemDataDownload = [ _key for _key in self.dicXmlDownload.keys() ][i - 1] 
                       _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( _itemDataDownload )).as_posix())
                       _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( _itemDataDownload )).as_posix())
                       _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination
                       
                       if find_private(itemDataDownload) : 
                          # Gestion des données PRIVATE
                          _itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
                       else :   
                          # Gestion des données PUBLIC
                          _itemDataDownload = itemDataDownload 
                       
                       mdownload  = "\nURLGPF="                    + _itemDataDownload
                       mdownload += "\nFILEDESTI="                 + _local_file_destination
                       mdownload += '\nrm -f "'                    + _local_file_destination + '"'
                       mdownload += '\ncurl "$URLGPF"  -o "$FILEDESTI"'
                       
                       # Requête initiale pour obtenir la taille du fichier
                       os.environ["HTTP_PROXY"]  = self.HTTP_PROXY_GPF
                       os.environ["HTTPS_PROXY"] = self.HTTPS_PROXY_GPF
                       os.environ["http_proxy"]  = self.HTTP_PROXY_GPF
                       os.environ["https_proxy"] = self.HTTPS_PROXY_GPF
                       response = requests.head(_itemDataDownload)
                       _taille = int(response.headers.get('Content-Length', 0))                       

                       #Update PostgreSQL / LOG
                       _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GeoPlateforme", "Differe Executable Linux", _id_telechargement, self.itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0' 
                       mysql      = '\n$pathFilePSQL -h $PP_HOST -p $PP_PORT -d $PP_BASE -U $PP_USER -c \"INSERT INTO $PP_SCHEMA.$PP_TABLE '
                       mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                       mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                       mysql     += "$$" + _machine + "$$);"
                       mysql     += '"'
                       mdownload += mysql
                       #Update PostgreSQL / LOG
                       
                       telechargementFile.write( mdownload.encode("utf-8") ) 

                       _managerLogContent    = ["GeoPlateforme", "Differe Linux", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLog.writeManagerLog( _managerLogContent )
                       #-
                       _managerLogContentPostgreSQL = ["GeoPlateforme", "Differe Linux", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
                 else : # WINDOWS 
                    _psql = '"' + find_psql() + '"'
                    mEntete =   "rem Téléchargement : " +  itemDataDownload + "\n" 
                    mEntete +=  "rem " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                    telechargementFile.write( mEntete.encode("utf-8") ) 

                    mdownload  =  '\nset HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                    mdownload  += '\nset HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF
                    mdownload  += '\nset http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                    mdownload  += '\nset https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF

                    mdownload  += '\nset pathFilePSQL=' + _psql
                    mdownload  += '\nset PP_HOST='     + self.selfQgeoDistribution.PP_HOST
                    mdownload  += '\nset PP_PORT='     + self.selfQgeoDistribution.PP_PORT
                    mdownload  += '\nset PP_BASE='     + self.selfQgeoDistribution.PP_BASE
                    mdownload  += '\nset PP_USER='     + self.selfQgeoDistribution.PP_USER
                    #mdownload  += '\nset PP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                    mdownload  += '\nset PP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                    mdownload  += '\nset PP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                    mdownload  += '\nset PGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                    _organisation, _machine = self.return_info_PostgreSQL_Differe()

                    telechargementFile.write( mdownload.encode("utf-8") ) 
                    #

                    _itemDataDownload = itemDataDownload
                    _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

                    for i in range(1, nbOccurenceReferentiel + 1) :
                       itemDataDownload = [ _key for _key in self.dicXmlDownload.keys() ][i - 1] 
                       _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )))
                       _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( itemDataDownload )))
                       _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination

                       if find_private(itemDataDownload) : 
                          # Gestion des données PRIVATE
                          _itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
                       else :   
                          # Gestion des données PUBLIC
                          _itemDataDownload = itemDataDownload 
                       
                       mdownload  = "\nset URLGPF="                    + _itemDataDownload
                       mdownload += "\nset FILEDESTI="                 + _local_file_destination
                       mdownload += '\ndel "'                          + _local_file_destination + '"'
                       mdownload += '\ncurl "%URLGPF%"  -o "%FILEDESTI%"'

                       # Requête initiale pour obtenir la taille du fichier
                       os.environ["HTTP_PROXY"]  = self.HTTP_PROXY_GPF
                       os.environ["HTTPS_PROXY"] = self.HTTPS_PROXY_GPF
                       os.environ["http_proxy"]  = self.HTTP_PROXY_GPF
                       os.environ["https_proxy"] = self.HTTPS_PROXY_GPF
                       response = requests.head(_itemDataDownload)
                       _taille = int(response.headers.get('Content-Length', 0))                       

                       #Update PostgreSQL / LOG
                       _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GeoPlateforme", "Differe Executable Windows", _id_telechargement, self.itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0' 
                       mysql      = '\n%pathFilePSQL% -h %PP_HOST% -p %PP_PORT% -d %PP_BASE% -U %PP_USER% -c \"INSERT INTO %PP_SCHEMA%.%PP_TABLE% '
                       mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                       mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                       mysql     += "$$" + _machine + "$$);"
                       mysql     += '"'
                       mdownload += mysql
                       #Update PostgreSQL / LOG
                       
                       telechargementFile.write( mdownload.encode("utf-8") ) 

                       _managerLogContent = ["GeoPlateforme", "Differe Windows", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLog.writeManagerLog( _managerLogContent )
                       #-
                       _managerLogContentPostgreSQL = ["GeoPlateforme", "Differe Windows", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
            
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                 zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
                 zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      
                 zMess1  += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The file " , None)           
                 zMess1  += fileName     
                 zMess1  += QtWidgets.QApplication.translate("qgidistribution_ui", " has been created." , None)           
                 displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoEntrepot.Dialog.durationBarInfo)

           self.selfQgeoDistribution.downloadEnCours = False

        elif _action == "DOWNLOAD DIRECT GPF" :
           self.selfQgeoDistribution.downloadEnCours = True
           _title = QtWidgets.QApplication.translate("qgidistribution_ui",  "PLUGIN QGIREFERENTIELS", None)
           _mess =  QtWidgets.QApplication.translate("qgidistribution_ui",  "You have wished to download the batch live.", None) + "<br>( " + str(nbOccurenceReferentiel) + " ) parties.<br>" +    QtWidgets.QApplication.translate("qgidistribution_ui",  "The processing may take several minutes.", None) + "<br><br>" + QtWidgets.QApplication.translate("qgidistribution_ui",  "Do you want to continue ?", None)
           if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes|QMessageBox.StandardButton.No) ==  QMessageBox.StandardButton.No :
              self.selfQgeoDistribution.downloadEnCours = False
              return

           #----------
           self.traitement_DOWNLOAD_DIRECT_GPF(nbOccurenceReferentiel, _geoide_distrib_rate, itemDataDownload, "Multiple")
           #----------
           self.selfQgeoDistribution.downloadEnCours = False
        return

    #===============================              
    def traitement_DOWNLOAD_DIRECT_GPF(self, nbOccurenceReferentiel, _geoide_distrib_rate, itemDataDownload, action):
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
        zMessTitle      = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload GeoPlateforme", None) + "  " + str(returnVersion())
        zMessConfirme   = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload files...", None)
        zMessConfirme2  = QtWidgets.QApplication.translate("qgidistribution_ui", "This operation may take a few minutes.", None)
        zMessConfirme3  = QtWidgets.QApplication.translate("qgidistribution_ui", "Wait ........", None)
        #----------
        monHtml = zMessConfirme + "\n\n" + zMessConfirme2  + "\n\n" + zMessConfirme3

        #===============================================
        # Gestion de la taille de fichiers à télécharger
        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF

        _tailleAll = 0 
        if action == "Unique" : # Cas téléchargement en direct UNIQUE 
           if find_private(itemDataDownload) : 
              # Gestion des données PRIVATE
              _itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
           else :   
              # Gestion des données PUBLIC
              _itemDataDownload = itemDataDownload 
              
           # Requête initiale pour obtenir la taille du fichier
           response = requests.head(_itemDataDownload)
           file_size = int(response.headers.get('Content-Length', 0))
           _tailleAll += file_size
        else :
           for i in range(1, nbOccurenceReferentiel + 1) :
               itemDataDownload = [ _key for _key in self.dicXmlDownload.keys() ][i - 1]

               if find_private(itemDataDownload) : 
                  # Gestion des données PRIVATE
                  _itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
               else :   
                  # Gestion des données PUBLIC
                  _itemDataDownload = itemDataDownload 
              
               # Requête initiale pour obtenir la taille du fichier
               response = requests.head(_itemDataDownload)
               file_size = int(response.headers.get('Content-Length', 0))
               _tailleAll += file_size
        # Gestion de la taille de fichiers à télécharger
        #===============================================

        # Téléchargement par morceaux
        chunk_size = _geoide_distrib_rate * _geoide_distrib_rate  # 1 MB
        downloaded = 0            # Taille téléchargée
        start_time = time.time()  # Pour calculer le temps écoulé

        progress_value = 0
        managerPatienter = ManagerPatienter(zMessTitle, monHtml)
        num = managerPatienter.prgr_dialog.maximum() / _tailleAll

        if action == "Unique" : # Cas téléchargement en direct UNIQUE 
           _itemDataDownload = itemDataDownload 

           if find_private(itemDataDownload) : 
              # Gestion des données PRIVATE
              itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
           else :   
              # Gestion des données PUBLIC
              itemDataDownload = itemDataDownload 

           local_file_destination   = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( _itemDataDownload )))
           managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( _itemDataDownload ))
           _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

           with requests.get(itemDataDownload, stream=True) as r, open(local_file_destination, "wb") as f:
               for chunk in r.iter_content(chunk_size=chunk_size):
                   # Gestion du bouton Annuler
                   if managerPatienter.prgr_dialog.wasCanceled():  
                      managerPatienter.prgr_dialog.cancel()
                      QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                      QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )                         
                      return 
                   # Gestion du bouton Annuler
                      
                   if chunk:
                      f.write(chunk)
                      downloaded += len(chunk)

                      # Barre de progression
                      percent = (downloaded / _tailleAll) * 100
                      elapsed_time = time.time() - start_time
                      speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                      speed_log = downloaded / elapsed_time
                      progress_value = percent

                      # Temps restant
                      if elapsed_time > 0:
                         speed = downloaded / elapsed_time  # Vitesse en octets/s
                         remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                      else:
                         remaining_time = 0

                      # Format du temps restant (hh:mm:ss)
                      remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                      messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                      messTime += "\n\n"
                      messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                      messTime += remaining_time_formatted
                      managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( _itemDataDownload ) + "\n\n" + messTime)
                      managerPatienter.prgr_dialog.setValue( int(progress_value) )
               # - 
               _managerLogContent = [ "GeoPlateforme", "Direct Unique", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAll) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLog.writeManagerLog( _managerLogContent )
               #-
               _managerLogContentPostgreSQL = [ "GeoPlateforme", "Direct Unique", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAll) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )

        else :  
           _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           
           for i in range(1, nbOccurenceReferentiel + 1) :
               _tailleAllLog = 0
               start_time_log = time.time()  
               
               itemDataDownload = [ _key for _key in self.dicXmlDownload.keys() ][i - 1] 
               _itemDataDownload = itemDataDownload 

               if find_private(itemDataDownload) : 
                  # Gestion des données PRIVATE
                  itemDataDownload = itemDataDownload + "?apikey=" + self.mValueLoginGPF 
               else :   
                  # Gestion des données PUBLIC
                  itemDataDownload = itemDataDownload 

               local_file_destination   = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( _itemDataDownload )))
               managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( _itemDataDownload ))

               with requests.get(itemDataDownload, stream=True) as r, open(local_file_destination, "wb") as f:
                  for chunk in r.iter_content(chunk_size=chunk_size):
                      # Gestion du bouton Annuler
                      if managerPatienter.prgr_dialog.wasCanceled():  
                         managerPatienter.prgr_dialog.cancel()
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )                         
                         return 
                      # Gestion du bouton Annuler
                         
                      if chunk:
                         f.write(chunk)
                         downloaded += len(chunk)
                         _tailleAllLog += len(chunk)
                         # Barre de progression
                         percent = (downloaded / _tailleAll) * 100
                         elapsed_time = time.time() - start_time
                         elapsed_time_log = time.time() - start_time_log
                         speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                         speed_log = downloaded / elapsed_time
                         progress_value = percent

                         # Temps restant
                         if elapsed_time > 0:
                            speed = downloaded / elapsed_time  # Vitesse en octets/s
                            remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                         else:
                            remaining_time = 0

                         # Format du temps restant (hh:mm:ss)
                         remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                         messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                         messTime += "\n\n"
                         messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                         messTime += remaining_time_formatted
                         managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( _itemDataDownload ) + "\n\n" + messTime)
                         managerPatienter.prgr_dialog.setValue( int(progress_value) )
                         
                  # - 
                  _managerLogContent = [ "GeoPlateforme", "Direct Multiple", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
                  self._managerLog.writeManagerLog( _managerLogContent )
                  #-
                  _managerLogContentPostgreSQL = [ "GeoPlateforme", "Direct Multiple", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
                  self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )

        managerPatienter.startDownload(100, "Téléchargement terminé")
        
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        zTitre = QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Information" , None)
        zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      

        displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoEntrepot.Dialog.durationBarInfo)
        return

    #===============================              
    def actionContextuelGIDistribution(self, itemDataDownload, _action, nbOccurenceReferentiel = None):
        _local_file_destination      = self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )
        _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( itemDataDownload )))
        _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination

        _geoide_distrib_http_user = self.selfQgeoDistribution.mValueLoginGI
        _geoide_distrib_http_pass = self.selfQgeoDistribution.mValueMdpGI 
        _geoide_distrib_rate      = 1024
        self._managerLog           = ManagerLog(self.selfQgeoDistribution.urlStatistiquesDistribution)           
        self._managerLogPostgreSQL = ManagerLogPostgreSQL(PP_BASE, PP_USER, PP_PASSWORD, PP_HOST, PP_PORT, PP_SCHEMA, PP_TABLE, self.selfQgeoDistribution.mValueOrganisation)           
        _psql = '"' + find_psql() + '"'

        if _action == "DOWNLOAD ONLY" : 
           self.selfQgeoDistribution.downloadEnCours = True
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
           #----------
           self.traitement_DOWNLOAD_DIRECT_GIDistribution(1, _geoide_distrib_http_user, _geoide_distrib_http_pass, _geoide_distrib_rate, itemDataDownload, "Unique")
           #----------
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
           self.selfQgeoDistribution.downloadEnCours = False

        elif _action == "SAVE DOWNLOAD LOT" :
           self.selfQgeoDistribution.downloadEnCours = True
           #boite de dialogue Fichiers
           _path= self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText()
           InitDir = _path.replace("\\","/")
           if not InitDir.endswith("/") : InitDir += "/"                   
           TypeList = "Fichier de téléchargement différé d'un lot Windows (*.bat);;Fichier de téléchargement différé d'un lot Linux (*.sh)"
           fileName = QFileDialog.getSaveFileName(self, "Fichier de téléchargement d'un lot :",InitDir,TypeList)[0]
           fileName = str(fileName).strip()

           if fileName == "" : 
              self.selfQgeoDistribution.downloadEnCours = False
              return   
           else : 
              with open(fileName, "wb") as telechargementFile :
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
                 if fileName.rsplit('.', 1)[1] == "sh" :  # LINUX 
                    _psql = '"psql"'
                    mEntete =   "#!/bin/bash" + "\n" 
                    mEntete +=  "# Téléchargement : " +  itemDataDownload + "\n" 
                    mEntete +=  "# " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                    telechargementFile.write( mEntete.encode("utf-8") ) 
                    #
                    mdownload  =  "\n_geoide_distrib_http_user=" + _geoide_distrib_http_user
                    mdownload  += "\n_geoide_distrib_http_pass=" + _geoide_distrib_http_pass.replace("%", "%%")

                    mdownload  += '\nexport HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nexport HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nexport http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nexport https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION

                    mdownload  += '\npathFilePSQL=' + _psql
                    mdownload  += '\nPP_HOST='     + self.selfQgeoDistribution.PP_HOST
                    mdownload  += '\nPP_PORT='     + self.selfQgeoDistribution.PP_PORT
                    mdownload  += '\nPP_BASE='     + self.selfQgeoDistribution.PP_BASE
                    mdownload  += '\nPP_USER='     + self.selfQgeoDistribution.PP_USER
                    #mdownload  += '\nPP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                    mdownload  += '\nPP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                    mdownload  += '\nPP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                    mdownload  += '\nPGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                    _organisation, _machine = self.return_info_PostgreSQL_Differe()
                    # - 
                    telechargementFile.write( mdownload.encode("utf-8") ) 

                    _itemDataDownload = itemDataDownload
                    _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

                    for i in range(1, nbOccurenceReferentiel + 1) :
                       itemDataDownload = _itemDataDownload + "." + str(i).zfill(3)  
                       _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )).as_posix())
                       _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( itemDataDownload )).as_posix())
                       _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination
                       mdownload  = "\nURLGI="                     + itemDataDownload.replace("http", "https")
                       mdownload += "\nFILEDESTI="                 + _local_file_destination
                       mdownload += '\nrm -f "'                    + _local_file_destination + '"'
                       mdownload += '\ncurl -L $URLGI -u "$_geoide_distrib_http_user:$_geoide_distrib_http_pass" -o $FILEDESTI'

                       # Requête initiale pour obtenir la taille du fichier
                       os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                       os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                       os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                       os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION                       
                       response = requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
                       _taille = int(response.headers.get('Content-Length', 0))

                       #Update PostgreSQL / LOG
                       _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GI Distribution", "Differe Executable Linux", _id_telechargement, self.itemlibLot, itemDataDownload, str(_taille), '00:00:00', '0' 
                       mysql      = '\n$pathFilePSQL -h $PP_HOST -p $PP_PORT -d $PP_BASE -U $PP_USER -c \"INSERT INTO $PP_SCHEMA.$PP_TABLE '
                       mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                       mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                       mysql     += "$$" + _machine + "$$);"
                       mysql     += '"'
                       mdownload += mysql
                       #Update PostgreSQL / LOG

                       telechargementFile.write( mdownload.encode("utf-8") ) 

                       _managerLogContent = [ "GI Distribution", "Differe Linux", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", "" ]
                       self._managerLog.writeManagerLog( _managerLogContent )
                       #- 
                       _managerLogContentPostgreSQL = ["GI Distribution", "Differe Linux", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
                 else : # WINDOWS 
                    _psql = '"' + find_psql() + '"'
                    mEntete =   "rem Téléchargement : " +  itemDataDownload + "\n" 
                    mEntete +=  "rem " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                    telechargementFile.write( mEntete.encode("utf-8") ) 
                    #
                    mdownload  =  "\nset _geoide_distrib_http_user=" + _geoide_distrib_http_user
                    mdownload  += "\nset _geoide_distrib_http_pass=" + _geoide_distrib_http_pass.replace("%", "%%")

                    mdownload  += '\nset HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nset HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nset http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nset https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                    mdownload  += '\nset pathFilePSQL=' + _psql

                    mdownload  += '\nset PP_HOST='     + self.selfQgeoDistribution.PP_HOST
                    mdownload  += '\nset PP_PORT='     + self.selfQgeoDistribution.PP_PORT
                    mdownload  += '\nset PP_BASE='     + self.selfQgeoDistribution.PP_BASE
                    mdownload  += '\nset PP_USER='     + self.selfQgeoDistribution.PP_USER
                    #mdownload  += '\nset PP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                    mdownload  += '\nset PP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                    mdownload  += '\nset PP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                    mdownload  += '\nset PGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                    _organisation, _machine = self.return_info_PostgreSQL_Differe()

                    telechargementFile.write( mdownload.encode("utf-8") ) 

                    _itemDataDownload = itemDataDownload
                    _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

                    for i in range(1, nbOccurenceReferentiel + 1) :
                       itemDataDownload = _itemDataDownload + "." + str(i).zfill(3)  
                       _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )))
                       _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( itemDataDownload )))
                       _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination
                       mdownload  = "\nset URLGI="                     + itemDataDownload.replace("http", "https")
                       mdownload += "\nset FILEDESTI="                 + _local_file_destination
                       mdownload += '\ndel "'                          + _local_file_destination + '"'
                       mdownload += '\ncurl -L %URLGI% -u "%_geoide_distrib_http_user%:%_geoide_distrib_http_pass%" -o %FILEDESTI%'

                       # Requête initiale pour obtenir la taille du fichier
                       os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                       os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                       os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                       os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION                       
                       response = requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
                       _taille = int(response.headers.get('Content-Length', 0))

                       #Update PostgreSQL / LOG
                       _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GI Distribution", "Differe Executable Windows", _id_telechargement, self.itemlibLot, itemDataDownload, str(_taille), '00:00:00', '0' 
                       mysql      = '\n%pathFilePSQL% -h %PP_HOST% -p %PP_PORT% -d %PP_BASE% -U %PP_USER% -c \"INSERT INTO %PP_SCHEMA%.%PP_TABLE% '
                       mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                       mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                       mysql     += "$$" + _machine + "$$);"
                       mysql     += '"'
                       mdownload += mysql
                       #Update PostgreSQL / LOG

                       telechargementFile.write( mdownload.encode("utf-8") )

                       _managerLogContent = [ "GI Distribution", "Differe Windows", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", "" ]
                       self._managerLog.writeManagerLog( _managerLogContent )
                       #- 
                       _managerLogContentPostgreSQL = ["GI Distribution", "Differe Windows", _id_telechargement, self.itemlibLot, itemDataDownload, "", "00:00:00", ""]
                       self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
            
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                 QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                 zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
                 zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      
                 zMess1  += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The file " , None)           
                 zMess1  += fileName     
                 zMess1  += QtWidgets.QApplication.translate("qgidistribution_ui", " has been created." , None)           
                 displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoEntrepot.Dialog.durationBarInfo)

           self.selfQgeoDistribution.downloadEnCours = False

        elif _action == "DOWNLOAD DIRECT GI" :
           self.selfQgeoDistribution.downloadEnCours = True
           _title = QtWidgets.QApplication.translate("qgidistribution_ui",  "PLUGIN QGIREFERENTIELS", None)
           _mess =  QtWidgets.QApplication.translate("qgidistribution_ui",  "You have wished to download the batch live.", None) + "<br>( " + str(nbOccurenceReferentiel) + " ) parties.<br>" +    QtWidgets.QApplication.translate("qgidistribution_ui",  "The processing may take several minutes.", None) + "<br><br>" + QtWidgets.QApplication.translate("qgidistribution_ui",  "Do you want to continue ?", None)
           if QMessageBox.question(self, _title, _mess, QMessageBox.StandardButton.Yes|QMessageBox.StandardButton.No) ==  QMessageBox.StandardButton.No : 
              self.selfQgeoDistribution.downloadEnCours = False
              return
           #----------
           self.traitement_DOWNLOAD_DIRECT_GIDistribution(nbOccurenceReferentiel, _geoide_distrib_http_user, _geoide_distrib_http_pass, _geoide_distrib_rate, itemDataDownload, "Multiple")
           #----------
           self.selfQgeoDistribution.downloadEnCours = False
        return
                
    #===============================              
    def traitement_DOWNLOAD_DIRECT_GIDistribution(self, nbOccurenceReferentiel, _geoide_distrib_http_user, _geoide_distrib_http_pass, _geoide_distrib_rate, itemDataDownload, action):
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
        zMessTitle      = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload QGIDistribution", None) + "  " + str(returnVersion())
        zMessConfirme   = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload files...", None)
        zMessConfirme2  = QtWidgets.QApplication.translate("qgidistribution_ui", "This operation may take a few minutes.", None)
        zMessConfirme3  = QtWidgets.QApplication.translate("qgidistribution_ui", "Wait ........", None)
        #----------
        monHtml = zMessConfirme + "\n\n" + zMessConfirme2  + "\n\n" + zMessConfirme3

        #===============================================
        # Gestion de la taille de fichiers à télécharger
        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION

        _tailleAll = 0
         
        if action == "Unique" : # Cas téléchargement en direct UNIQUE 
           itemDataDownload = itemDataDownload 
           # Requête initiale pour obtenir la taille du fichier
           response = requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
           file_size = int(response.headers.get('Content-Length', 0))
           _tailleAll += file_size
        else : 
           _itemDataDownload = itemDataDownload
           for i in range(1, nbOccurenceReferentiel + 1) :
               itemDataDownload = _itemDataDownload + "." + str(i).zfill(3)  
               # Requête initiale pour obtenir la taille du fichier
               response = requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
               file_size = int(response.headers.get('Content-Length', 0))
               _tailleAll += file_size
        # Gestion de la taille de fichiers à télécharger
        #===============================================
        # Téléchargement par morceaux
        chunk_size = _geoide_distrib_rate * _geoide_distrib_rate  # 1 MB
        downloaded = 0            # Taille téléchargée
        start_time = time.time()  # Pour calculer le temps écoulé

        progress_value = 0
        managerPatienter = ManagerPatienter(zMessTitle, monHtml)
        num = managerPatienter.prgr_dialog.maximum() / _tailleAll

        if action == "Unique"  : # Cas téléchargement en direct UNIQUE
           itemDataDownload = itemDataDownload 
           local_file_destination   = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )))
           managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( itemDataDownload ))
           _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

           with requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True) as r, open(local_file_destination, "wb") as f:
               for chunk in r.iter_content(chunk_size=chunk_size):
                   # Gestion du bouton Annuler
                   if managerPatienter.prgr_dialog.wasCanceled():  
                      managerPatienter.prgr_dialog.cancel()
                      QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                      QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )                         
                      return 
                   # Gestion du bouton Annuler
                      
                   if chunk:
                      f.write(chunk)
                      downloaded += len(chunk)

                      # Barre de progression
                      percent = (downloaded / _tailleAll) * 100
                      elapsed_time = time.time() - start_time
                      speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                      speed_log = downloaded / elapsed_time
                      progress_value = percent

                      # Temps restant
                      if elapsed_time > 0:
                         speed = downloaded / elapsed_time  # Vitesse en octets/s
                         remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                      else:
                         remaining_time = 0

                      # Format du temps restant (hh:mm:ss)
                      remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                      messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                      messTime += "\n\n"
                      messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                      messTime += remaining_time_formatted
                      managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( itemDataDownload ) + "\n\n" + messTime)
                      managerPatienter.prgr_dialog.setValue( int(progress_value) )
               # - 
               _managerLogContent = [ "GI Distribution", "Direct Unique", _id_telechargement, self.itemlibLot, itemDataDownload, str( "{:.0f}".format(_tailleAll) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLog.writeManagerLog( _managerLogContent )
               #-
               _managerLogContentPostgreSQL = [ "GI Distribution", "Direct Unique", _id_telechargement, self.itemlibLot, itemDataDownload, str( "{:.0f}".format(_tailleAll) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
        else :  
           _itemDataDownload = itemDataDownload.rsplit('.', 1)[0] # Enlève le .001 etc ...
           _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

           for i in range(1, nbOccurenceReferentiel + 1) :
               _tailleAllLog = 0
               start_time_log = time.time()  

               itemDataDownload = _itemDataDownload + "." + str(i).zfill(3)  
               local_file_destination   = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( itemDataDownload )))
               managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( itemDataDownload ))

               with requests.get(itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True) as r, open(local_file_destination, "wb") as f:
                  for chunk in r.iter_content(chunk_size=chunk_size):
                      # Gestion du bouton Annuler
                      if managerPatienter.prgr_dialog.wasCanceled():  
                         managerPatienter.prgr_dialog.cancel()
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )                         
                         return 
                      # Gestion du bouton Annuler
                         
                      if chunk:
                         f.write(chunk)
                         downloaded += len(chunk)
                         _tailleAllLog += len(chunk)

                         # Barre de progression
                         percent = (downloaded / _tailleAll) * 100
                         elapsed_time = time.time() - start_time
                         elapsed_time_log = time.time() - start_time_log
                         speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                         speed_log = downloaded / elapsed_time
                         progress_value = percent

                         # Temps restant
                         if elapsed_time > 0:
                            speed = downloaded / elapsed_time  # Vitesse en octets/s
                            remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                         else:
                            remaining_time = 0

                         # Format du temps restant (hh:mm:ss)
                         remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                         messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                         messTime += "\n\n"
                         messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                         messTime += remaining_time_formatted
                         managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( itemDataDownload ) + "\n\n" + messTime)
                         managerPatienter.prgr_dialog.setValue( int(progress_value) )
                  # - 
                  _managerLogContent = [ "GI Distribution", "Direct Multiple", _id_telechargement, self.itemlibLot, itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
                  self._managerLog.writeManagerLog( _managerLogContent )
                  #-
                  _managerLogContentPostgreSQL = [ "GI Distribution", "Direct Multiple", _id_telechargement, self.itemlibLot, itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
                  self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )

        managerPatienter.startDownload(100, "Téléchargement terminé")
        
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        zTitre = QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Information" , None)
        zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      
        displayMess(self.selfQgeoEntrepot.Dialog, (2 if self.selfQgeoEntrepot.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoEntrepot.Dialog.durationBarInfo)
        return
        
    #===============================              
    def on_item_changed_qchekcbox(self, item, column):
        # Vérifie si la case à cocher a changé
        if column == 0 and item.flags() & Qt.ItemFlag.ItemIsUserCheckable:
           updateLibelleQCheckBoxSelectObjets(self.selfQgeoDistribution, self.selfQgeoDistribution.mTreeListeDistribution, self.selfQgeoDistribution.mTreeListePanier)
        return

    #===============================              
    def return_info_PostgreSQL_Differe (self) :
        _date_   = datetime.now().strftime("%Y-%m-%d")
        _date    = datetime.strptime(_date_, "%Y-%m-%d").date()
        _heure_  = datetime.now().strftime("%H:%M:%S")
        _heure   = datetime.strptime(_heure_, "%H:%M:%S").time()
        _machine = str(platform.uname()).replace("'", '"')
        _organisation = self.selfQgeoDistribution.mZoneValueOrganisation.text()
        return _organisation, str(_machine)

#========================================================     
#========================================================     
# Class pour le tree View du PANIER
class CustomTREEVIEWPANIER(QTreeWidget):
    customMimeType = "text/plain"
    def __init__(self, *args):
        super().__init__(*args)
        self.imageBasket = QPixmap(os.path.abspath(os.path.dirname(__file__) + "/icons/general/basket.svg"))

        self.setColumnCount(6)
        self.hideColumn (1)   # For hide ID
        self.hideColumn (2)   # For hide ID
        self.hideColumn (3)   # For hide ID
        self.hideColumn (4)   # For hide ID
        self.setHeaderLabels([QtWidgets.QApplication.translate("qgidistribution_ui","Cart Data" , None), "IDG", "PARAM", "ICON", "LOT", "Statut"])
        self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)  
        self.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
        self.customContextMenuRequested.connect(self.menuContextuelTreeviewPanier)
        self.header().setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch) 
        self.header().setStretchLastSection(False)
        self.resizeColumnToContents(0)
        return

    #===============================              
    def initPanier(self, _selfQgeoDistribution, _selfQgeoEntrepotTreeView):
        self.selfQgeoDistribution     = _selfQgeoDistribution 
        self.selfQgeoEntrepotTreeView = _selfQgeoEntrepotTreeView 
        self.URL_API_GPF             = self.selfQgeoDistribution.URL_API_GPF
        self.URL_API_GPF_PRIVATE     = self.selfQgeoDistribution.URL_API_GPF_PRIVATE
        self.HTTP_PROXY_GPF          = self.selfQgeoDistribution.HTTP_PROXY_GPF
        self.HTTPS_PROXY_GPF         = self.selfQgeoDistribution.HTTPS_PROXY_GPF
        return

    #===============================
    # Ajouter au panier
    def addBasket(self, _referenceTreeView):
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )

        self.createOrDeleteNoeudPlateformePanier("CREATE")                  
        def add_checkboxes_recursively(item):
            if item is not None :  
               state = item.checkState(0)  

               if state == Qt.CheckState.Checked:  
                  itemlib           = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
                  itemIdResource    = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)
                  itemNiveau        = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)
                  itemIconPath      = item.data(3, QtCore.Qt.ItemDataRole.DisplayRole)
                  itemIcon          = item.icon(0)
                  _lisInfosBranche  = [itemlib, itemIdResource, itemNiveau, itemIcon, itemIconPath]
                  
                  if _lisInfosBranche[2] == "RESSOURCE" or _lisInfosBranche[2] == "RESSOURCEGIDISTRIBUTION" :
                     self.alimentePanier( _lisInfosBranche )
                     # Désactive 
                     item.setFlags(item.flags() & ~QtCore.Qt.ItemFlag.ItemIsEnabled)            
                     # Décoche 
                     item.setCheckState(0, Qt.CheckState.Unchecked)  # Force la case à décoché

               # Parcourir les enfants du nœud actuel
               for i in range(item.childCount()):
                   child = item.child(i)
                   if child is not None : add_checkboxes_recursively(child)            

        # Parcourir tous les nœuds de premier niveau
        for i in range(_referenceTreeView.topLevelItemCount()):
            top_level_item = _referenceTreeView.topLevelItem(i)
            if top_level_item is not None : add_checkboxes_recursively(top_level_item)            

        self.createOrDeleteNoeudPlateformePanier("DELETE")                  

        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        return

    #===============================
    # Ajouter au panier
    def addBasketMenuContextuel(self, itemMenuContextuel):
        self.createOrDeleteNoeudPlateformePanier("CREATE")                  
        def add_checkboxes_recursively(item):
            itemlib           = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
            itemIdResource    = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)
            itemNiveau        = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)
            itemIconPath      = item.data(3, QtCore.Qt.ItemDataRole.DisplayRole)
            itemIcon          = item.icon(0)
            _lisInfosBranche  = [itemlib, itemIdResource, itemNiveau, itemIcon, itemIconPath]
            
            if _lisInfosBranche[2] == "RESSOURCE" or _lisInfosBranche[2] == "RESSOURCEGIDISTRIBUTION" :
               self.alimentePanier( _lisInfosBranche )
               # Désactive 
               item.setFlags(item.flags() & ~QtCore.Qt.ItemFlag.ItemIsEnabled)            
               # Décoche 
               item.setCheckState(0, Qt.CheckState.Unchecked)  # Force la case à décoché

            # Parcourir les enfants du nœud actuel
            for i in range(item.childCount()):
                child = item.child(i)
                if child is not None : add_checkboxes_recursively(child)            

        if itemMenuContextuel is not None : add_checkboxes_recursively(itemMenuContextuel)            

        self.createOrDeleteNoeudPlateformePanier("DELETE")                  
        return

    #===============================
    def createOrDeleteNoeudPlateformePanier(self, _createOrDelete):
        self.mDicPlateforme = {"Géoplateforme": ["PLATEFORME", "GPF"], "Géoplateforme (données privées)": ["PLATEFORME", "GPFPRIVATE"], "Géo-IDE Distribution": ["PLATEFORME", "GI"]}

        if _createOrDelete.upper() == "CREATE" : 
           # Ajout des noeuds pour chaque regroupement, sauf "Autres"
           for groupe, code_regroupement in self.mDicPlateforme.items():
               groupe_item = self.getOrCreateProviderNodePanier( [ f"{groupe}", code_regroupement[0],  code_regroupement[1]] )
               groupe_item.setExpanded(True)
               menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/general/tiret.png"), 25)
               
               if  code_regroupement[1] == "GPF" : 
                   menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf.svg"), 25)
               elif  code_regroupement[1] == "GPFPRIVATE" : 
                   menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/gpf_private.svg"), 25)
               elif  code_regroupement[1] == "GI" : 
                   menuIcon = returnIcon(os.path.dirname(__file__) + ("/icons/logo/distribution.svg"), 25)
               groupe_item.setIcon(0, menuIcon)
                   
        elif _createOrDelete.upper() == "DELETE" :
           # Parcourir les nœuds racine SENS INVERSE et supprimer ceux qui n'ont pas d'enfants
           for i in reversed(range(self.topLevelItemCount())):
               item = self.topLevelItem(i)
               if item.childCount() == 0:
                   # Supprimer l'élément racine sans enfants
                   self.takeTopLevelItem(i)
        return 

    #===============================
    def getOrCreateProviderNodePanier(self, _lisInfosBranche):
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        _mDicPlateforme = {"Géoplateforme": ["PLATEFORME", "GPF"], "Géoplateforme (données privées)": ["PLATEFORME", "GPFPRIVATE"], "Géo-IDE Distribution": ["PLATEFORME", "GI"]}

        # Vérifier si le nœud existe déjà
        for i in range(self.topLevelItemCount()):
            item = self.topLevelItem(i)
            if item.text(0) == _lisInfosBranche[0] :
               type_item = item
               return type_item

        # Récupérer l'ordre des clés du dictionnaire
        ordered_keys = list(_mDicPlateforme.keys())
        new_key      = _lisInfosBranche[0]
        new_index    = ordered_keys.index(new_key) if new_key in ordered_keys else len(ordered_keys)
        type_item    = QTreeWidgetItem( [_lisInfosBranche[0], _lisInfosBranche[1], _lisInfosBranche[2]])
        insert_index = self.topLevelItemCount()  # Par défaut, ajoute à la fin

        for i in range(self.topLevelItemCount()):
            item = self.topLevelItem(i)
            if item.text(0) in ordered_keys and ordered_keys.index(item.text(0)) > new_index:
               insert_index = i
               break

        # Insérer à la bonne position
        self.insertTopLevelItem(insert_index, type_item)
        return type_item
                                                  
    #===============================
    def alimentePanier(self, _lisInfosBranche):
        _mDicPlateforme = {"Géoplateforme": ["PLATEFORME", "GPF"], "Géoplateforme (données privées)": ["PLATEFORME", "GPFPRIVATE"], "Géo-IDE Distribution": ["PLATEFORME", "GI"]}
        # Parcourir les nœuds existants pour vérifier si un nœud du type donné existe déjà
        # Retourne le noeud existant
        node_plateforme = None  # Stocke le bon nœud
 
        for k, v in _mDicPlateforme.items():

            if (k == "Géoplateforme" and _lisInfosBranche[2] == "RESSOURCE" and not find_private( _lisInfosBranche[1]) ) :
               node_plateforme = self.getOrCreateProviderNodePanier([k, v[0], v[1]])
               break
            if (k == "Géoplateforme (données privées)" and _lisInfosBranche[2] == "RESSOURCE" and find_private( _lisInfosBranche[1]) ) :
               node_plateforme = self.getOrCreateProviderNodePanier([k, v[0], v[1]])
               break
            if (k == "Géo-IDE Distribution"            and _lisInfosBranche[2] == "RESSOURCEGIDISTRIBUTION"):
               node_plateforme = self.getOrCreateProviderNodePanier([k, v[0], v[1]])
               break

        if node_plateforme is None : return  
               
        # Vérifier si l'enfant existe déjà sous node_plateforme
        for i in range(node_plateforme.childCount()):
            child = node_plateforme.child(i)
            if child.text(0) == _lisInfosBranche[0] and child.text(1) == _lisInfosBranche[1]:
               return  

        # Retourne le noeud créé
        type_item = QTreeWidgetItem( [ _lisInfosBranche[0], _lisInfosBranche[1], _lisInfosBranche[2], _lisInfosBranche[4]] )
        type_item.setIcon(0, _lisInfosBranche[3])

        node_plateforme.addChild(type_item)

        node_plateforme.setExpanded(True)
        
        # Ajoute les ressources au lot ajouté
        self.alimenteRessourcePanier( _lisInfosBranche, type_item)
        return 

    #===============================
    def alimenteRessourcePanier(self, _lisInfosBranche, _type_item):
        if _lisInfosBranche[2] == "RESSOURCE" : 
           if find_private(_lisInfosBranche[1]) : 
              # Gestion des données PRIVATE
              ret = self.selfQgeoEntrepotTreeView.instanceGeoIdeDistribution.get_donwload_directe_private( _lisInfosBranche[1] )
           else :   
              # Gestion des données PUBLIC
              ret = self.selfQgeoEntrepotTreeView.instanceGeoIdeDistribution.get_donwload_directe( _lisInfosBranche[1] )

           if ret == None : return
           dicXmlDownload = analyseXmDownload( ret.text )  

           for _key, _value in dicXmlDownload.items() :                                                                       
               __key = os.path.basename( _key ) 
               type_item = QTreeWidgetItem( [ "Ressource - " + str(__key), str(_key), "RESSOURCEPANIER", "", str(__key.rsplit('.', 1)[0]) ] )
               _type_item.addChild(type_item)
        
        elif _lisInfosBranche[2] == "RESSOURCEGIDISTRIBUTION" :
           for _key, _value in self.selfQgeoDistribution.xmlDistributionReturnFunctionApplyParam.items() :
              # Test si le libellé du lot correspond à chaque ressource du lot sans les .001
              if os.path.basename( _lisInfosBranche[0] ) == os.path.basename( _key ).rsplit('.', 1)[0] : # Enlève le .001 etc ...  
                 __key = os.path.basename( _key ) 
                 type_item = QTreeWidgetItem( [ "Ressource - " + str(__key), str(_value['url']), "RESSOURCEGIDISTRIBUTIONPANIER", "", str(__key.rsplit('.', 1)[0]) ] )
                 _type_item.addChild(type_item)
                 #Affichage des données brutes 
                 if _value['Etat'].upper() == 'GI_BRUTE' : 
                    font = QtGui.QFont(self.selfQgeoDistribution.policeQGroupBox)
                    font.setItalic(True)
                    type_item.setFont(0, font)
        return 

    #===============================
    # Désactive les cases à cocher
    def desactiveQCheckBoxBasket(self, _referenceTreeView):
        def disable_checkboxes_recursively(item):
            if item is not None :  
               state = item.checkState(0)  
               item.setCheckState(0, Qt.CheckState.Unchecked)
               # active 
               item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsEnabled)            
                
               # Parcourir les enfants du nœud actuel
               for i in range(item.childCount()):
                   child = item.child(i)
                   if child is not None : disable_checkboxes_recursively(child)            

        # Parcourir tous les nœuds de premier niveau
        for i in range(_referenceTreeView.topLevelItemCount()):
            top_level_item = _referenceTreeView.topLevelItem(i)
            if top_level_item is not None : disable_checkboxes_recursively(top_level_item)            

        return

    #===============================              
    def menuContextuelTreeviewPanier(self, point):
        index = self.indexAt(point)
        if not index.isValid():
           return

        #-------
        if index.data(0) != None : 
           item = self.itemFromIndex(index)
           #item = self.currentItem()
           itemlib         = index.siblingAtColumn(0).data()
           itemIdResource  = index.siblingAtColumn(1).data()
           itemNiveau      = index.siblingAtColumn(2).data()
           itemData        = [itemlib, itemIdResource, itemNiveau]
 
           if item != None :
              #============
              if itemNiveau == "RESSOURCE" or itemNiveau == "RESSOURCEGIDISTRIBUTION" :
                 self.treeMenu = QMenu(self)
                 self.treeMenu.setToolTipsVisible(True)
                 
                 menuIcon                 = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/delete.svg")) 
                 addLibActionAndDeleteAddBasket          = QtWidgets.QApplication.translate("qgidistribution_ui", "Delete basket")     
                 treeAction_addTooltipDeleteAddBasket    = QtWidgets.QApplication.translate("qgidistribution_ui", "Delete tooltip basket")
                 treeActionDeleteAddBasket               = QAction(QtGui.QIcon(menuIcon), addLibActionAndDeleteAddBasket, self.treeMenu)
                 self.treeMenu.addAction(treeActionDeleteAddBasket)
                 treeActionDeleteAddBasket.setToolTip(treeAction_addTooltipDeleteAddBasket)
                 treeActionDeleteAddBasket.triggered.connect( lambda : self.deleteBasketMenuContextuel( item ) )
                 #
                 self.treeMenu.exec(self.mapToGlobal(point))

    #===============================              
    def deleteBasketMenuContextuel(self, _item):
        if _item is not None:
            parent = _item.parent()
            if parent is not None:
                parent.removeChild(_item)  

            if parent.childCount() == 0 : 
               self.invisibleRootItem().removeChild(parent)

        updateLibelleQCheckBoxSelectObjets(self.selfQgeoDistribution, self.selfQgeoDistribution.mTreeListeDistribution, self.selfQgeoDistribution.mTreeListePanier)
        mappingIsoTreeDistributionTreePanier(self.selfQgeoDistribution, self.selfQgeoDistribution.mTreeListeDistribution, self.selfQgeoDistribution.mTreeListePanier, "videOrDeletePanier")
        return

    #===============================              
    def addFlag(self, _typeItem, _lotRessource, _flag):
        if _flag == "vert" : 
           if _lotRessource == "lot": 
               menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/cocheverte.svg"))
           else :
               menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/ressourceverte.svg"))
                
        elif _flag == "orange" : 
           if _lotRessource == "lot": 
               menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/cocheorange.svg")) 
           else :
               menuIcon  = returnIcon(os.path.dirname(__file__) + ("/icons/buttons/ressourceorange.svg")) 

        _typeItem.setIcon(5, menuIcon)      
        return

    #===============================              
    def resetStatus(self):
        iterator = QTreeWidgetItemIterator(self)
        
        while iterator.value():
           item = iterator.value()
           item.setIcon(5, QIcon())      
           iterator += 1  
        return

    #===============================              
    def findItemFromId(self, _id):
        iterator = QTreeWidgetItemIterator(self)
        
        while iterator.value():
           item = iterator.value()
           if _id == item.data(0, QtCore.Qt.ItemDataRole.DisplayRole) :
              return item  
           iterator += 1  
        return None
        
    #===============================              
    def paintEvent(self, event):
        # Création d'un QPainter pour le widget
        painter = QPainter(self.viewport())
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        painter.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)

        # Récupération de la taille du widget
        widget_rect = self.rect()

        # Redimensionne l'image pour qu'elle reste homothétique
        scaled_pixmap = self.imageBasket.scaled(
            widget_rect.size(),
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation
        )

        # Calcul pour centrer l'image dans le widget
        x_offset = (widget_rect.width() - scaled_pixmap.width()) // 2
        y_offset = (widget_rect.height() - scaled_pixmap.height()) // 2

        # Applique une transparence
        painter.setOpacity(0.3)  # Réglez la valeur entre 0 (transparent) et 1 (opaque)

        # Dessine l'image redimensionnée
        painter.drawPixmap(x_offset, y_offset, scaled_pixmap)

        # Appelle la méthode de rendu par défaut pour dessiner les autres éléments
        super().paintEvent(event)

    #===============================              
    def traitement_DOWNLOAD_DIRECT_PANIER(self, selfQgeoDistribution):
        self.resetStatus()
        self._managerLog           = ManagerLog(self.selfQgeoDistribution.urlStatistiquesDistribution)           
        self._managerLogPostgreSQL = ManagerLogPostgreSQL(PP_BASE, PP_USER, PP_PASSWORD, PP_HOST, PP_PORT, PP_SCHEMA, PP_TABLE, self.selfQgeoDistribution.mValueOrganisation)           
        _psql = '"' + find_psql() + '"'

        _geoide_distrib_http_user = self.selfQgeoDistribution.mValueLoginGI
        _geoide_distrib_http_pass = self.selfQgeoDistribution.mValueMdpGI 
        _geoide_distrib_rate      = 1024
        # Treeview panier
        iterator = QTreeWidgetItemIterator(self)
        countGFP = 0
        countGI  = 0
        itemDataDownload = []
        
        while iterator.value():
           item = iterator.value()
           itemlib      = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
           itemid       = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)
           itemtype     = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)
           itemlibLot   = item.data(4, QtCore.Qt.ItemDataRole.DisplayRole)
           item         = item

           if itemtype.lower() ==  "ressourcepanier": 
              countGFP += 1
           elif itemtype.lower() ==  "ressourcegidistributionpanier": 
              countGI += 1
           itemDataDownload.append( (itemlib, itemid, itemtype.lower(), itemlibLot, item) ) 
           iterator += 1
           
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )
        zMessTitle      = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload Basket", None) + "  " + str(returnVersion())
        zMessConfirme   = QtWidgets.QApplication.translate("qgidistribution_ui", "Donwload files...", None)
        zMessConfirme2  = QtWidgets.QApplication.translate("qgidistribution_ui", "This operation may take a few minutes.", None)
        zMessConfirme3  = QtWidgets.QApplication.translate("qgidistribution_ui", "Wait ........", None)
        #----------
        monHtml = zMessConfirme + "\n\n" + zMessConfirme2  + "\n\n" + zMessConfirme3

        #===============================================
        # Gestion de la taille de fichiers à télécharger

        _tailleAll = 0 
        for i in range(0, len(itemDataDownload)) :
            itemlib    = itemDataDownload[i][0]
            lienhttp   = itemDataDownload[i][1]
            param      = itemDataDownload[i][2]
            itemlibLot = itemDataDownload[i][3]
            item       = itemDataDownload[i][4]
            
            if param == "ressourcepanier" : 
               os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
               os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
               os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
               os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
               
               if find_private(lienhttp) : 
                  # Gestion des données PRIVATE
                  _itemDataDownload = lienhttp + "?apikey=" + self.selfQgeoDistribution.mValueLoginGPF 
               else :   
                  # Gestion des données PUBLIC
                  _itemDataDownload = lienhttp

               # Requête initiale pour obtenir la taille du fichier
               response = requests.head(_itemDataDownload)
               file_size = int(response.headers.get('Content-Length', 0))
               _tailleAll += file_size
                   
            elif param == "ressourcegidistributionpanier" : 
               os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
               os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
               os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION   
               os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION 
               
               # Requête initiale pour obtenir la taille du fichier
               response = requests.get(lienhttp, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
               file_size = int(response.headers.get('Content-Length', 0))
               _tailleAll += file_size
        # Gestion de la taille de fichiers à télécharger
        #===============================================

        # Téléchargement par morceaux
        chunk_size = _geoide_distrib_rate * _geoide_distrib_rate  # 1 MB
        downloaded = 0            # Taille téléchargée
        start_time = time.time()  # Pour calculer le temps écoulé

        progress_value = 0
        managerPatienter = ManagerPatienter(zMessTitle, monHtml)
        num = managerPatienter.prgr_dialog.maximum() / _tailleAll

        _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )  
        _firstIdFlag = True         

        for i in range(0, len(itemDataDownload)) :
            _tailleAllLog = 0
            start_time_log = time.time()  
            
            itemlib    = itemDataDownload[i][0]
            lienhttp   = itemDataDownload[i][1]
            param      = itemDataDownload[i][2]
            itemlibLot = itemDataDownload[i][3]
            item       = itemDataDownload[i][4]

            #Gestion du statut - Changement de l'id u statut du lot
            if _firstIdFlag :
               if param in [ "ressource", "ressourcegidistribution"] : 
                  self.addFlag(item, "lot", "orange")
                  _idFlag = itemlib   
                  _firstIdFlag = False
            else  :
               # Réinitialise l'id du statut du lot         
               if param in [ "ressource", "ressourcegidistribution"] : 
                  itemRessource = self.findItemFromId(_idFlag)
                  self.addFlag(itemRessource, "lot", "vert")
                  _idFlag = itemlib         

               if param in [ "ressourcepanier", "ressourcegidistributionpanier"] : 
                  itemRessource = self.findItemFromId(_idFlag)
                  self.addFlag(itemRessource, "lot", "orange")
            #Gestion du statut - Changement de l'id u statut du lot

            if find_private(lienhttp) : 
               # Gestion des données PRIVATE
               _itemDataDownload = lienhttp + "?apikey=" + self.selfQgeoDistribution.mValueLoginGPF 
            else :   
               # Gestion des données PUBLIC
               _itemDataDownload = lienhttp 
            self.itemlibLot = itemlibLot
            
            local_file_destination   = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( lienhttp )))
            managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( lienhttp ))
            #Gestion du statut - Changement de l'id u statut du lot
            if param in [ "ressourcepanier", "ressourcegidistributionpanier"] : self.addFlag(item, "ressource", "orange")

            if param == "ressourcepanier" : 
               os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
               os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
               os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
               os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF

               with requests.get(_itemDataDownload, stream=True) as r, open(local_file_destination, "wb") as f:
                  for chunk in r.iter_content(chunk_size=chunk_size):
                      # Gestion du bouton Annuler
                      if managerPatienter.prgr_dialog.wasCanceled():  
                         managerPatienter.prgr_dialog.cancel()
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) ) 
                         #Gestion du statut - Changement de l'id u statut du lot
                         self.addFlag(item, "ressource", "orange")
                         return 
                      # Gestion du bouton Annuler
                         
                      if chunk:
                         f.write(chunk)
                         downloaded += len(chunk)
                         _tailleAllLog += len(chunk)
                         # Barre de progression
                         percent = (downloaded / _tailleAll) * 100
                         elapsed_time = time.time() - start_time
                         elapsed_time_log = time.time() - start_time_log
                         speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                         speed_log = downloaded / elapsed_time
                         progress_value = percent

                         # Temps restant
                         if elapsed_time > 0:
                            speed = downloaded / elapsed_time  # Vitesse en octets/s
                            remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                         else:
                            remaining_time = 0

                         # Format du temps restant (hh:mm:ss)
                         remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                         messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                         messTime += "\n\n"
                         messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                         messTime += remaining_time_formatted
                         managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( lienhttp ) + "\n\n" + messTime)
                         managerPatienter.prgr_dialog.setValue( int(progress_value) )
                  #Gestion du statut - Changement de l'id u statut du lot
                  self.addFlag(item, "ressource", "vert")
               # - 
               _managerLogContent = [ "GeoPlateforme", "Direct Panier", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLog.writeManagerLog( _managerLogContent )
               #-
               _managerLogContentPostgreSQL = [ "GeoPlateforme", "Direct Panier", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )

            elif param == "ressourcegidistributionpanier" : 
               os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
               os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
               os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION   
               os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION 

               with requests.get(lienhttp, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True) as r, open(local_file_destination, "wb") as f:
                  for chunk in r.iter_content(chunk_size=chunk_size):
                      # Gestion du bouton Annuler
                      if managerPatienter.prgr_dialog.wasCanceled():  
                         managerPatienter.prgr_dialog.cancel()
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
                         QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )                         
                         #Gestion du statut - Changement de l'id u statut du lot
                         self.addFlag(item, "ressource", "orange")
                         return 
                      # Gestion du bouton Annuler
                         
                      if chunk:
                         f.write(chunk)
                         downloaded += len(chunk)
                         _tailleAllLog += len(chunk)

                         # Barre de progression
                         percent = (downloaded / _tailleAll) * 100
                         elapsed_time = time.time() - start_time
                         elapsed_time_log = time.time() - start_time_log
                         speed     = downloaded / elapsed_time / (1024 * 1024)  # Vitesse en MB/s
                         speed_log = downloaded / elapsed_time
                         progress_value = percent

                         # Temps restant
                         if elapsed_time > 0:
                            speed = downloaded / elapsed_time  # Vitesse en octets/s
                            remaining_time = (_tailleAll - downloaded) / speed if speed > 0 else 0 
                         else:
                            remaining_time = 0

                         # Format du temps restant (hh:mm:ss)
                         remaining_time_formatted = time.strftime("%H:%M:%S", time.gmtime(remaining_time))
                         messTime = "\r{:,.2f} MB / {:,.2f} MB".format(downloaded / (1024 * 1024), _tailleAll / (1024 * 1024)).replace(',', ' ')
                         messTime += "\n\n"
                         messTime += QtWidgets.QApplication.translate("qgidistribution_ui", "Time remaining:", None)
                         messTime += remaining_time_formatted
                         managerPatienter.startDownload(progress_value, monHtml + "\n\n" + os.path.basename( _itemDataDownload ) + "\n\n" + messTime)
                         managerPatienter.prgr_dialog.setValue( int(progress_value) )
                  #Gestion du statut - Changement de l'id u statut du lot
                  self.addFlag(item, "ressource", "vert")
               
               # - 
               _managerLogContent = [ "GI Distribution", "Direct Panier", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLog.writeManagerLog( _managerLogContent )
               #-
               _managerLogContentPostgreSQL = [ "GI Distribution", "Direct Panier", _id_telechargement, self.itemlibLot, _itemDataDownload, str( "{:.0f}".format(_tailleAllLog) ), str( time.strftime("%H:%M:%S", time.gmtime(elapsed_time)) ), str( "{:.0f}".format(speed_log) ) ]
               self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )

        #Gestion du statut - Changement de l'id u statut du lot
        itemRessource = self.findItemFromId(_idFlag)
        self.addFlag(itemRessource, "lot", "vert")
        #Gestion du statut - Changement de l'id u statut du lot

        managerPatienter.startDownload(100, "Téléchargement terminé")
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
        QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )

        zTitre = QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Information" , None)
        zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      
        displayMess(self.selfQgeoDistribution.Dialog, (2 if self.selfQgeoDistribution.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoDistribution.Dialog.durationBarInfo)
        return

    #===============================              
    def traitement_DOWNLOAD_SAVE_PANIER(self, _selfQgeoDistribution):
        #boite de dialogue Fichiers
        _path= self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText()
        InitDir = _path.replace("\\","/")
        if not InitDir.endswith("/") : InitDir += "/"                   
        TypeList = "Fichier de téléchargement différé du panier Windows (*.bat);;Fichier de téléchargement différé du panier Linux (*.sh)"
        fileName = QFileDialog.getSaveFileName(self, "Fichier de téléchargement du panier :",InitDir,TypeList)[0]
        fileName = str(fileName).strip()

        if fileName == "" : return   
        else : 
           with open(fileName, "wb") as telechargementFile :
              QApplication.setOverrideCursor( QCursor( Qt.CursorShape.WaitCursor ) )    

              self.resetStatus()
              self._managerLog           = ManagerLog(self.selfQgeoDistribution.urlStatistiquesDistribution)           
              self._managerLogPostgreSQL = ManagerLogPostgreSQL(PP_BASE, PP_USER, PP_PASSWORD, PP_HOST, PP_PORT, PP_SCHEMA, PP_TABLE, self.selfQgeoDistribution.mValueOrganisation)           
              _psql = '"' + find_psql() + '"'

              _geoide_distrib_http_user = self.selfQgeoDistribution.mValueLoginGI
              _geoide_distrib_http_pass = self.selfQgeoDistribution.mValueMdpGI 
              _geoide_distrib_rate      = 1024
              # Treeview panier
              iterator = QTreeWidgetItemIterator(self)
              countGFP = 0
              countGI  = 0
              itemDataDownload = []
              
              while iterator.value():
                 item = iterator.value()
                 itemlib        = item.data(0, QtCore.Qt.ItemDataRole.DisplayRole)
                 itemid         = item.data(1, QtCore.Qt.ItemDataRole.DisplayRole)
                 itemtype       = item.data(2, QtCore.Qt.ItemDataRole.DisplayRole)
                 itemplateforme = item.data(3, QtCore.Qt.ItemDataRole.DisplayRole)
                 itemlibLot     = item.data(4, QtCore.Qt.ItemDataRole.DisplayRole)
                 item           = item

                 if itemtype.lower() in  [ "ressourcepanier", "ressourcegidistributionpanier" ] : 
                    itemDataDownload.append( (itemlib, itemid, itemtype.lower(), itemlibLot, item, itemplateforme) ) 
                 iterator += 1
           

              if fileName.rsplit('.', 1)[1] == "sh" :  # LINUX 
                 _psql = '"psql"'
                 mEntete =   "#!/bin/bash" + "\n" 
                 mEntete +=  "rem Téléchargement du panier" + "\n" 
                 mEntete +=  "rem " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                 telechargementFile.write( mEntete.encode("utf-8") ) 

                 mdownload  =  "\n_geoide_distrib_http_user=" + _geoide_distrib_http_user
                 mdownload  += "\n_geoide_distrib_http_pass=" + _geoide_distrib_http_pass.replace("%", "%%")
                 mdownload  += '\npathFilePSQL=' + _psql
                 mdownload  += '\nPP_HOST='     + self.selfQgeoDistribution.PP_HOST
                 mdownload  += '\nPP_PORT='     + self.selfQgeoDistribution.PP_PORT
                 mdownload  += '\nPP_BASE='     + self.selfQgeoDistribution.PP_BASE
                 mdownload  += '\nPP_USER='     + self.selfQgeoDistribution.PP_USER
                 #mdownload  += '\nset PP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                 mdownload  += '\nPP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                 mdownload  += '\nPP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                 mdownload  += '\nPGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                 _organisation, _machine = self.selfQgeoDistribution.mTreeListeDistribution.return_info_PostgreSQL_Differe()

                 telechargementFile.write( mdownload.encode("utf-8") ) 
                 #

                 _itemDataDownload = itemid
                 _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

                 for i in range(0, len(itemDataDownload)) :
                     _tailleAllLog = 0
                     start_time_log = time.time()  
                     
                     itemlib    = itemDataDownload[i][0]
                     lienhttp   = itemDataDownload[i][1]
                     param      = itemDataDownload[i][2]
                     itemlibLot = itemDataDownload[i][3]
                     item       = itemDataDownload[i][4]
                     itemplateforme = itemDataDownload[i][5]

                     _itemDataDownload = lienhttp
                     _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( lienhttp )))
                     _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( lienhttp )))
                     _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination

                     if find_private(_itemDataDownload) : 
                        # Gestion des données PRIVATE
                        _itemDataDownload = _itemDataDownload + "?apikey=" + self.selfQgeoDistribution.mValueLoginGPF 
                     else :   
                        # Gestion des données PUBLIC
                        _itemDataDownload = _itemDataDownload 
                     # Requête initiale pour obtenir la taille du fichier
                     if param == "ressourcepanier" : 
                        mdownload  =  '\nexport HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                        mdownload  += '\nexport HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        mdownload  += '\nexport http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                        mdownload  += '\nexport https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF

                        mdownload  += "\nURLGPF="                    + _itemDataDownload
                        mdownload  += "\nFILEDESTI="                 + _local_file_destination
                        mdownload  += '\nrm -f "'                    + _local_file_destination + '"'
                        mdownload  += '\ncurl "$URLGPF"  -o "$FILEDESTI"'

                        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
                        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
                        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        response = requests.head(_itemDataDownload)
                        _taille = int(response.headers.get('Content-Length', 0))  
                     else : 
                        mdownload  =  '\nexport HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nexport HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nexport http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nexport https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION

                        mdownload += "\nURLGI="                     + _itemDataDownload.replace("http", "https")
                        mdownload += "\nFILEDESTI="                 + _local_file_destination
                        mdownload += '\nrm -f "'                    + _local_file_destination + '"'
                        mdownload += '\ncurl -L $URLGI -u "$_geoide_distrib_http_user:$_geoide_distrib_http_pass" -o $FILEDESTI'

                        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        response = requests.get(_itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
                        _taille = int(response.headers.get('Content-Length', 0))

                     #Update PostgreSQL / LOG
                     if param == "ressourcepanier" : 
                        _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GeoPlateforme", "Differe Panier Executable Linux", _id_telechargement, itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0'
                     else :     
                        _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GI Distribution", "Differe Panier Executable Linux", _id_telechargement, itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0' 
                     mysql      = '\n$pathFilePSQL -h $PP_HOST -p $PP_PORT -d $PP_BASE -U $PP_USER -c \"INSERT INTO $PP_SCHEMA.$PP_TABLE '
                     mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                     mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                     mysql     += "$$" + _machine + "$$);"
                     mysql     += '"'
                     mdownload += mysql
                     #Update PostgreSQL / LOG
                     
                     telechargementFile.write( mdownload.encode("utf-8") ) 

                     if param == "ressourcepanier" : 
                         _managerLogContent = ["GeoPlateforme", "Differe Panier Linux", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     else :
                         _managerLogContent = ["GI Distribution", "Differe Panier Linux", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", "" ]
                           
                     self._managerLog.writeManagerLog( _managerLogContent )
                     #-
                     if param == "ressourcepanier" : 
                        _managerLogContentPostgreSQL = ["GeoPlateforme", "Differe Panier Linux", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     else :    
                        _managerLogContentPostgreSQL = ["GI Distribution", "Differe Panier Linux", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
                     
              else : # WINDOWS 
                 _psql = '"' + find_psql() + '"'
                 mEntete =   "rem Téléchargement du panier" + "\n" 
                 mEntete +=  "rem " + time.strftime("%d ") + zMyFrenchMonth(float(time.strftime("%m"))) + time.strftime(" %Y - %Hh %Mm") + "\n"
                 telechargementFile.write( mEntete.encode("utf-8") ) 

                 mdownload  =  "\nset _geoide_distrib_http_user=" + _geoide_distrib_http_user
                 mdownload  += "\nset _geoide_distrib_http_pass=" + _geoide_distrib_http_pass.replace("%", "%%")
                 mdownload  += '\nset pathFilePSQL=' + _psql
                 mdownload  += '\nset PP_HOST='     + self.selfQgeoDistribution.PP_HOST
                 mdownload  += '\nset PP_PORT='     + self.selfQgeoDistribution.PP_PORT
                 mdownload  += '\nset PP_BASE='     + self.selfQgeoDistribution.PP_BASE
                 mdownload  += '\nset PP_USER='     + self.selfQgeoDistribution.PP_USER
                 #mdownload  += '\nset PP_PASSWORD=' + self.selfQgeoDistribution.PP_PASSWORD
                 mdownload  += '\nset PP_SCHEMA='   + self.selfQgeoDistribution.PP_SCHEMA
                 mdownload  += '\nset PP_TABLE='    + self.selfQgeoDistribution.PP_TABLE
                 mdownload  += '\nset PGPASSWORD='  + self.selfQgeoDistribution.PP_PASSWORD
                 _organisation, _machine = self.selfQgeoDistribution.mTreeListeDistribution.return_info_PostgreSQL_Differe()

                 telechargementFile.write( mdownload.encode("utf-8") ) 
                 #

                 _itemDataDownload = itemid
                 _id_telechargement = str( time.strftime("%Y-%m-%d | %H:%M:%S", time.gmtime( time.time() ) ) )           

                 for i in range(0, len(itemDataDownload)) :
                     _tailleAllLog = 0
                     start_time_log = time.time()  
                     
                     itemlib    = itemDataDownload[i][0]
                     lienhttp   = itemDataDownload[i][1]
                     param      = itemDataDownload[i][2]
                     itemlibLot = itemDataDownload[i][3]
                     item       = itemDataDownload[i][4]
                     itemplateforme = itemDataDownload[i][5]

                     _itemDataDownload = lienhttp
                     _local_file_destination      = str(Path(self.selfQgeoDistribution.mZoneQComboValuePathReferentiel.currentText() + "/" + os.path.basename( lienhttp )))
                     _local_file_destinationRadio = str(Path(self.selfQgeoDistribution.createRadioButton.mZonepathForce.text()       + "/" + os.path.basename( lienhttp )))
                     _local_file_destination      = _local_file_destinationRadio if self.selfQgeoDistribution.createRadioButton.pathForce.isChecked() else _local_file_destination

                     if find_private(_itemDataDownload) : 
                        # Gestion des données PRIVATE
                        _itemDataDownload = _itemDataDownload + "?apikey=" + self.selfQgeoDistribution.mValueLoginGPF 
                     else :   
                        # Gestion des données PUBLIC
                        _itemDataDownload = _itemDataDownload 
                     # Requête initiale pour obtenir la taille du fichier
                     if param == "ressourcepanier" : 
                        mdownload  =  '\nset HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                        mdownload  += '\nset HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        mdownload  += '\nset http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GPF
                        mdownload  += '\nset https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GPF

                        mdownload  += "\nset URLGPF="                    + _itemDataDownload
                        mdownload  += "\nset FILEDESTI="                 + _local_file_destination
                        mdownload  += '\ndel "'                          + _local_file_destination + '"'
                        mdownload  += '\ncurl "%URLGPF%"  -o "%FILEDESTI%"'

                        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
                        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GPF
                        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GPF
                        response = requests.head(_itemDataDownload)
                        _taille = int(response.headers.get('Content-Length', 0))  
                     else : 
                        mdownload  =  '\nset HTTP_PROXY='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nset HTTPS_PROXY='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nset http_proxy='   + self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        mdownload  += '\nset https_proxy='  + self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION

                        mdownload += "\nset URLGI="                     + _itemDataDownload.replace("http", "https")
                        mdownload += "\nset FILEDESTI="                 + _local_file_destination
                        mdownload += '\ndel "'                          + _local_file_destination + '"'
                        mdownload += '\ncurl -L %URLGI% -u "%_geoide_distrib_http_user%:%_geoide_distrib_http_pass%" -o %FILEDESTI%'

                        os.environ["HTTP_PROXY"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        os.environ["HTTPS_PROXY"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        os.environ["http_proxy"]  = self.selfQgeoDistribution.HTTP_PROXY_GI_DISTRIBUTION
                        os.environ["https_proxy"] = self.selfQgeoDistribution.HTTPS_PROXY_GI_DISTRIBUTION
                        response = requests.get(_itemDataDownload, auth=(_geoide_distrib_http_user, _geoide_distrib_http_pass), stream=True )
                        _taille = int(response.headers.get('Content-Length', 0))

                     #Update PostgreSQL / LOG
                     if param == "ressourcepanier" : 
                        _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GeoPlateforme", "Differe Panier Executable Windows", _id_telechargement, itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0'
                     else :     
                        _plateforme, _action, _id, _lot, _ressource, _taille, _temp, _vitesse = "GI Distribution", "Differe Panier Executable Windows", _id_telechargement, itemlibLot, _itemDataDownload, str(_taille), '00:00:00', '0' 
                     mysql      = '\n%pathFilePSQL% -h %PP_HOST% -p %PP_PORT% -d %PP_BASE% -U %PP_USER% -c \"INSERT INTO %PP_SCHEMA%.%PP_TABLE% '
                     mysql     += '(date, heure, organisation, plateforme, action, id_telechargement, lot, ressource, taille, temps, vitesse, machine) '
                     mysql     += "VALUES (CURRENT_DATE, CURRENT_TIME, $$" + _organisation + "$$,'" + _plateforme + "','" + _action + "','" + _id + "','" + _lot + "','" + _ressource + "'," + _taille + ",'" + _temp + "'," + _vitesse + ","
                     mysql     += "$$" + _machine + "$$);"
                     mysql     += '"'
                     mdownload += mysql
                     #Update PostgreSQL / LOG
                     
                     telechargementFile.write( mdownload.encode("utf-8") ) 

                     if param == "ressourcepanier" : 
                         _managerLogContent = ["GeoPlateforme", "Differe Panier Windows", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     else :
                         _managerLogContent = ["GI Distribution", "Differe Panier Windows", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", "" ]
                           
                     self._managerLog.writeManagerLog( _managerLogContent )
                     #-
                     if param == "ressourcepanier" : 
                        _managerLogContentPostgreSQL = ["GeoPlateforme", "Differe Panier Windows", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     else :    
                        _managerLogContentPostgreSQL = ["GI Distribution", "Differe Panier Windows", _id_telechargement, itemlibLot, _itemDataDownload, "", "00:00:00", ""]
                     self._managerLogPostgreSQL.writeManagerLogPostgreSQL( _managerLogContentPostgreSQL )
         
              QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
              QApplication.setOverrideCursor( QCursor( Qt.CursorShape.ArrowCursor ) )
              zTitre = QtWidgets.QApplication.translate("qgidistribution_ui", "PLUGIN QGIREFERENTIELS : Information" , None)
              zMess1  = QtWidgets.QApplication.translate("qgidistribution_ui", "Processing complete." , None)      
              zMess1  += "\n" + QtWidgets.QApplication.translate("qgidistribution_ui", "The file " , None)           
              zMess1  += fileName     
              zMess1  += QtWidgets.QApplication.translate("qgidistribution_ui", " has been created." , None)           

              displayMess(self.selfQgeoDistribution.Dialog, (2 if self.selfQgeoDistribution.Dialog.displayMessage else 1), zTitre, zMess1 , Qgis.Info, self.selfQgeoDistribution.Dialog.durationBarInfo)
        return

#========================================================     
#========================================================     
# Class pour la création de radio boutons
class RadioButtonDate(QWidget):
    def __init__(self, _selfQgeoDistribution):
        super().__init__()
        self.selfQgeoDistribution = _selfQgeoDistribution

        self.selfQgeoDistribution.groupBox_QSplitterFiltre_Date.setMaximumHeight(110)
        
        self.sous_groupBox_radio_date = QtWidgets.QGroupBox()
        self.sous_groupBox_radio_date.setObjectName("sous_groupBox_radio_date")
        self.sous_groupBox_radio_date.setStyleSheet("QGroupBox {   \
                              margin-top: 0px; \
                              margin-left: 0px; \
                              margin-right: 0px; \
                              margin-down: 20px; \
                              font-family:" + self.selfQgeoDistribution.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:0px ; \
                              border-color:"  + self.selfQgeoDistribution.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    06px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.sous_layout_radio_date = QtWidgets.QGridLayout()
        self.sous_layout_radio_date.setColumnStretch(0, 2)
        self.sous_layout_radio_date.setColumnStretch(1, 2)
        self.sous_layout_radio_date.setColumnStretch(2, 1)
        self.sous_layout_radio_date.setColumnStretch(3, 2)
        self.sous_layout_radio_date.setColumnStretch(4, 2)
        self.sous_layout_radio_date.setContentsMargins(0, 0, 0, 0)
        
        self.sous_groupBox_radio_date.setLayout(self.sous_layout_radio_date)
        
        self.radio_date_aucune  = QRadioButton(QtWidgets.QApplication.translate("qgientrepot_ui", "No date" , None))
        self.radio_date_annee   = QRadioButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Year date" , None))
        self.radio_date_periode = QRadioButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Between date" , None))
        
        self.radio_date_aucune.setChecked(True if self.selfQgeoDistribution.mZoneRadioDate else False)

        # Radio connection
        self.radio_date_aucune.toggled.connect(lambda : self.on_radio_button_toggled_date(1))
        self.radio_date_annee.toggled.connect(lambda : self.on_radio_button_toggled_date(2))
        self.radio_date_periode.toggled.connect(lambda : self.on_radio_button_toggled_date(3))

        # Layout vertical
        self.sous_layout_radio_date.addWidget(self.radio_date_aucune, 0, 0)
        self.sous_layout_radio_date.addWidget(self.radio_date_annee, 1, 0)
        self.sous_layout_radio_date.addWidget(self.radio_date_periode, 2, 0)

        regex = QRegularExpression(r"^\d{4}$") 
        #-  DATE ANNEEE
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",       "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), ""          , "mZoneDateAnnee",  Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneDateAnnee = genereButtonWithDict( dicParamButton )
        self.mZoneDateAnnee = mZoneDateAnnee
        validator = QRegularExpressionValidator(regex, mZoneDateAnnee)
        mZoneDateAnnee.setValidator(validator)        
        self.sous_layout_radio_date.addWidget(mZoneDateAnnee,1 ,1 ,1 ,1, Qt.AlignmentFlag.AlignTop )
        #-

        #-  DATE FROM
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",       "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), ""          , "mZoneDateFrom",  Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneDateFrom = genereButtonWithDict( dicParamButton )
        self.mZoneDateFrom = mZoneDateFrom
        validator = QRegularExpressionValidator(regex, mZoneDateFrom)
        mZoneDateFrom.setValidator(validator)        
        self.sous_layout_radio_date.addWidget(mZoneDateFrom,2 ,1 ,1 ,1, Qt.AlignmentFlag.AlignTop )
        #-  DATE TO LABEL
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "To", None)
        mTextToolTip = ""
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "toolTipWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), mText,        "label_" ,     Qt.AlignmentFlag.AlignCenter,  True,        mTextToolTip,   "QLabel {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  +"; background-color:" + self.selfQgeoDistribution.labelBackGround  +";}" ]
        dicParamLabel = dict(zip(_Listkeys, _ListValues))
        mLabelDateTo  = genereLabelWithDict( dicParamLabel )
        self.sous_layout_radio_date.addWidget(mLabelDateTo,2 ,2 ,1 ,1, Qt.AlignmentFlag.AlignTop)
        #-
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",       "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), ""          , "mZoneDateTo",  Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneDateTo = genereButtonWithDict( dicParamButton )
        self.mZoneDateTo = mZoneDateTo
        validator = QRegularExpressionValidator(regex, mZoneDateTo)
        mZoneDateTo.setValidator(validator)        
        self.sous_layout_radio_date.addWidget(mZoneDateTo,2 ,3 ,1 ,1, Qt.AlignmentFlag.AlignTop )

        #==============================================
        # QGroupBox Case à cocher Millésime
        self.groupBox_Millesime_Date =QtWidgets.QGroupBox()

        #- Case à cocher
        mText        = QtWidgets.QApplication.translate("qgientrepot_ui", "Date Der", None)
        mTextToolTip = QtWidgets.QApplication.translate("qgientrepot_ui", "Enable the display of the latest vintages for each product", None)
        _Listkeys   = [ "typeWidget",           "textWidget", "nameWidget",  "toolTipWidget", "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QCheckBox() , "",        "mZoneChoiceDateDer",   mTextToolTip,   Qt.AlignmentFlag.AlignLeft,    "QCheckBox {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZoneChoiceDateDer   = genereButtonWithDict( dicParamButton )
        self.mZoneChoiceDateDer = mZoneChoiceDateDer
        self.mZoneChoiceDateDer.setChecked(True if self.selfQgeoDistribution.mDateDerniere else False)
        self.sous_layout_radio_date.addWidget(self.mZoneChoiceDateDer, 4, 0)
        self.mZoneChoiceDateDer.stateChanged.connect(lambda : self.on_radio_button_toggled_date(4))        
        # -
        _text = QtWidgets.QApplication.translate("qgidistribution_ui", "Last Vintage" , None)
        mText        = QtWidgets.QApplication.translate("qgidistribution_ui", "Enable the display of the latest vintages for each product" , None)
        _Listkeys   = [ "typeWidget",       "textWidget", "nameWidget", "aligneWidget",  "wordWrap", "styleSheet" ]
        _ListValues = [ QtWidgets.QLabel(), _text,        "label_" ,     Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,  True, "QLabel {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  +"; background-color:" + self.selfQgeoDistribution.labelBackGround  +";}" ]
        dicParamLabelDefault = dict(zip(_Listkeys, _ListValues))
        mLabelValueDefault = genereLabelWithDict( dicParamLabelDefault )
        mLabelValueDefault.setTextFormat(Qt.TextFormat.RichText)
        self.sous_layout_radio_date.addWidget(mLabelValueDefault, 4, 1, 1, 3)

        self.controlDate(1) # Pour initialiser
        
    def on_radio_button_toggled_date(self, _radio) :
        self.controlDate(_radio)
        self.selfQgeoDistribution.buttonSaveFilter.setEnabled(True)
        return

    def controlDate(self, _radio) :
        if _radio == 1 :   # Pas de date
           self.mZoneDateAnnee.setEnabled(False)
           self.mZoneDateFrom.setEnabled(False)
           self.mZoneDateTo.setEnabled(False)
           self.mZoneChoiceDateDer.setEnabled(True)
        elif _radio == 2 : # Année
           self.mZoneDateAnnee.setEnabled(True)
           self.mZoneDateFrom.setEnabled(False)
           self.mZoneDateTo.setEnabled(False)
           self.mZoneChoiceDateDer.setChecked(False)
           self.mZoneChoiceDateDer.setEnabled(False)
        elif _radio == 3 : # Période
           self.mZoneDateAnnee.setEnabled(False)
           self.mZoneDateFrom.setEnabled(True)
           self.mZoneDateTo.setEnabled(True)
           self.mZoneChoiceDateDer.setEnabled(True)
        elif _radio == 4 : # Millesime Simulation
           pass

        gb = self.selfQgeoDistribution.groupBox_QSplitterFiltre_Date           
        _NormalBold  = "bold" if self.ifUneDateSaisie() else "normal"    

        if hasattr(gb, 'isCollapsed') and gb.isCollapsed(): # Fermé
             border_style = "None"
        else:
             border_style = "solid"        
        
        gb.setStyleSheet("QGroupBox {   \
                              margin-top: 10px; \
                              margin-left: 10px; \
                              margin-right: 10px; \
                              margin-down: 10px; \
                              font-family:" + self.selfQgeoDistribution.policeQGroupBox  +" ; \
                              border-style: "  + border_style  + ";      \
                              font-weight : "  + _NormalBold  + ";      \
                              border-width:1px ; \
                              border-color:"  + self.selfQgeoDistribution.colorQTabWidget  + ";      \
                              padding-left:    6px;            \
                              padding-top:     6px;            \
                              padding-right:   6px;            \
                              padding-bottom:  0px;            \
                              } \
                              QGroupBox::title { \
                              subcontrol-origin: margin; \
                              subcontrol-position: top left; \
                              padding-left: 20px; \
                              }")  
        return

    def ifUneDateSaisie(self):
        #Lecture des infos via IHM pour les DATES

        # Si Bouton radio pas de date est coché
        if self.radio_date_aucune.isChecked() :
           # ET si case à cochée MILLESIME n'est pas cochée
           # ALORS pas de date et pas de gras
           if not self.mZoneChoiceDateDer.isChecked() :
              return False
        return True
                
#========================================================     
#========================================================     
# Class pour la création de radio boutons
class RadioButtonWidget(QWidget):
    def __init__(self, _selfQgeoDistribution):
        super().__init__()
        self.selfQgeoDistribution = _selfQgeoDistribution

        self.groupBox_radio = QtWidgets.QGroupBox()
        self.groupBox_radio.setObjectName("groupBox_radio")
        self.groupBox_radio.setStyleSheet("QGroupBox {   \
                              margin-top: 20px; \
                              margin-left: 0px; \
                              margin-right: 0px; \
                              margin-down: 20px; \
                              font-family:" + self.selfQgeoDistribution.policeQGroupBox  +" ; \
                              border-style: solid;    \
                              border-width:1px ; \
                              border-color:"  + self.selfQgeoDistribution.colorQTabWidget  + ";      \
                              font-weight : bold;         \
                              padding-left:    06px;            \
                              padding-top:    10px;            \
                              padding-right:   6px;            \
                              padding-bottom:  6px;            \
                              }")
        self.groupBox_radio.setTitle(QtWidgets.QApplication.translate("qgientrepot_ui", "Destination path for deferred downloads" , None)) #"Chemin de destination pour les téléchargements différés")
        self.layout_radio = QtWidgets.QGridLayout()
        self.layout_radio.setColumnStretch(0, 1)
        self.layout_radio.setColumnStretch(1, 3)
        
        self.groupBox_radio.setLayout(self.layout_radio)

        self.pathDefault = QRadioButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Path défault" , None))
        self.pathDefault.setStyleSheet("QRadioButton {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}")
        self.pathForce   = QRadioButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Defined ForcePath défault" , None))
        self.pathForce.setStyleSheet("QRadioButton {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}")
        # Layout vertical
        self.layout_radio.addWidget(self.pathDefault, 0, 0)
        self.layout_radio.addWidget(self.pathForce, 1, 0)

        #- zone de saisie
        _Listkeys   = [ "typeWidget",          "textWidget",    "nameWidget",       "aligneWidget", "styleSheet" ]
        _ListValues = [ QtWidgets.QLineEdit(), ""          , "mZoneLabelProxygpf",  Qt.AlignmentFlag.AlignLeft,    "QLineEdit {  font-family:" + self.selfQgeoDistribution.policeQGroupBox  + ";}" ]
        dicParamButton = dict(zip(_Listkeys, _ListValues))
        mZonepathForce = genereButtonWithDict( dicParamButton )
        self.mZonepathForce = mZonepathForce
        self.layout_radio.addWidget(mZonepathForce, 1, 1)
        
        self.pathDefault.toggled.connect(lambda : self.on_radio_button_toggled_path(1))
        self.pathForce.toggled.connect(lambda : self.on_radio_button_toggled_path(2))

        if self.selfQgeoDistribution.valueRadioPath == 1 :
           self.pathDefault.setChecked(True)
        elif self.selfQgeoDistribution.valueRadioPath == 2 : 
           self.pathForce.setChecked(True)
           self.mZonepathForce.setText( self.selfQgeoDistribution.valueRadioPathZone )

        self.mZonepathForce.setEnabled(False if self.selfQgeoDistribution.valueRadioPath == 1 else True)
        self.selfQgeoDistribution.valueRadioPath = 1 if self.pathDefault.isChecked() else 2

    def on_radio_button_toggled_path(self, _radio) :
        self.selfQgeoDistribution.valueRadioPath = 1 if self.pathDefault.isChecked() else 2
        self.mZonepathForce.setEnabled(False if self.pathDefault.isChecked() else True)

#========================================================     
#========================================================     
# Boite de dialogue de confirmation 
class BoiteDialogue(QDialog):
    def __init__(self, _selfQgeoDistribution):
        super().__init__()
        self.text = ""
        self.selfQgeoDistribution = _selfQgeoDistribution
        self.initUI()

    def initUI(self):                                    
        #--------------------------
        layout_General = QtWidgets.QGridLayout()
        layout_General.setContentsMargins(0, 0, 0, 0)
        layout_General.setColumnStretch(0, 2)
        layout_General.setColumnStretch(1, 2)
        layout_General.setColumnStretch(2, 1)
        layout_General.setColumnStretch(3, 2)
        layout_General.setColumnStretch(4, 2)
        layout_General.setColumnStretch(5, 3)
        #--------------------------
        layout_General.setRowStretch(0, 1)
        layout_General.setRowStretch(1, 1)
        layout_General.setRowStretch(2, 1)
        layout_General.setRowStretch(3, 1)
        #--------------------------
        self.lineEdit = QtWidgets.QLineEdit()
        
        _text_mZoneQComboSaveLoadFilter = self.selfQgeoDistribution.retourneTexteQcomboBoxSansIconeFavori(self.selfQgeoDistribution.mZoneQComboSaveLoadFilter.currentText())
        if _text_mZoneQComboSaveLoadFilter.strip() != "Aucun" : self.lineEdit.setText( _text_mZoneQComboSaveLoadFilter )
        
        regex     = QRegularExpression("^[A-Za-z0-9_\\s]+$")
        validator = QRegularExpressionValidator(regex)
        self.lineEdit.setValidator(validator)        
        layout_General.addWidget(self.lineEdit, 1, 2, 1, 3)
        #
        okButton = QtWidgets.QPushButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Ok"))
        layout_General.addWidget(okButton, 2, 2)
        okButton.clicked.connect(self.accept)
        #
        cancelButton = QtWidgets.QPushButton(QtWidgets.QApplication.translate("qgientrepot_ui", "Cancel"))
        layout_General.addWidget(cancelButton, 2, 4)
        cancelButton.clicked.connect(self.reject)

        self.setLayout(layout_General)
        return

    def accept(self):
        text = self.lineEdit.text()
        if text.strip() == "Aucun" :
           QMessageBox.warning(self, QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Warning" , None), QtWidgets.QApplication.translate("qgientrepot_ui", "Aucun est un nom réservé."))
           return
        if text.strip():
            self.textNameFilter = text
            self.hide()
        else:
            QMessageBox.warning(self, QtWidgets.QApplication.translate("qgientrepot_ui", "QGIDISTRIBUTION : Warning" , None), QtWidgets.QApplication.translate("qgientrepot_ui", "Please enter a filter Name"))
        return

    def reject(self):
        self.textNameFilter = None
        self.hide()
        return
        
#========================================================     
#========================================================     
# QComboBox personnalisé pour les filtres 
class filtreQComboBox(QComboBox):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.model = QStandardItemModel()
        self.setModel(self.model)
        self.setMinimumWidth(200)  
        self.setMaximumWidth(300)  
        return

    def addItem(self, text, bold=False, italic=False, data=None):
        """
        Ajoute un item avec option pour le mettre en gras.
        :param text: Texte affiché dans la combo.
        :param bold: Booléen, True pour mettre en gras.
        :param data: Données associées à l'item (optionnel).
        """
        item = QStandardItem(text)
        font = self.font()

        if bold:
            font.setBold(True)
        if italic:
            font.setItalic(True)
        item.setFont(font)

        if data is not None:
            item.setData(data)
        self.model.appendRow(item)
        return
        
    def showPopup(self):
        # Calcule de la largeur max
        max_width = 0
        for i in range(self.model.rowCount()):
            item = self.model.item(i)
            font = item.font()
            metrics = QFontMetrics(font)
            width = metrics.horizontalAdvance(item.text())
            max_width = max(max_width, width)        
        padding = 50
          
        # Appliquer au popup de la liste
        self.view().setMinimumWidth(max_width + padding)
        super().showPopup()
        return
                    
