//======================================================================================================================================================================== // CONFIG_CAPTEUR_CALCULE_BOOLEEN.QML // Ce fichier traite la configuration d'un capteur calculé de type booléen. La page permet notamment de : // - Créer, modifier et supprimer les conditions du capteur calculé. // La page est appelée depuis la page config_capteur.qml //======================================================================================================================================================================== import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQml.Models 2.1 import qt.koriolan.shipheart 1.0 import"fonctions.js" as Fonctions Shipheart_page { id: page_config_capteur_calcule_booleen // Mis en forme : readonly property double pourcentage_largeur_colonne_gauche: 0.75 readonly property int espace_colonnes_principales: 20 readonly property int espace_bouton_selection: 5 readonly property int largeur_bouton_selection: 80 readonly property int largeur_par_niveau: 60 readonly property double pourcentage_hauteur_ligne_haut: 1 readonly property int affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas readonly property int espace_lignes_principales: 20 readonly property int hauteur_ligne_formulaire: 60 readonly property int nombre_conditions_affiches_sur_une_colonne: 12 readonly property int hauteur_bouton_droit: 80 readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 1 // Timings : readonly property int periode_init_raffraichissement_parametres: 1 // En ms readonly property int periode_raffraichissement_parametres: 1000 // En ms readonly property int step_timer_appui_long: 30 // en ms // Boite de dialogue : readonly property int type_boite_information_nombre_maxi_atteint: 0 readonly property int type_boite_information_sortir_sans_enregistrer: 1 // Affichage : property bool flag_init: true // Permet de bloquer certains affichage tant que l'init n'est pas terminée // Données : property int valeur_timer_appui_long: 0 property int id_capteur: 0 property string nom_capteur: "" property string entrees : "" property string entrees_init : "" property int index_condition_en_cours: -1 // Modèles : // Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes //=========================================================== // Signaux : //=========================================================== //---------------------------------------------------------------------------------- // Création du signal destiné à la page 'config_capteur.qml' : signal enregistrer_config_capteur_calcule_booleen(string entrees) //---------------------------------------------------------------------------------- // Connexion au signal de la page 'config_capteur_calcule_booleen_condition.qml' : Connections { target: stackView.currentItem // Pointe sur la page active de StackView (qui sera créée... bientôt, ou pas) ignoreUnknownSignals: true // Permet de ne pas déclencher d'erreur AVANT que la page ne soit créée par un StackView.push() // ----------------------------------------------- // Fonction d'enregistrement des nouvelles data : // ----------------------------------------------- function onEnregistrer_config_capteur_calcule_booleen_condition(flag_new, type_source, id_source, id_variable, test, seuil) { //console.log("Mise à jour de la condition : flag_new="+flag_new+", type_source="+type_source+", id_source="+id_source+", id_variable="+id_variable+", test="+test+", seuil="+seuil); // Cas d'une création de condition : if (flag_new) { index_condition_en_cours ++; grille_conditions_booleennes.model.insert(index_condition_en_cours, { "validite":1 // Necessaire car mis à jour manuellement uniquement // "type_condition": 0, // Pas utilisé sur une condition normale (pas un début ou une fin de groupe) // "operation": 0, // Mis à jour par ordonnancement_modele_conditions() // "display_operation": true, // Mis à jour par ordonnancement_modele_conditions() // "niveau": 0 // Mis à jour par ordonnancement_modele_conditions() }); } // Cas général (création ou modification) : grille_conditions_booleennes.model.set(index_condition_en_cours, { // Mise à jour des propriétés de la ligne qui sont indirectement impactées par le retour : "icone": icone_condition(type_source), "libelle": libelle_condition(type_source, id_source, id_variable, test, seuil), // Mise à jour des propriétés de la ligne modifiées/créées : "type_source": type_source, "id_source": id_source, "id_variable": id_variable, "test": test, "seuil": seuil }); // Mise en ordre de la liste et enregistrement das la BDD : ordonnancement_modele_conditions(); } } //=========================================================== // 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(); maj_valeurs_courantes(); } else { maj_valeurs_courantes(); } } } //=========================================================== // Timer pour gérer les appuis longs : //=========================================================== Timer { id: timer_appui_long interval: step_timer_appui_long triggeredOnStart: false repeat: true onTriggered: { if (valeur_timer_appui_long < shipheart_mouse_press_and_hold_interval_tres_long) valeur_timer_appui_long+= step_timer_appui_long; else // Le fait de ne pas utilise le OnPressandHold permet d'être sût que la sortie se fait au même moment que la fin du comptage (sinon, on peut avoir de petits décalages) { timer_appui_long.running = false; valeur_timer_appui_long = 0; // Suppression : if (mousearea_bouton_suppression.pressed) { shipheart_clic(); if (grille_conditions_booleennes.model.get(index_condition_en_cours).type_condition === shipheart_type_condition_normale) { suppression_condition(index_condition_en_cours); } else suppression_groupe(index_condition_en_cours); } } } } // Titre de la page : Shipheart_titre_1 {titre: qsTr("Equation du capteur calculé [%1]").arg(nom_capteur); hauteur: shipheart_hauteur_bandeau_haut} //------------------------------------------------------- // Ecran Haut - Gauche : //------------------------------------------------------- Rectangle { id: zone_affichage_haut_gauche x: 0 y: shipheart_hauteur_bandeau_haut; width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: (affichage_hauteur_utile * pourcentage_hauteur_ligne_haut) - (espace_lignes_principales / 2); color: "transparent" //========================= // Capteur calculé booléen : //========================= ListView { id: grille_conditions_booleennes anchors.fill: parent clip: true snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière model: ListModel { } delegate: bouton_condition_booleenne displaced: Transition { NumberAnimation{ properties: "x,y" duration: 500 // Vitesse à laquelle se déplacent les boutons lorsqu'on les déplace } } Component { id: bouton_condition_booleenne MouseArea { id: drag_zone_bouton_condition width: grille_conditions_booleennes.width height: hauteur_ligne_formulaire property bool appui_en_cours: false property int derniere_position_y: 0 property bool vers_le_bas: false pressAndHoldInterval: 500; // Temporise avant de passer en moide "déplacement" drag.target: appui_en_cours ? contenu_bouton_condition : undefined drag.axis: Drag.YAxis // On ne se déplace que sur l'axe Y onPressAndHold: { shipheart_clic(); if (model.type_condition === shipheart_type_condition_normale) { index_condition_en_cours = -1; // Si on bouge une condition, on dévalide la condition en cours (qui peut être différente de celle en cours de mouvt). appui_en_cours = true // Le test interdit les boutons d'ouverture et fermetude de groupe d'être draggable } } onReleased: { if (appui_en_cours) { shipheart_clic(); appui_en_cours = false ordonnancement_modele_conditions(); } } onYChanged: { vers_le_bas = derniere_position_y < y; // Détection du sens de déplacement. Utilisé pour toujours afficher un élément de plus en bas (si descente) ou en haut (si montée) derniere_position_y = y; } //------------------------------------- // Bouton principal de la condition : Rectangle { id: contenu_bouton_condition anchors { right: parent.right // Permet d'avoir l'indentation à gauche rightMargin: largeur_bouton_selection + espace_bouton_selection // Permet de se décaler à droite du bouton de sélection verticalCenter: parent.verticalCenter } width: drag_zone_bouton_condition.width - 5 - (model.niveau * largeur_par_niveau) - largeur_bouton_selection - espace_bouton_selection height: drag_zone_bouton_condition.height - 5 radius: shipheart_rayon_bouton color: (model.type_condition === shipheart_type_condition_normale) ? // si c'est une condition "normale" ((index_condition_en_cours !== index) ? shipheart_couleur_fond_bouton : shipheart_couleur_fond_bouton_actif ) : "transparent" // Si c'est une parenthèse, on laisse le bouton transparent opacity: drag_zone_bouton_condition.appui_en_cours ? 0.4 : // Pendant le déplacement, l'opacité du bouton est réduite (model.validite ? 1.0 : 0.6) // Si la condition est dévalidée, on opacifie tout le bouton //----------------------------------------- // Ligne de séparation des parenthèses : Rectangle { id: ligne_masquage anchors { verticalCenter: parent.verticalCenter // Trait centré verticalement ... verticalCenterOffset: (model.type_condition > 0) ? // ... mais décalé pour s'ligner avec le haut de '[' ou le bas de ']' -7 : 9 right: (model.type_condition > 0) ? parent.right : undefined // Permet de laisser la place à gauche au '[' left: (model.type_condition < 0) ? parent.left : undefined // Permet de laisser la place à droite au ']' } width: parent.width - 10 // Le '-10' permet de laisser la place au '[' ou au ']' height: 5 border.width: height / 2 border.color: // couleur_gris_pale model.valeur ? couleur_green_yellow : couleur_rouge color: "transparent" visible: (model.type_condition !== shipheart_type_condition_normale) // Ne s'applique qu'aux lignes de parenthèses (ouvrantes ou fermantes) } //-------------------------------------------------------------------- // Icone de la condition : Image { source: model.icone sourceSize.height: parent.height * 0.8 sourceSize.width: 30 anchors { verticalCenter: parent.verticalCenter left: parent.left leftMargin: 10 } visible: (model.type_condition === shipheart_type_condition_normale) && (model.icone !== "") } //-------------------------------------------------------------------- // Texte du bouton (soit le contenu de la condition, soit '['ou ']') : Text { anchors.fill: parent horizontalAlignment: (model.type_condition < 0) ? Qt.AlignRight : Qt.AlignLeft leftPadding: (model.type_condition === shipheart_type_condition_normale) ? 50 : 0 verticalAlignment: Qt.AlignVCenter textFormat: Text.RichText text: (model.type_condition === shipheart_type_condition_normale) ? //("Index= " + index + " -Niveau= " + model.niveau + " -type= " + model.type_condition + " -Clé= " + model.id) : model.libelle : ((model.type_condition > 0) ? "[" : "]" ) color: (model.type_condition === shipheart_type_condition_normale) ? couleur_blanc_casse : // couleur_gris_pale model.valeur ? couleur_green_yellow : couleur_rouge font.weight: (model.type_condition === shipheart_type_condition_normale) ? Font.Normal : Font.Bold font.pixelSize: (model.type_condition === shipheart_type_condition_normale) ? 18 : 24 } //----------------------------------------- // Ligne de séparation des parenthèses : Rectangle { anchors { verticalCenter: parent.verticalCenter right: parent.right } width: 5 height: parent.height color: model.valeur ? couleur_green_yellow : couleur_rouge visible: (model.type_condition === shipheart_type_condition_normale) && (model.validite) //visible: (model.validite) } Drag.active: drag_zone_bouton_condition.appui_en_cours Drag.source: drag_zone_bouton_condition Drag.hotSpot.x: width / 2 Drag.hotSpot.y: height / 2 states: State{ when: drag_zone_bouton_condition.appui_en_cours ParentChange { target: contenu_bouton_condition parent: grille_conditions_booleennes } AnchorChanges { target: contenu_bouton_condition anchors { horizontalCenter: undefined verticalCenter: undefined } } } } //---------------------------------------------------------------------------------------------- // Bouton de sélection de la ligne (petit bouton à droite de chaque ligne - hors parenthèses) : Rectangle { id: selection_bouton_condition anchors { right: parent.right verticalCenter: parent.verticalCenter } width: largeur_bouton_selection height: drag_zone_bouton_condition.height - 5 radius: shipheart_rayon_bouton color: (index_condition_en_cours !== index) ? shipheart_couleur_fond_bouton : shipheart_couleur_fond_bouton_actif opacity: drag_zone_bouton_condition.appui_en_cours ? 0.0 : 1.0 visible: (model.type_condition >= 0) Image { source: "/images/faux.png" sourceSize.height: parent.height * 0.5 anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } visible: (model.validite === 0) } MouseArea { anchors.fill: parent pressAndHoldInterval: shipheart_mouse_press_and_hold_interval_long onClicked: { shipheart_clic(); if (index_condition_en_cours === index) index_condition_en_cours = -1; else index_condition_en_cours = index; } onPressAndHold: { shipheart_clic(); toggle_validation_condition(index); } } } //------------------------------- // Synthèse de début de ligne : Rectangle { id: bouton_operation visible: model.display_operation anchors { right: contenu_bouton_condition.left rightMargin: 5 verticalCenter: parent.verticalCenter } width: largeur_par_niveau - anchors.rightMargin height: parent.height - 5 radius: shipheart_rayon_bouton color: (model.validite) ? shipheart_couleur_fond_bouton_actif : shipheart_couleur_fond_bouton opacity: drag_zone_bouton_condition.appui_en_cours ? 0.0 : 1.0 Text { anchors.fill: parent horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter text: code_operation(model.operation) color: couleur_blanc_casse font.weight: (model.type_condition === shipheart_type_condition_normale) ? Font.Normal : Font.Bold font.pixelSize: 18 } MouseArea { anchors.fill: parent enabled: parent.visible pressAndHoldInterval: shipheart_mouse_press_and_hold_interval_long onPressAndHold: { shipheart_clic(); toggle_operation_groupe(index); } } } //-------------------------------------------- // Zone de déplacement : DropArea { enabled: (index !== 0) && // On interdit de déplacer une condition avant la première ligne (ouverture du groupe de niveau 0)... (index !== (grille_conditions_booleennes.model.count - 1)) // ... et on interdit de déplacer une condition après la dernière ligne (fermeture du groupe de niveau 0) anchors.fill: parent onEntered: { grille_conditions_booleennes.model.move(drag.source.DelegateModel.itemsIndex, drag_zone_bouton_condition.DelegateModel.itemsIndex, 1) // Ajout d'un élément en partie basse/haute pour avoir toujours une vision sur le prochain élément à "sauter" : if (drag_zone_bouton_condition.vers_le_bas) grille_conditions_booleennes.currentIndex = drag_zone_bouton_condition.DelegateModel.itemsIndex + 1 else grille_conditions_booleennes.currentIndex = drag_zone_bouton_condition.DelegateModel.itemsIndex - 1 } } } } } // Fin de ListView des capteurs calculés booleens } //------------------------------------------------------- // Ecran Droite : //------------------------------------------------------- Rectangle { id: zone_affichage_droite x: zone_affichage_haut_gauche.width + espace_colonnes_principales y: shipheart_hauteur_bandeau_haut; width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche)) - (espace_colonnes_principales / 2) height: (affichage_hauteur_utile * pourcentage_hauteur_ligne_haut) - (espace_lignes_principales / 2); color: "transparent" Column { anchors.fill: parent spacing: 10 //....................................................... // Bouton Enregistrer/créer : //....................................................... Rectangle { width: parent.width height: hauteur_bouton_droit color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (index_condition_en_cours === -1) Text { anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } font.pixelSize: 20 text: qsTr("Enregistrer") color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); enregistrement_entrees(); timer_tempo_reconfiguration.restart(); } } } //....................................................... // Bouton ajouter groupe //....................................................... Rectangle { id: bouton_ajouter_groupe width: parent.width height: hauteur_bouton_droit anchors.horizontalCenter: parent.horizontalCenter color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (index_condition_en_cours !== -1) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 28 // text: "+
" + qsTr("parenthèse") text: "[ + ]" color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); if (grille_conditions_booleennes.model.count > (shipheart_max_nombre_conditions_par_capteur - 2)) // le '-2' tient compte du fait qu'on va crééer 2 conditions avec ce nouveau groupe { boite_information.type = type_boite_information_nombre_maxi_atteint; boite_information.open(); } else ajout_groupe(index_condition_en_cours); } } } //....................................................... // Bouton ajouter condition //....................................................... Rectangle { id: bouton_ajouter_condition width: parent.width height: hauteur_bouton_droit anchors.horizontalCenter: parent.horizontalCenter color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (index_condition_en_cours !== -1) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 28 // text: "+
" + qsTr("condition") text: "+" color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); if (grille_conditions_booleennes.model.count > (shipheart_max_nombre_conditions_par_capteur - 1)) { boite_information.type = type_boite_information_nombre_maxi_atteint; boite_information.open(); } else { stackView.push("config_capteur_calcule_booleen_condition.qml", { "nom_capteur": nom_capteur, "type_source": 0, // Il faut que = 0... "id_source": 0, // ... OU = 0... "id_variable": 0, // ... OU = 0 pour que l'appel soit considéré comme une création. Sinon, ce sera une mise à jour. "test": 0, "seuil": 0 }); } } } } //....................................................... // Bouton modifier condition //....................................................... Rectangle { id: bouton_modifier_condition width: parent.width height: hauteur_bouton_droit anchors.horizontalCenter: parent.horizontalCenter color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (index_condition_en_cours !== -1) && (grille_conditions_booleennes.model.get(index_condition_en_cours).type_condition === shipheart_type_condition_normale) Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 20 // text: "+
" + qsTr("condition") text: "Modifier" color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); stackView.push("config_capteur_calcule_booleen_condition.qml", { "nom_capteur": nom_capteur, "type_source": grille_conditions_booleennes.model.get(index_condition_en_cours).type_source, // Il faut que > 0... "id_source": grille_conditions_booleennes.model.get(index_condition_en_cours).id_source, // ... ET > 0... "id_variable": grille_conditions_booleennes.model.get(index_condition_en_cours).id_variable, // ... ET > 0 pour que l'appel soit considéré comme une mise à jour. Sinon, ce sera une création. "test": grille_conditions_booleennes.model.get(index_condition_en_cours).test, "seuil": grille_conditions_booleennes.model.get(index_condition_en_cours).seuil }); } } } //....................................................... // Bouton de suppression //....................................................... Rectangle { width: parent.width height: hauteur_bouton_droit anchors.horizontalCenter: parent.horizontalCenter color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (index_condition_en_cours !== -1) && (index_condition_en_cours !== 0) Rectangle { // Barre grandissante pour montrer durée d'appui vs tempo nécessaire : width: (valeur_timer_appui_long / shipheart_mouse_press_and_hold_interval_tres_long) * parent.width height: parent.height color: couleur_rouge_transparent radius: shipheart_rayon_bouton visible: mousearea_bouton_suppression.pressed } Text { anchors.fill: parent horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 20 text: qsTr("Supprimer") color: couleur_blanc_casse } MouseArea { id: mousearea_bouton_suppression anchors.fill: parent onPressed: { // Déclenché lors de l'appui inital shipheart_clic(); timer_appui_long.running = true; valeur_timer_appui_long = 0; } onClicked: { // Déclenché si l'appui n'a pas été suffisement long pour avoir un Press&Hold : timer_appui_long.running = false; valeur_timer_appui_long = 0; } onExited: { // Déclenché si le doigt sort de la zone du bouton (sinon, on continue à compter alors qu'on est sorti de la zone et même relaché le doigt !!) timer_appui_long.running = false; valeur_timer_appui_long = 0; } } } //------------------------------------------------------- // Timer de reconfiguration : //------------------------------------------------------- Timer { id: timer_tempo_reconfiguration interval: 250 // Cette tempo n'est utilisée que pour le premier cycle triggeredOnStart: false running: false repeat: true onTriggered: { if (bdd.check_fin_configuration()) { timer_tempo_reconfiguration.stop(); stackView.pop(); // Retour à la page de config des capteurs } else timer_tempo_reconfiguration.interval = 100 // Tempo plus courte pour les lectures suivantes } } } } //------------------------------------------------------- // Bandeau bas : //------------------------------------------------------- Row { x: 0 y: shipheart_hauteur_page - shipheart_hauteur_bandeau_bas; width: shipheart_largeur_page; height: shipheart_hauteur_bandeau_bas; spacing: 5 padding: 5 //................................................. // Bouton retour //................................................. Rectangle { id: bandeau_bas_zone_retour width: (parent.width * pourcentage_bandeau_bas_largeur_zone_retour) - (2 * parent.padding) 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(); recalcul_entrees(); // Mise à jour de la valeur de 'entrees' en fonction de l'état actuel du modèle (on ne fait cette mise à jour que sur demande...) if (entrees !== entrees_init) // Si des modifications non enregistrées ont été faites : { boite_information.type = type_boite_information_sortir_sans_enregistrer; boite_information.open(); } else stackView.pop(); // Sinon, on sort sans rien demander } } } } //------------------------------------------------------- // Boite d'info : // Cette boite est utilisée dans 2 cas : // - si l'on essaie de créer un nouveau groupe alors qu'on est > max-2 // - si l'on essaie de créer une nouvelle condition alors qu'on est > max-1 //------------------------------------------------------- Shipheart_boite_dialogue { id: boite_information imageTitreSource: "/images/attention.png" niveau: 1 onOpened: { switch (type) { case type_boite_information_nombre_maxi_atteint: message = "

" + qsTr("Le nombre de conditions par capteur est limité à %1.

Vous ne pouvez pas ajouter de groupe ou de nouvelle condition avant d'en avoir supprimé préalablement.").arg(shipheart_max_nombre_conditions_par_capteur); boutonAnnuler: false; break; case type_boite_information_sortir_sans_enregistrer: message = "

" + qsTr("Des modifications ont été apportées au capteur
mais n'ont pas été enregistrées.

Cliquer sur ANNULER pour revenir au menu en cours.

Cliquer sur Ok pour sortir sans enregistrer."); boutonAnnuler: true; break; } } onClicked: { switch (type) { case type_boite_information_nombre_maxi_atteint: break; case type_boite_information_sortir_sans_enregistrer: if (bouton === shipheart_boite_dialogue_bouton_1) stackView.pop(); else index_condition_en_cours = -1; // Permet de dévalider la condition en cours s'il y en a une et, ainsi, de faire apparaitre le bouton Enregistrer. } } } //=========================================================== // Busy Indicator : //=========================================================== Shipheart_busy_indicator { id: busy_indicator running: timer_tempo_reconfiguration.running } // 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() { var req, res; var nb; var validite; var type_condition; var type_source; var id_source; var id_variable; var test; var seuil; //console.log("Id du capteur = " + id_capteur); // Note : l'appel à cette page se fait SYSTEMATIQUEMENT avec un id_capteur existant ! // Récupération des données du capteur : req = 'SELECT Nom, Entrees FROM TB_Capteurs WHERE Cle_primaire=' + id_capteur + ' AND Type_entrees=' + shipheart_capteur_type_entrees_calculee_booleen + ' '; //console.log("Requête = [" + req + ']') nb = bdd.requete(req); if (nb !== 1) { console.log("/!\\ La page Config_capteur_calcule_booleen.qml a été appelée avec un ID de capteur non valide (capteur inexistant OU Type_entrees!="+shipheart_capteur_type_entrees_calculee_booleen+")"); StackView.pop(); } // Mise à jour du modèle des conditions de l'équation : grille_conditions_booleennes.model.clear(); res = bdd.lecture_ligne(); // Si on arrive là, on est sûr que 'nb' = 1 if (!res.isEmpty) { nom_capteur = res[0]; entrees = res[1]; entrees_init = entrees; // Recherche des Valeurs/textes existants : var chaines_conditions = entrees.split(';'); // Segmentation des conditions du capteur sur séparateur ';' for (let chaine_condition of chaines_conditions) // [ validite / type_condition / type_source : id_source / id_variable / test / seuil ] { var troncons = chaine_condition.split(':'); // Récupération des 2 tronçons de chaine, de part et d'autre du ':' if (troncons.length === 2) // Evite de traiter les cas invalides (notamment, une chaine totalement vide qui arrive ici avec un length de 1...) { // Traitement du premier tronçon : // [ validite / type_condition / type_source ] var params = troncons[0].split('/'); validite = Number(params[0]); type_condition = Number(params[1]); type_source = Number(params[2]); // Traitement du second tronçon : // [ id_source / id_variable / test / seuil ] params = troncons[1].split('/'); id_source = Number(params[0]); id_variable = Number(params[1]); test = Number(params[2]); seuil = Number(params[3]); //console.log("Condition #" + grille_conditions_booleennes.model.count + " : type_source="+type_source+", id_source="+id_source+", id_variable="+id_variable+", test="+test+", seuil="+seuil); grille_conditions_booleennes.model.append({ "icone": icone_condition(type_source), // NB : si Type_source=0 (ligne de début ou fin de groupe), le retour sera "" "libelle": libelle_condition(type_source, id_source, id_variable, test, seuil), // NB : si Type_source=0 (ligne de début ou fin de groupe), le retour sera "" "validite": validite, "type_condition": type_condition, "operation": 0, "display_operation": true, "niveau": 0, "type_source": type_source, // Ces champs sont nécessaire pour appeler la page de config de ma conditoion si besoin "id_source": id_source, "id_variable": id_variable, "test": test, "seuil": seuil, "valeur": false }); } } } // Remplissage par défaut, si aucune condition n'existe déjà sur ce capteur : if (grille_conditions_booleennes.model.count === 0) { // Ajout de l'ouverture de groupe deplus haut niveau : grille_conditions_booleennes.model.append({ "icone": "", "libelle": "", "validite": 1, "type_condition": shipheart_type_condition_debut_groupe_ou, "operation": 0, "display_operation": true, "niveau": 0, "type_source": 0, // Ne sera pas utilisé sur des début ou fin de groupe mais permet d'être homogène "id_source": 0, "id_variable": 0, "test": 0, "seuil": 0, "valeur": false }); // Ajout de la fermeture de groupe de plus haut niveau : grille_conditions_booleennes.model.append({ "icone": "", "libelle": "", "validite": 1, "type_condition": - shipheart_type_condition_debut_groupe_ou, "operation": 0, "display_operation": true, "niveau": 0, "type_source": 0, // Ne sera pas utilisé sur des début ou fin de groupe mais permet d'être homogène "id_source": 0, "id_variable": 0, "test": 0, "seuil": 0, "valeur": false }); } // Completion du modèle (notamment, opérations) puis enregistrement dans la BDD : ordonnancement_modele_conditions(); flag_init = false; // Indique que l'init est terminée } //============================================================================================================= // Mise à jour du modèle (suite à init ou déplacement par exemple) //============================================================================================================= function ordonnancement_modele_conditions() { var i; var groupes = []; // Array à deux dimensions : [niveau, opération]. Il permet de stocker sous forme de pile (push et pop) les différents couples niveau/opération. // Le principe est qu'on affiche toujours l'opération sur la ligne SAUF : // - si c'est la première ligne (qui ne peut pas être "opérée" avec une ligne précédente...) // - si c'est une ligne de fin de groupe (il n'y a rien à faire sur une fin de groupe...) // - si c'est une ligne de début de groupe (sauf la première) ou ligne normale dont le niveau est != de celui de la ligne précédente. var flag_display_operation; var niveau = 0; // Boucle sur tout le modèle : for (i = 0; i < grille_conditions_booleennes.model.count; i ++) { flag_display_operation = true; // Valeur par défaut pour toutes les lignes //------------------------- // Ouverture de groupe : //------------------------- if (grille_conditions_booleennes.model.get(i).type_condition > 0) { if (i === 0) // Note : Le principe est que la première entrée est toujours du type "début de groupe"... { groupes.push([0, grille_conditions_booleennes.model.get(i).type_condition]); // Tout premier niveau [0] avec [operation = Type_condition de la première ligne] flag_display_operation = false; } niveau = groupes[groupes.length-1][0]; grille_conditions_booleennes.model.set(i, { "operation": groupes[groupes.length-1][1], "display_operation": flag_display_operation, "niveau": niveau }); // Push pour les conditions à venir avec [niveau = niveau+1] et [operation = type_condition d'ouverture] : groupes.push([ (groupes[groupes.length-1][0] + 1), grille_conditions_booleennes.model.get(i).type_condition ]); } //------------------------- // Fermeture de groupe : //------------------------- else if (grille_conditions_booleennes.model.get(i).type_condition < 0) { var type_condition_ouverture = groupes[groupes.length-1][1]; // On utilise l'opération du groupe que l'on va fermer comme valeur de 'Type_condition' de la ligne d'ouverture groupes.pop(); // Permet de revenir au niveau de la condition d'ouverture du groupe niveau = groupes[groupes.length-1][0]; grille_conditions_booleennes.model.set(i, { "type_condition": (- type_condition_ouverture), // Permet de garantir que la ligne de fermeture est bien toujours la valeur négative du type d'ouverture (utile dans le cas d'un toggle d'opération qui ne met à jour que la ligne d'ouverture). "operation": groupes[groupes.length-1][1], "display_operation": false, // Toujours FALSE pour les fin de groupe "niveau": niveau }); } //------------------------- // Condition normale : //------------------------- else { // Calcul du flag de display de l'opération en fonction du niveau précédent et du niveau actuel : if (niveau !== groupes[groupes.length-1][0]) { flag_display_operation = false; niveau = groupes[groupes.length-1][0]; } grille_conditions_booleennes.model.set(i, { "operation": groupes[groupes.length-1][1], "display_operation": flag_display_operation, "niveau": niveau }); } } } //============================================================================================================= // Mise à jour des valeurs courantes de l'équation //============================================================================================================= function maj_valeurs_courantes() { var i; var groupes = []; // Array à deux dimensions : [rang, opération, résultat]. Il permet de stocker sous forme de pile (push et pop) les différents couples rang(de la condition d'ouverture)/opération/résultat var val; // Le principe est : // A chaque '[', on : // - push le rang de la condition d'ouverture du groupe & son opération & le résultat initialisé à une valeur neutre (FALSE pour OU et TRUE pour ET) // A chaque condition normale : // - on évalue la condition (si la condition est dévalidée, la valeur est remplacée par la valeur neutre correspondant à l'opération du niveau) , // - on ajoute ce résultat au résultat du niveau (par '|=' si OU, par '&=' si ET) // A chaque ']', on : // - Si le niveau est > 0 : // - on décrémente le niveau par pop() // - on ajoute le résultat du niveau inférieur (qu'on vient de quitter) au résultat du niveau en cours avec l'opération du niveau en cours. // -Si le niveau est = 0, le résultat du niveau 0 est égal au résultat de l'équation (et on doit être arrivé au bout du modèle...). // Boucle sur tout le modèle : for (i = 0; i < grille_conditions_booleennes.model.count; i ++) { //------------------------- // Ouverture de groupe : //------------------------- if (grille_conditions_booleennes.model.get(i).type_condition > 0) { groupes.push([ i, grille_conditions_booleennes.model.get(i).type_condition, (grille_conditions_booleennes.model.get(i).type_condition === shipheart_operation_condition_ou) ? false : true ]); } //------------------------- // Fermeture de groupe : //------------------------- else if (grille_conditions_booleennes.model.get(i).type_condition < 0) { if (groupes.length > 1) { var res_prec = groupes[groupes.length-1][2]; var rang_ouverture = groupes[groupes.length-1][0]; groupes.pop(); if (groupes[groupes.length-1][1] === shipheart_operation_condition_ou) groupes[groupes.length-1][2] |= res_prec; else groupes[groupes.length-1][2] &= res_prec; // Renseignement de la 'valeur' de la condition d'ouverture du groupe : grille_conditions_booleennes.model.set(rang_ouverture, { "valeur": (res_prec !== 0) }); // Renseignement de la valeur dans la condition de fermeture (condition actuelle) : grille_conditions_booleennes.model.set(i, { "valeur": (res_prec !== 0) }); } else { // Renseignement de la 'valeur' de la condition d'ouverture du groupe : grille_conditions_booleennes.model.set(groupes[groupes.length-1][0], { "valeur": (groupes[groupes.length-1][2] !== 0) }); // Renseignement de la valeur dans la condition de fermeture (condition actuelle) : grille_conditions_booleennes.model.set(i, { "valeur": (groupes[groupes.length-1][2] !== 0) }); } } //------------------------- // Condition normale : //------------------------- else { if (grille_conditions_booleennes.model.get(i).validite) val = test_condition_capteur(i); else val = (groupes[groupes.length-1][1] === shipheart_operation_condition_ou) ? false : true; if (groupes[groupes.length-1][1] === shipheart_operation_condition_ou) groupes[groupes.length-1][2] |= val; else groupes[groupes.length-1][2] &= val; grille_conditions_booleennes.model.set(i, { "valeur": val }); } } } //============================================================================================================= // Toggle de la validite d'une conditions //============================================================================================================= function toggle_validation_condition(index) { var type; var cle; var val; var niveau; var i; type = grille_conditions_booleennes.model.get(index).type_condition; cle = grille_conditions_booleennes.model.get(index).id; val = grille_conditions_booleennes.model.get(index).validite; niveau = grille_conditions_booleennes.model.get(index).niveau; // Calcul de la nouvelle validité : if (val === 0) val = 1; else val = 0; // Mise à jour de l'index en cours dans le modèle : grille_conditions_booleennes.model.set(index, {"validite": val}); // Mise à jour des lignes de niveau inférieur dans le cas où on est sur un début de groupe : // Note : les boutons de fin de groupe ne sont pas traités (et, de toutes façons, ils n'ont pas de bouton...) if (type > 0) { // Boucle depuis la position suivant la ligne en cours : for (i = (index+1); i < grille_conditions_booleennes.model.count; i ++) { if ( (grille_conditions_booleennes.model.get(i).type_condition < 0) // On s'arrête si on trouve une fin de groupe... && (grille_conditions_booleennes.model.get(i).niveau === niveau) ) break; // ... et du même niveau que la ligne en cours (sinon, ça peut être une fin de sous-groupe) grille_conditions_booleennes.model.set(i, {"validite": val}); // Tant qu'on n'est pas arrivé à la fin du groupe, on positionne toutes les lignes avec la nouvelle validité du début de groupe } } } //============================================================================================================= // Insertion d'un groupe de conditions //============================================================================================================= function ajout_groupe(index) { var operation; var niveau; niveau = grille_conditions_booleennes.model.get(index).niveau; operation = grille_conditions_booleennes.model.get(index).operation; // Par défaut, le groupe créé hérite de l'opération de la ligne d'origine // Insertion du début et fin de groupe dans le modèle : grille_conditions_booleennes.model.insert((index+1), { "icone": "", "libelle": "", "validite": 1, "type_condition": operation, // 'operation' correspond à la valeur du début de groupe "operation": operation, "niveau": niveau }); grille_conditions_booleennes.model.insert((index+2), { "icone": "", "libelle": "", "validite": 1, "type_condition": - operation, // Valeur négative pour la fin de groupe "operation": operation, "niveau": niveau }); } //============================================================================================================= // Basculement du type d'opération d'un groupe //============================================================================================================= function toggle_operation_groupe(index) { var i; var type_condition; var niveau; niveau = grille_conditions_booleennes.model.get(index).niveau; if (index === 0) return; // Ne devrait pas arriver car on ne peut changer qu'à partir d'une condition DANS un groupe (et celui de niveau 0 n'a que l'ouverture et la fermetude générale donc pas de contenu...) // Recherche de la tête du groupe : // Soit : la PREMIERE ligne trouvée en remontant le modèle qui est une Ouverture de Groupe // ET dont le Niveau est juste de 1 au dessus de celui de départ. for (i=(index - 1); i >= 0; i --) // Parcours le modèle en remontant, depuis la ligne précédente, jusqu'au début si besoin { if ( (grille_conditions_booleennes.model.get(i).type_condition > 0) // Si début de groupe... && (grille_conditions_booleennes.model.get(i).niveau === (niveau - 1)) ) // ... et niveau -1 par rapport à la ligne de départ, c'est qu'on est arrivé à la tête de groupe. { // Type de condition actuel (donc opération appliquée à tout le groupe) : type_condition = grille_conditions_booleennes.model.get(i).type_condition; // Calcul de la nouvelle opération à appliquer : if (type_condition === shipheart_type_condition_debut_groupe_ou) type_condition = shipheart_type_condition_debut_groupe_et; // else if (type_condition === shipheart_type_condition_debut_groupe_et) type_condition = shipheart_type_condition_debut_groupe_ou_exclusif; else type_condition = shipheart_type_condition_debut_groupe_ou; // Mise à jour du type de condition de la ligne d'ouverture : grille_conditions_booleennes.model.set(i, {"type_condition": type_condition}); break; } } // Mise à jour du rang de toutes les lignes dans le modèle et dans la BDD : ordonnancement_modele_conditions(); } //============================================================================================================= // Recalcule la chaine 'entrees' en focntion de l'état actuel du modèle //============================================================================================================= function recalcul_entrees() { var i; entrees = ""; for (i=0; i < grille_conditions_booleennes.model.count; i ++) { if (entrees !== "") entrees += ";"; entrees += grille_conditions_booleennes.model.get(i).validite; entrees += "/" + grille_conditions_booleennes.model.get(i).type_condition; entrees += "/" + grille_conditions_booleennes.model.get(i).type_source; entrees += ":" + grille_conditions_booleennes.model.get(i).id_source; // Attention au séparateur ':' !!! entrees += "/" + grille_conditions_booleennes.model.get(i).id_variable; entrees += "/" + grille_conditions_booleennes.model.get(i).test; entrees += "/" + grille_conditions_booleennes.model.get(i).seuil; } //console.log("Entrees recalculées = "+entrees); } //============================================================================================================= // Enregistre les conditions du capteur //============================================================================================================= function enregistrement_entrees() { var req; recalcul_entrees(); // Calcul de la chaine à enregistrer à partur de l'état actuel du modèle. req = 'UPDATE TB_Capteurs SET Entrees="' + entrees + '" WHERE Cle_primaire=' + id_capteur + ' '; //console.log("Requête = [ " + req + "; ]") bdd.requete_unique(req); // Miseà jour de l'état mémorisé des entrées : entrees_init = entrees; // Emission du signal vers la page 'config_capteur.qml' : page_config_capteur_calcule_booleen.enregistrer_config_capteur_calcule_booleen(entrees); // Demande de reconfiguration système via la BDD car on a modifié des valeurs de configuration : synchro_bdd(shipheart_type_synchro_config); } //============================================================================================================= // Suppression de la condition en cours //============================================================================================================= function suppression_condition(index) { // Suppression dans le modèle : grille_conditions_booleennes.model.remove(index, 1); // Mise à jour du rang de toutes les lignes dans le modèle et dans la BDD : ordonnancement_modele_conditions(); // Dévalidation de l'index suivant (puisqu'on a supprimé l'actuel) : index_condition_en_cours = -1; } //============================================================================================================= // Suppression d'un groupe : Suppression de la ligne de début de groupe et de la ligne de fermeture, remontée // d'un niveau de toutes les lignes entre les deux, mise à jour du modèle et de la BDD (pour les rangs qui ont // été modifiés du fait des 2 suppressions et pour le type d'opérateur). // Important : le groupe n'est pas forcément vide. Il peut également contenir des sous-groupes qui seront conservés. //============================================================================================================= function suppression_groupe(index) { var i; var niveau; var niveau_suppression; var operation_suppression; niveau_suppression = grille_conditions_booleennes.model.get(index).niveau; operation_suppression = grille_conditions_booleennes.model.get(index).operation; //console.log("Opérateur d'orgine =" + operation_suppression) // Remontée d'un niveau de toutes les conditions entre l'ouverture du groupe et sa fermeture : for (i = (index + 1); i < grille_conditions_booleennes.model.count; i ++) { niveau = grille_conditions_booleennes.model.get(i).niveau; // Ajustement de l'opération de toutes les conditions situées JUSTE en dessous de groupe supprimé : if (niveau === (niveau_suppression + 1)) { grille_conditions_booleennes.model.set(i, {"operation": operation_suppression}); } // Ajustement des niveaux de toutes les conditions situées dans le groupe supprimé : if ((grille_conditions_booleennes.model.get(i).type_condition >= 0) && (niveau !== niveau_suppression)) { // Mise à jour des rangs du modèle : grille_conditions_booleennes.model.set(i, {"niveau": (niveau - 1)}); } else // Ligne de fermeture du groupe : { // Suppression dans le modèle de la fermeture du groupe : grille_conditions_booleennes.model.remove(i, 1); break; } } // Suppression dans le modèle de l'ouverture du groupe : grille_conditions_booleennes.model.remove(index, 1); // Mise à jour du rang de toutes les lignes dans le modèle et dans la BDD : ordonnancement_modele_conditions(); // Dévalidation de l'index suivant (puisqu'on a supprimé l'actuel) : index_condition_en_cours = -1; } //============================================================================================================= // Défini le nom du fichier à utiliser comme icone de la condition //============================================================================================================= function icone_condition(type_source) { var image; // Sélection du fichier en fonction du Type de source : switch(type_source) { case shipheart_source_mesure_circuit: image = "/images/icone_consommation_electrique.png"; break; case shipheart_source_mesure_capteur: image = "/images/icone_auxiliaires.png"; break; case shipheart_source_mesure_reservoir: image = "/images/reservoir_eau.png"; break; case shipheart_source_mesure_batterie: image = "/images/batterie_moyen.png"; break; default: image = ""; break; } return(image); } //============================================================================================================= // Constitution du libellé de la condition //============================================================================================================= function libelle_condition(type_source, id_source, id_variable, test, seuil) { var req, res; var i; var nb; var table; var libelle; // Sélection de la table à utiliser en focntion du Type de source : switch(type_source) { case shipheart_source_mesure_circuit: table = "TB_Circuits"; break; case shipheart_source_mesure_capteur: table = "TB_Capteurs"; break; case shipheart_source_mesure_reservoir: table = "TB_Reservoirs"; break; case shipheart_source_mesure_batterie: table = "TB_Batteries"; break; default: table = ""; break; } // Génération du libellé : if (table !== "") { // Chargement des infos de la BDD : req = 'SELECT Nom'; req += ', Code_variable '; req += ', Libelle_unite '; if (table === "TB_Capteurs") req += ', Type_entrees '; req += 'FROM ' + table + ', '; req += ' (SELECT Cle_primaire, Code AS Code_variable, Unite AS Libelle_unite FROM TB_Variables) AS TB_Variables '; req += ' WHERE ' + table + '.Cle_primaire=' + id_source + ' AND TB_Variables.Cle_primaire=' + id_variable+ ' '; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); // Nom de l'équipement : libelle = " " + res[0]; // Attention, sans '+=' car premier accès... // Nom de la variable : if ((type_source === shipheart_source_mesure_circuit) // On ne mentionne le nom de la variable que pour un circuit... || (type_source === shipheart_source_mesure_batterie)) // ... ou une batterie { libelle += " - " + Fonctions.nom_variable(res[1]); // Nom de la variable } // Cas particulier des capteurs binaires : if ((type_source === shipheart_source_mesure_capteur) && ((Number(res[3]) == shipheart_capteur_type_entrees_aux) || (Number(res[3]) == shipheart_capteur_type_entrees_calculee_booleen)) ) { if (test === shipheart_test_strictement_superieur) libelle += qsTr(" est actif"); else libelle += qsTr(" est inactif"); } else { // Test : switch(test) { case shipheart_test_non_defini: default: libelle += " ? " break; case shipheart_test_strictement_inferieur: libelle += " < " break; case shipheart_test_inferieur_ou_egal: libelle += " ≤ " break; case shipheart_test_egal: libelle += " = " break; case shipheart_test_superieur_ou_egal: libelle += " ≥ " break; case shipheart_test_strictement_superieur: libelle += " > " break; } libelle += seuil; // Valeur de seuil libelle += " " + res[2]; // Unité } } else libelle = ""; return(libelle); } //============================================================================================================= // Recherche du code d'une opération //============================================================================================================= function code_operation(operation) { switch (operation) { case shipheart_operation_condition_non_definie: return("?"); // Pas besoin de break; après le return. case shipheart_operation_condition_ou: return(qsTr("Ou")); case shipheart_operation_condition_et: return(qsTr("Et")); case shipheart_operation_condition_ou_exclusif: return(qsTr("X-Ou")); case shipheart_operation_condition_plus: return("+"); case shipheart_operation_condition_moins: return("-"); case shipheart_operation_condition_multiplie: return("x"); case shipheart_operation_condition_divise: return("/"); } } //============================================================================================================= // Recherche du résultat d'une condition //============================================================================================================= function test_condition_capteur(no) { var type_source; var id_source; var id_variable; var code_variable; var test; var seuil; var valeur; var req, res; var champ; // Récupération des données de la condition : type_source = grille_conditions_booleennes.model.get(no).type_source; id_source = grille_conditions_booleennes.model.get(no).id_source; id_variable = grille_conditions_booleennes.model.get(no).id_variable; test = grille_conditions_booleennes.model.get(no).test; seuil = grille_conditions_booleennes.model.get(no).seuil; //=================================================== // Récupération de la valeur de la source à tester : //=================================================== // Récupération du code de la variable associée à la condition : req = ' SELECT Code FROM TB_Variables WHERE Cle_primaire=' + id_variable + ' '; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); code_variable = res[0]; // Génération de la requête en fonction du type de source et de la variable concernée : switch(type_source) { //------------------------------------- case shipheart_source_mesure_circuit: switch(code_variable) { case shipheart_circuit_consigne: { champ = "Consigne"; break;} case shipheart_circuit_tension: { champ = "Tension"; break;} case shipheart_circuit_courant: { champ = "Intensite"; break;} case shipheart_circuit_frequence: { champ = "Frequence"; break;} case shipheart_circuit_puissance: { champ = "(Tension * Intensite) AS Puissance"; break;} // case shipheart_circuit_energie: { champ = ""; break;} case shipheart_circuit_tension_secteur: { champ = "Tension"; break;} } // Requete de lecture de la valeur à analyser : req = "SELECT " + champ + " FROM TB_Circuits WHERE Cle_primaire=" + id_source+ " "; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); valeur = res[0]; break; //------------------------------------- case shipheart_source_mesure_capteur: // Requete de lecture de la valeur à analyser : req = "SELECT Valeur FROM TB_Capteurs WHERE Cle_primaire=" + id_source+ " "; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); valeur = res[0]; break; //------------------------------------- case shipheart_source_mesure_reservoir: // Requete de lecture de la valeur à analyser : req = "SELECT Niveau FROM TB_Reservoirs WHERE Cle_primaire=" + id_source+ " "; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); valeur = res[0]; break; //------------------------------------- case shipheart_source_mesure_batterie: switch(code_variable) { case shipheart_batterie_temperature: { champ = "Temperature"; break;} case shipheart_batterie_tension: { champ = "Tension"; break;} case shipheart_batterie_courant_differentiel: { champ = "Courant_differentiel"; break;} case shipheart_batterie_courant_charge: { champ = "Courant_charge"; break;} case shipheart_batterie_courant_decharge: { champ = "Courant_decharge"; break;} case shipheart_batterie_soh: { champ = "Soh"; break;} case shipheart_batterie_soc: { champ = "Soc"; break;} case shipheart_batterie_autonomie: { champ = "Autonomie"; break;} case shipheart_batterie_puissance: { champ = "(Tension * Courant_decharge) AS Puissance"; break;} // case shipheart_batterie_energie: { champ = ""; break;} } // Requete de lecture de la valeur à analyser : req = "SELECT " + champ + " FROM TB_Batteries WHERE Cle_primaire=" + id_source+ " "; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); valeur = res[0]; break; //------------------------------------- default: valeur = 0; break; } //======================== // Test proprement dit : //======================== switch(test) { case shipheart_test_non_defini: default: return(false); case shipheart_test_strictement_inferieur: return(valeur < seuil); case shipheart_test_inferieur_ou_egal: return(valeur <= seuil); case shipheart_test_egal: return(valeur === seuil); case shipheart_test_superieur_ou_egal: return(valeur >= seuil); case shipheart_test_strictement_superieur: return(valeur > seuil); } } //============================================================================================================= // Recherche de l'index d'une certaine valeur dans un modele //============================================================================================================= function recherche_index_valeur_modele(cible, modele, nom_modele) { var i; for (i=0; i