1639 lines
79 KiB
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 += " < "
|
|
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<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);
|
|
}
|
|
|
|
|
|
}
|
|
|