Files
shipheart-qt/config_capteur_calcule_booleen.qml

1639 lines
79 KiB
QML

//========================================================================================================================================================================
// 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: "+<br />" + 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: "+<br />" + 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: "+<br />" + 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 = "<br /><br />" + qsTr("Le nombre de conditions par capteur est limité à %1.<br /><br />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 = "<br /><br />" + qsTr("Des modifications ont été apportées au capteur<br />mais n'ont pas été enregistrées.<br /><br />Cliquer sur ANNULER pour revenir au menu en cours.<br /><br />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 += " &lt; "
break;
case shipheart_test_inferieur_ou_egal:
libelle += " &le; "
break;
case shipheart_test_egal:
libelle += " = "
break;
case shipheart_test_superieur_ou_egal:
libelle += " &ge; "
break;
case shipheart_test_strictement_superieur:
libelle += " &gt; "
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<modele.count; i ++)
{
if (modele.get(i).valeur === cible) break; // Cas où la valeur cible a été trouvée parmi les valeurs du modèle
}
if (i === modele.count)
{
console.log("Aucune valeur trouvée pour cible = [" + cible + "] du modèle = " + nom_modele);
i = -1; // Cas où la valeur n'a pas été trouvée parmi les valeurs du modèle
}
//else console.log("Valeur trouvée : [" + i + "] pour cible = [" + cible + "] soit texte = [" + modele.get(i).texte + "]");
return(i);
}
}