//======================================================================================================================================================================== // CONFIG_CAPTEURS.QML // Ce fichier traite la configuration des capteurs. La page permet notamment de : // - Afficher, pour tous les capteurs déjà configurés (et donc d'accéder à la configuration détaillée de l'un d'eux ; ou sa création) // - Déclencher la recherche de nouveaux capteurs OW // La page est appelée depuis la page PARAMETRES_AVANCES, en cliquant sur "Capteurs" //======================================================================================================================================================================== import QtQuick 2.12 import QtQuick.Controls 2.12 import qt.koriolan.shipheart 1.0 import"fonctions.js" as Fonctions Shipheart_page { id: page_config_capteurs // Mis en forme : readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas readonly property int hauteur_bouton_droit: 80 readonly property double pourcentage_largeur_colonne_gauche: 0.75 readonly property int espace_colonnes_principales: 20 readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 1.0 readonly property int nombre_capteurs_affiches_sur_une_colonne: 8 readonly property int periode_init_raffraichissement_parametres: 1 // En ms readonly property int periode_raffraichissement_parametres: 1000 // En ms /!\ Laisser à 1s afin que le compteur secondes fonctionne correctement... // Affichage : // Modèles : // Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes //=========================================================== // Timer periode raffraichissement parametres : //=========================================================== Timer { id: timer_raffraichissement_parametres interval: periode_init_raffraichissement_parametres triggeredOnStart: false running: true repeat: true onTriggered: { if (interval == periode_init_raffraichissement_parametres) // Premier passage, 1ms après le premier chargement { interval = periode_raffraichissement_parametres; // init_page(); // Fait via StackView.onActivating } else { mise_a_jour_donnees(); } } } //=========================================================== // Lorsque la page est sur le point d'être affichée dans la pile : //=========================================================== StackView.onActivating: { mise_a_jour_donnees(); // Permet que lors du retour sur la page, l'état des différentes variables soit mise à jour avant l'affichage proprement dit. } // Titre de la page : Shipheart_titre_1 {titre:qsTr("Configuration des capteurs"); hauteur: shipheart_hauteur_bandeau_haut} //------------------------------------------------------- // Ecran de gauche (liste des capteurs) : //------------------------------------------------------- Rectangle { id: zone_affichage_gauche x: 0 y: shipheart_hauteur_bandeau_haut; width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: affichage_hauteur_utile color: "transparent" //------------------------------------------------------------------- // Grille pour afficher les capteurs : GridView { id: grille_principale width: parent.width height: parent.height cellWidth: parent.width; cellHeight: height / nombre_capteurs_affiches_sur_une_colonne snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière clip: true // Nécessaire pour que les Delegates s'arretent à l'intérieur de la GridView model: modele_grille_principale delegate: Rectangle { width: grille_principale.cellWidth height: grille_principale.cellHeight color: "transparent" // Ajout d'une ligne de sous-titre avec le nom du famille de capteurs si c'est le premier capteur de la famille : Shipheart_titre_3 {titre:model.nom_famille; hauteur: (affichage_hauteur_utile / nombre_capteurs_affiches_sur_une_colonne); visible: (model.nom_famille !== "")} Rectangle { // c'est le bouton proprement dit... height: parent.height - 10 width:parent.width - 10 color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton border.color: couleur_rouge border.width: (model.etat_systeme === 0) ? 0 : 3 anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter visible: (model.nom_famille === "") // Nom du capteur : Text { anchors.fill: parent horizontalAlignment: Qt.AlignLeft verticalAlignment: Qt.AlignVCenter leftPadding: 20 text: model.nom color: couleur_blanc_casse font.pixelSize: 18 wrapMode: Label.Wrap } // Valeur actuelle du capteur : Text { anchors.fill: parent horizontalAlignment: Qt.AlignRight verticalAlignment: Qt.AlignVCenter rightPadding: 20 text: model.valeur color: couleur_gris_moyen font.pixelSize: 18 } // Triangle bleu indiquant un capteur masqué : Image { id: image_capteur_masque // Affichage du coin inférieur-droit en couleur si le capteur est masqué source: "/images/coin_bas_droite_bleu_koriolan.png" sourceSize.height: 20 anchors { bottom: parent.bottom right: parent.right } visible: model.flag_masque ? true : false } MouseArea{ anchors.fill : parent enabled : !grille_principale.moving // Permet de bloquer le Mousearea pendant le déplacement de la grille onReleased: { // Permet déclencher à la fin d'un clic (court) sans mouvement shipheart_clic(); stackView.push("config_capteur.qml", {"id_capteur": model.id}) } } } } ListModel { id: modele_grille_principale } Label { anchors.fill: parent horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter visible: parent.count === 0 text: qsTr("Aucun capteur n'est encore configuré...") color: couleur_rouge_transparent font.pixelSize: 15 font.bold: true wrapMode: Label.Wrap } } } //------------------------------------------------------- // Ecran Droite : //------------------------------------------------------- Rectangle { id: zone_affichage_droite x: zone_affichage_gauche.width + espace_colonnes_principales y: shipheart_hauteur_bandeau_haut + 5; // Le +5 permet d'aligner le haut du premier bouton de droite avec le haut du premier bouton de la liste de gauche ( width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche)) - (espace_colonnes_principales / 2) height: affichage_hauteur_utile color: "transparent" Column { anchors.fill: parent spacing: 10 //---------------------- // Bouton + : Rectangle { width: parent.width height: hauteur_bouton_droit color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: !clavier.active Text { anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } font.pixelSize: 40 text: qsTr("+") color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); stackView.push("config_capteur.qml"); } } } //---------------------- // Bouton tri : Rectangle { width: parent.width height: hauteur_bouton_droit color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: !clavier.active // && (modele_grille_principale.count > 1) // SDIR #258 Image { id: image_parametres source: "/images/tri.png" sourceSize.height: 25 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); stackView.push("config_ordre_elements.qml", {"table": "TB_Capteurs"}) } } } } } //------------------------------------------------------- // Bandeau bas : //------------------------------------------------------- Row { x: 0 y: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas; width: shipheart_largeur_page; height: shipheart_hauteur_bandeau_bas; padding: 5 spacing: 5 //................................................. // Bouton retour //................................................. Rectangle { id: bandeau_bas_zone_retour width: (parent.width * pourcentage_bandeau_bas_largeur_zone_retour) - parent.leftPadding - (parent.spacing / 2) height: shipheart_hauteur_bandeau_bas - parent.topPadding - parent.bottomPadding; radius: shipheart_rayon_bouton color: shipheart_couleur_fond_bouton Image { source: "/images/icone_retour.png" sourceSize.height: 30 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } } MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille. id: mouse_area_bandeau_bas_zone_retour anchors.fill: parent onClicked: { shipheart_clic(); stackView.pop() } } } } // Note : il est inutile de prévoir un Mousearea pour sortir de l'économiseur sur cette page puisqu'il // est systématiquement bloqué pour toutes les pages lancées depuis 'Paramètres Avancés'. //============================================================================================================= // Init de la page //============================================================================================================= function init_page() { mise_a_jour_donnees(); } //============================================================================================================= // Mise à jour des données //============================================================================================================= function mise_a_jour_donnees() { var req, res; var sous_req, sous_res; var i, j; var nb_capteurs; var prec_famille; // Grille principale (liste des capteurs configurés) : modele_grille_principale.clear(); // Recherche des valeurs en BDD : req = ' SELECT Cle_primaire, '; req += ' Etat_systeme, ' req += ' Nom, '; req += ' Type_entrees, '; req += ' Entrees, '; req += ' ID_Variable, '; req += ' Valeur, '; req += ' Precision_affichage_accueil, '; req += ' Liste_valeurs_textes, '; req += ' Nom_famille, '; req += ' Priorite_affichage_accueil '; req += ' FROM TB_Capteurs, '; req += ' (SELECT Cle_primaire AS Cle_famille, Nom AS Nom_famille, Priorite_affichage AS Priorite_famille '; req += ' FROM TB_Familles WHERE Type_source=' + shipheart_type_source_capteurs + ') AS TB_Familles '; req += ' WHERE ID_Famille=Cle_famille '; req += ' ORDER BY Priorite_famille, ABS(Priorite_affichage_accueil)'; //console.log("Requête = [ " + req + "; ]"); nb_capteurs = bdd.requete(req); prec_famille = ""; // Boucle sur tous les capteurs : for (i = 0; i < nb_capteurs; i ++) { res = bdd.lecture_ligne(); if (!res.isEmpty) { // Récup de toutes les données du capteur (pas forcément super efficace mais BEAUCOUP plus simple à maintenir...) : j = 0; var cle_primaire = Number(res[j++]); var etat_systeme = Number(res[j++]); var nom = res[j++]; var type_entrees = Number(res[j++]); var entrees = res[j++]; var id_variable = Number(res[j++]); var valeur = Number(res[j++]); var precision_affichage = Number(res[j++]); var liste_valeurs_textes = res[j++]; var nom_famille = res[j++]; var priorite_affichage_accueil = Number(res[j++]); // Recherche des infos stockées dans la Variable pointée par ID_Variable : sous_res = bdd.requete_unique('SELECT Unite, Conversion_unite FROM TB_Variables WHERE Cle_primaire="' + id_variable + '" '); j = 0; var symbole_unite = sous_res[j++]; var conversion_unite = Number(sous_res[j++]); var nouvelle_unite; var type_unite; // Traitement des conversions d'unités : switch(conversion_unite) { case shipheart_type_unite_volume: nouvelle_unite = shipheart_unite_volume; symbole_unite = shipheart_unite_volume_symbole; type_unite = shipheart_type_unite_volume; break; case shipheart_type_unite_temperature: nouvelle_unite = shipheart_unite_temperature; symbole_unite = shipheart_unite_temperature_symbole; type_unite = shipheart_type_unite_temperature; break; case shipheart_type_unite_latitude: nouvelle_unite = 0; symbole_unite = ""; type_unite = shipheart_type_unite_latitude; break; case shipheart_type_unite_longitude: nouvelle_unite = 0; symbole_unite = ""; type_unite = shipheart_type_unite_longitude; break; default: nouvelle_unite = 0; type_unite = 0; symbole_unite = sous_res[0]; break; } // Cas spécifiques en fonction du type de capteur : var chaine_valeur = Fonctions.conversion_unites( valeur, nouvelle_unite, "", precision_affichage, type_unite); switch(type_entrees) { //----------------------------------------------------------------- case shipheart_capteur_type_entrees_aux: case shipheart_capteur_type_entrees_calculee_booleen: // Traitement des listes : var chaines_valeurs_textes = liste_valeurs_textes.split(';'); for (let chaine_valeur_texte of chaines_valeurs_textes) { var chaine = chaine_valeur_texte.split('/'); if (chaine.length === 2) // Evite de traiter les cas invalides (notamment, une chaine totalement vide qui arrive ici avec un length de 1...) { if (valeur === Number(chaine [0])) // Si l'une des valeurs de la liste correspond à la valeur actuelle : { chaine_valeur = chaine[1]; // La valeur affichée sera le texte correspondant. break; // Et il est inutile de chercher d'autres valeurs... } } } break; //----------------------------------------------------------------- case shipheart_capteur_type_entrees_level_sensor: break; //----------------------------------------------------------------- case shipheart_capteur_type_entrees_ow: break; //----------------------------------------------------------------- case shipheart_capteur_type_entrees_predefinie: break; //----------------------------------------------------------------- default : break; } // Cas particulier d'un capteur absent : if (etat_systeme !== 0) chaine_valeur = "---" // Ajout de le ligne de famille : if (prec_famille !== nom_famille) { modele_grille_principale.append({ "nom_famille": nom_famille, "id": 0, "etat_systeme": 0, "nom": "", "flag_masque": false, "valeur": ""} ); prec_famille = nom_famille; } // Entrée normale : modele_grille_principale.append({ "nom_famille": "", "id": cle_primaire, "etat_systeme": etat_systeme, "nom": nom, "flag_masque": (priorite_affichage_accueil < 1) ? true : false, "valeur": chaine_valeur + " " + symbole_unite } ); } else break; // Ne devrait pas arriver.... } } }