Files

983 lines
46 KiB
QML

//========================================================================================================================================================================
// RESERVOIR.QML
// Ce fichier traite l'affichage des détails d'un réservoir. La page affiche notamment :
// - le niveau actuel sous forme graphique (avec référence aux seuils haut et bas)
// - la contenance actuelle (dans l'unit en cours) et son niveau relatif
// - la liste des derniers événements,
// - la courbe historique de niveau
// La page est appelée depuis la page HOME, en cliquant sur la zone d'information du réservoir.
//========================================================================================================================================================================
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtCharts 2.3
import qt.koriolan.shipheart 1.0
import"fonctions.js" as Fonctions
import"fonctions_date_heure.js" as Fonctions_date_heure
Shipheart_page {
id: page_reservoir
// Mis en forme :
readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas - (2 * espace_lignes_principales)
readonly property double pourcentage_hauteur_ligne_haut: 0.6
readonly property double pourcentage_hauteur_ligne_erreur: 0.3 // Part de 'pourcentage_hauteur_ligne_haut'
readonly property double espace_lignes_principales: 20
readonly property double pourcentage_largeur_colonne_gauche: 0.5
readonly property double pourcentage_largeur_graphique: 0.85
readonly property double espace_colonnes_principales: 20
readonly property double espace_colonnes_secondaires: 50
readonly property int nombre_lignes_historique_visibles: 8
readonly property int nombre_lignes_historique_par_page: 30
readonly property double nb_boutons_periode: 4
readonly property int periode_init_raffraichissement_parametres: 20 // En ms ATtention : The Timer type is synchronized with the animation timer. Since the animation timer is usually set to 60fps, the resolution of Timer will be at best 16ms.
readonly property int periode_raffraichissement_parametres: 1000 // En ms
readonly property int periode_init_raffraichissement_graphiques: 20 // En ms
readonly property int periode_raffraichissement_graphiques: (15 * 1000) // en ms
// Affichage :
property bool courbe_flag_vide: false // Flag indiquant s'il y a des données à afficher ou pas
property int courbe_nombre_principal_graduations_axe_x: 13
property int courbe_nombre_zoom_1_graduations_axe_x: 8
property int courbe_nombre_graduations_axe_y: 5
property string courbe_format_principal_axe_x: "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
property string courbe_format_zoom_1_axe_x: "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
property int periode_analyse: 0
property bool flag_zoom_en_cours: false
property real zoomx_en_cours: 1
property date xMin_date
property date xMax_date
property real yMin_valeur: 0
property real yMax_valeur: 1
property int precision_affichage_axe_y_courbe: 1
property string symbole_unite: "--"
// Historique :
property string date_premiere_entree_historique: "" // Contient une chaine (format BDD) représentant la date/heure de l'entrée historique la plus ancienne. Permet de recharger de plus anciennes lors d'un MORE...
property string date_derniere_entree_historique: "" // Contient une chaine (format BDD) représentant la date/heure de l'entrée historique la plus récente. Permet de ne recharger que les nouvelles...
property bool flag_journal_full: false // est positionné à vrai quand il n'y a plus d'enregistrements supplémentaires disponibles pour ce filtre
// Données :
property bool flag_init: true // Permet de bloquer certains affichage tant que l'init n'est pas terminée
property int id_reservoir: 0
property int id_variable: 0
property int etat_systeme: 0
property int etat: 0
property string nom_reservoir: "---"
property double niveau: 0
property double niveau_seuil_bas: 75
property double niveau_seuil_haut: 25
property int capacite: 0
property int id_famille: 1 // Eau par défaut
property int precision_affichage_mesures: 0
property int type_periode_graphique: 1
property string texte_alerte: ""
property int nb_events: -1 // -1: aucun event n'est lié à ce capteur, 0: au moins 1 event est lié à ce capteur mais aucun n'a Etat_test>0, 1: au moins un event lié et au moins un Etat_test=1
// Modèles :
// Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes
//===========================================================
// Timer periode raffraichissement parametres du circuit :
//===========================================================
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;
busy_indicator.running = true;
init_page();
}
else
{
mise_a_jour_valeurs_instantanees();
}
}
}
//===========================================================
// Timer periode raffraichissement graphiques :
//===========================================================
Timer {
id: timer_raffraichissement_graphiques
interval: periode_raffraichissement_graphiques
triggeredOnStart: false
running: true
repeat: true
onTriggered: {
if (interval === periode_init_raffraichissement_graphiques) interval = periode_raffraichissement_graphiques;
if (!flag_init) // La gestion du premier calcul des courbes est géré directement par 'init()' car le séquençage des 2 timers au démarrage n'est pas garanti !!
{
if (!flag_zoom_en_cours) // On ne met pas à jour les courbes si on est en train de zoomer
{
mise_a_jour_courbes();
}
}
}
}
// Titre de la page :
Shipheart_titre_1 {titre:nom_reservoir; 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;
color: "transparent"
visible: (etat_systeme === 0)
//-------------------------------------------------------
// Valeur si unité :
Rectangle {
anchors.fill: parent
color: "transparent"
visible: (symbole_unite !== "")
Text {
id: valeur_actuelle
anchors {
verticalCenter: parent.verticalCenter
verticalCenterOffset: -80
horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: -20
}
text: Fonctions.conversion_volume((capacite * niveau / 100), shipheart_unite_volume, "", precision_affichage_mesures);
font.family: "Montserrat"
font.pixelSize: 120
font.weight: Font.Bold
// color: (nb_events > 0) ? couleur_rouge : couleur_blanc_casse
color: couleur_blanc_casse
}
//-------------------------------------------------------
// Unite :
Text {
anchors {
baseline: valeur_actuelle.baseline
left: valeur_actuelle.right
leftMargin: 10
}
text: shipheart_unite_volume_symbole
font.pixelSize: 20
color: couleur_blanc_casse
}
//-------------------------------------------------------
// Valeur en % de remplissage :
Text {
id: valeur_relative
anchors {
verticalCenter: parent.verticalCenter
verticalCenterOffset: 50
horizontalCenter: parent.horizontalCenter
horizontalCenterOffset: -10
}
text: qsTr("[ %1 % ]").arg(niveau.toFixed(0))
font.family: "Montserrat"
font.pixelSize: 50
color: couleur_blanc_casse
}
}
//-----------------------------------
// Alarmes :
Rectangle {
id: zone_alarmes
width: parent.width
height: 50
color: shipheart_couleur_fond_bouton
radius: shipheart_rayon_bouton
anchors {
left: parent.left
bottom: parent.bottom
}
visible: nb_events >= 0
Image {
source: (nb_events === 0) ? "/images/cloche_sombre.png" : "/images/cloche_rouge.png"
sourceSize.height: 20
anchors {
verticalCenter: zone_alarmes.verticalCenter
horizontalCenter: zone_alarmes.horizontalCenter
}
}
//-----------------------------------
// Zone de clics dédiée aux alarmes :
MouseArea{
anchors.fill: zone_alarmes
onClicked: {
shipheart_clic();
boite_dialogue_liste_alarmes.open();
}
}
}
Component.onCompleted: {
mise_a_jour_valeurs_instantanees();
}
}
//-------------------------------------------------------
// Ecran haut - droite :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_haut_droite
x: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) + (espace_colonnes_principales / 2);
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 * pourcentage_hauteur_ligne_erreur) - (espace_lignes_principales / 2)
color: "transparent"
border.width: 3
border.color: couleur_rouge
radius: shipheart_rayon_bouton
visible: (etat_systeme === 0) && (texte_alerte !== "")
Image {
id: picto_alerte
source: "/images/ak14.png"
sourceSize.height: 30;
anchors {
left: parent.left
leftMargin: 20
verticalCenter: parent.verticalCenter
}
}
Text { // Affiche parfaitement 1, 2 ou 3 lignes de texte. A partir de 4 et 5, ça mort sur le contour du rectangle mais c'est encore lisible.
width: parent.width - picto_alerte.width - picto_alerte.anchors.leftMargin - anchors.leftMargin;
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
leftPadding: 10 // Dégage le pictogramme sur la gauche
rightPadding: 10 // Evite de se caler sur le bord droit du rectangle
text: texte_alerte;
anchors {
left: picto_alerte.right
verticalCenter: parent.verticalCenter
}
font.pixelSize: 16
color: couleur_blanc_casse
}
}
//-------------------------------------------------------
// Ecran milieu - droite :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_milieu_droite
x: zone_affichage_haut_droite.x
y: zone_affichage_haut_droite.y + zone_affichage_haut_droite.height + espace_lignes_principales
width: zone_affichage_haut_droite.width
height: (affichage_hauteur_utile * pourcentage_hauteur_ligne_haut * (1 - pourcentage_hauteur_ligne_erreur)) - (espace_lignes_principales / 2)
color: "transparent"
visible: (etat_systeme === 0)
Rectangle {
id: visuel_niveau
width: parent.width * 0.6
height: parent.height
color: "transparent"
border.width: 3
border.color: couleur_gris_moyen
radius: 30
anchors {
horizontalCenter: parent.horizontalCenter
}
Rectangle {
width: parent.width - (2 * parent.border.width)
height: (parent.height - (2 * parent.border.width)) * niveau / 100
radius: 2
color: couleur_bleu_koriolan_transparent
anchors {
bottom: parent.bottom
bottomMargin: parent.border.width
horizontalCenter: parent.horizontalCenter
}
}
Rectangle { // Rectangle permettant de centrer tout le texte de capacité (valeur et unité)
width: texte_capacite_reservoir.paintedWidth + texte_unite_capacite_reservoir.paintedWidth + texte_unite_capacite_reservoir.anchors.leftMargin
height: texte_capacite_reservoir.paintedHeight
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
color: "transparent"
Text {
id: texte_capacite_reservoir
text: Fonctions.conversion_volume(capacite, shipheart_unite_volume, "", 0);
font.pixelSize: 50
font.bold: true
color: couleur_gris_tres_pale_transparent
}
Text {
id: texte_unite_capacite_reservoir
text: shipheart_unite_volume_symbole
anchors {
left: texte_capacite_reservoir.right
leftMargin: 20
baseline: texte_capacite_reservoir.baseline
}
font.pixelSize: 20
font.bold: true
color: couleur_gris_tres_pale_transparent
}
}
/* Rectangle { // Ligne de niveau haut
width: parent.width * 0.9
height: 1
anchors {
bottom: parent.bottom
bottomMargin: (parent.height - (2 * parent.border.width)) * niveau_seuil_haut / 100
horizontalCenter: parent.horizontalCenter
}
color: couleur_vert_transparent
}
Rectangle { // Ligne de niveau bas
width: parent.width * 0.9
height: 1
anchors {
bottom: parent.bottom
bottomMargin: (parent.height - (2 * parent.border.width)) * niveau_seuil_bas / 100
horizontalCenter: parent.horizontalCenter
}
color: couleur_rouge_transparent
}
*/
}
}
//-------------------------------------------------------
// Ecran bas :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_bas
x: 0
y: zone_affichage_haut_gauche.y + zone_affichage_haut_gauche.height + espace_lignes_principales;
width: shipheart_largeur_page;
height: affichage_hauteur_utile * (1 - pourcentage_hauteur_ligne_haut)
color: "transparent"
visible: (etat_systeme === 0)
//========================
// Graphique :
ChartView {
id: graphique
antialiasing: true
anchors {
top: parent.top;
left:parent.left;
bottom:parent.bottom;
margins: -15 // Un peu compliqué mais permet, avec la ligne suivante, ...
}
margins { right: 0; bottom: 0; left: 5; top: 0 } // ... d'annuler les marges.
width: parent.width * pourcentage_largeur_graphique;
backgroundColor: "transparent"
// animationDuration: 10000
// animationOptions: ChartView.SeriesAnimations
legend {visible: false }
visible: (id_variable !== 0)
DateTimeAxis {
id: axisX
format: (zoomx_en_cours > 0.5) ? courbe_format_principal_axe_x : courbe_format_zoom_1_axe_x
min: xMin_date
max: xMax_date
tickCount: (zoomx_en_cours > 0.5) ? courbe_nombre_principal_graduations_axe_x : courbe_nombre_zoom_1_graduations_axe_x
//labelsColor: (!flag_zoom_en_cours) ? couleur_blanc_casse : couleur_green_yellow
labelsColor: couleur_blanc_casse
labelsFont: Qt.font({pointSize: 10})
color: couleur_gris_moyen
shadesColor: courbes_couleur_shades_fond
shadesVisible: true
gridVisible: false
// gridLineColor: "green"
}
ValueAxis {
id: axisY1
min: yMin_valeur
max: yMax_valeur
tickCount: courbe_nombre_graduations_axe_y
labelFormat: "%." + precision_affichage_axe_y_courbe + "f"
// labelsColor: (!flag_zoom_en_cours) ? couleur_blanc_casse : couleur_green_yellow
labelsColor: couleur_blanc_casse
labelsFont:Qt.font({pointSize: 10})
color: couleur_gris_moyen
// shadesColor: courbes_couleur_shades_fond
shadesVisible: false
gridVisible: true
gridLineColor: couleur_gris_tres_fonce
titleText: "<font color='" + couleur_blanc_casse + "'>" + symbole_unite + "</font>"
titleFont {
pointSize: 20
bold: true
}
}
LineSeries { // Utilisé si on veut renforcer la courbe mais sans avoir tout le tour de l'area renfocée (qui se fait dans AreaSeries pour le coup)
id: courbe_principale
name: "Courbe principale"
axisX: axisX
axisY: axisY1
capStyle: Qt.RoundCap
style: Qt.SolidLine
width: courbes_epaisseur_bordure
color: shipheart_couleur_bordure_courbes
}
Text {
id: texte_courbe_vide
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
text: qsTr("Aucune donnée n'est disponible pour cette période")
font.pixelSize: 20
font.weight: Font.Bold
color: "red"
visible: courbe_flag_vide ? true : false;
}
//---------------------------------
// Rectangle de sélection de zoom :
Rectangle {
id: rectangle_zoom
x: pinch_area.zoom_x
y: pinch_area.zoom_y
width: pinch_area.zoom_w
height: pinch_area.zoom_h
radius: shipheart_rayon_zoom
color: couleur_bleu_koriolan_tres_transparent
}
//---------------------------------
// Zone de pinch :
PinchArea{
id: pinch_area
// Propriété de la eone de zoom pendant toute la phase de sélection :
property real zoom_x: 0
property real zoom_y: 0
property real zoom_w: 0
property real zoom_h: 0
anchors.fill: parent // Calé sur 'graphique'.
// Attention : la zone de traçage à l'intérieur de 'graphique' est 'graphique.plotArea'.
// Toutes les coordonnées sont données dans 'graphique' mais on limite à l'usage les coordonnées intérieures à 'graphique.plotArea'.
//-----------------------------------------------
// Mis à jour en cours de déplacement du pinch :
onPinchUpdated: {
if ((pinch.point1.x !== pinch.point2.x) || // Il arrive, en fin de pinch, que les 2 points renvoyés soient les mêmes...
(pinch.point1.y !== pinch.point2.y)) // ... Il faut éviter de les traiter sous peine de ramener W et H à 0.
{
// Récupération des données en s'affranchissant de la position des 2 points :
zoom_x = Math.min(pinch.point1.x, pinch.point2.x)
zoom_y = Math.min(pinch.point1.y, pinch.point2.y)
zoom_w = Math.abs(pinch.point1.x - pinch.point2.x)
zoom_h = Math.abs(pinch.point1.y - pinch.point2.y)
// Limitation de 'x' et 'w' à la largeur de la zone de traçage :
if (zoom_x < graphique.plotArea.x) zoom_x = graphique.plotArea.x;
if (zoom_x > (graphique.plotArea.x + graphique.plotArea.width)) zoom_x = graphique.plotArea.x + graphique.plotArea.width
if ((zoom_x + zoom_w) > (graphique.plotArea.x + graphique.plotArea.width)) zoom_w = (graphique.plotArea.x + graphique.plotArea.width) - zoom_x;
// Limitation de 'y' et 'h' à la hauteur de la zone de traçage :
if (zoom_y < graphique.plotArea.y) zoom_y = graphique.plotArea.y;
if (zoom_y > (graphique.plotArea.y + graphique.plotArea.height)) zoom_y = graphique.plotArea.y + graphique.plotArea.height
if ((zoom_y + zoom_h) > (graphique.plotArea.y + graphique.plotArea.height)) zoom_h = (graphique.plotArea.y + graphique.plotArea.height) - zoom_y;
}
}
//-------------------------
// Valeur de fin du pinch :
onPinchFinished: {
// Préparation du zoom sur le rectangle sélectionné :
var r = Qt.rect(zoom_x, zoom_y, zoom_w, zoom_h);
graphique.zoomIn(r);
flag_zoom_en_cours = true;
zoomx_en_cours *= (zoom_w / graphique.plotArea.width);
// Effacement du rectangle :
zoom_x = 0
zoom_y = 0
zoom_w = 0
zoom_h = 0
}
// Déplacement de la courbe :
MouseArea{
anchors.fill: parent
drag.target: dragTarget
drag.axis: Drag.XAndYAxis
onClicked: {
shipheart_clic();
if (!flag_zoom_en_cours) // Si le zoom est en cours, il ne faut PAS lancer le raffraichissement...!
{
busy_indicator.running = true;
timer_raffraichissement_graphiques.interval = periode_init_raffraichissement_graphiques; // Cela permet de lancer le "busy_indicator' avant de faire la mise à jour de la courbe
}
}
onPressAndHold: {
raz_zoom();
}
}
Item {
id: dragTarget
property real oldX : x // Permet de mémoriser la dernière position d'arrivée
property real oldY : y
property real cumulX : 0 // Permet de revenir à un déclage nul lorsque nécessaire
property real cumulY : 0
onXChanged: {
graphique.scrollLeft( x - oldX );
cumulX -= (x - oldX); // Le signe '-' permettra ensuite de revenir à le position de départ
oldX = x;
}
onYChanged: {
graphique.scrollUp( y - oldY );
cumulY -= (y - oldY); // Le signe '-' permettra ensuite de revenir à le position de départ
oldY = y;
}
}
}
}
//========================
// Busy Indicator :
Shipheart_busy_indicator {
id: busy_indicator
}
//========================
// Boutons de pếriode :
ColumnLayout {
spacing: 10
anchors {
top: parent.top;
right:parent.right;
rightMargin: 5;
bottom:parent.bottom;
}
width: (parent.width * (1 - pourcentage_largeur_graphique)) - anchors.rightMargin;
ListModel {
id: modele_periodes_graphique
}
Repeater {
model: modele_periodes_graphique
Rectangle {
color: "transparent"
Layout.preferredWidth: parent.width;
Layout.preferredHeight: (parent.height / nb_boutons_periode) - parent.spacing;
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
text: model.libelle
font.pixelSize: 18
font.weight: (model.index === periode_analyse) ? Font.Bold : Font.Normal
color: couleur_blanc_casse
}
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.
anchors.fill: parent
onClicked: {
shipheart_clic();
raz_zoom(); // Au-delà de la fonctionnalité, c'est obligatoire sinon, le raffraichissement des la courbe est bloqué au niveau du timer
periode_analyse = model.index;
busy_indicator.running = true;
timer_raffraichissement_graphiques.interval = periode_init_raffraichissement_graphiques; // Cela permet de lancer le "busy_indicator' avant de faire la mise à jour de la courbe
}
}
// Fond du bouton :
Rectangle { // Permet d'avoir un fond et de pouvoir régler son opacité sans changer celle des textes au-dessus
width: parent.width
height: parent.height
color: (model.index === periode_analyse) ? (flag_zoom_en_cours ? couleur_green_yellow_transparent : shipheart_couleur_fond_bouton_actif) : shipheart_couleur_fond_bouton;
opacity: 0.5
radius: shipheart_rayon_bouton
}
}
}
}
}
//-------------------------------------------------------
// Message d'erreur si réservoir Absent
// (le module sur lequel le réservoir est configuré n'est pas physiquement présent)
//-------------------------------------------------------
Rectangle {
id: zone_message_absence
x: 0
y: shipheart_hauteur_bandeau_haut + espace_lignes_principales
width: shipheart_largeur_page
height: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas - espace_lignes_principales
color: "transparent"
visible: (etat_systeme !== 0)
Rectangle { // Rectangle entouré de rouge
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -50
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height: parent.height / 2
radius: shipheart_rayon_bouton
border.width: 3
border.color: couleur_rouge
color: couleur_rouge_transparent
Image { // Pictogramme DANGER
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: -100
anchors.horizontalCenter: parent.horizontalCenter
source: "/images/ak14.png"
sourceSize.height: 70;
}
Text { // Texte d'info
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 50
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
height : parent.height / 2
horizontalAlignment: Qt.AlignCenter
verticalAlignment: Qt.AlignVCenter
padding: 50
text: qsTr("Le module assurant la supervision de ce réservoir n'est pas accessible !<br /><br />Si des ajouts/suppression/déplacements de modules ont eu lieu récemment, mettez à jour la configuration correspondant dans le menu MODULES de PARAMETRES AVANCES.<br /><br />Dans le cas où aucune modification n'a été effectuée récemment, vérifier les connexions de tous les modules.")
color: couleur_blanc_casse
font.pixelSize: 18
wrapMode: Label.Wrap
}
}
}
//-------------------------------------------------------
// 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 - (2 * parent.padding)
height: shipheart_hauteur_bandeau_bas - parent.topPadding - parent.bottomPadding;
radius: 5
color: shipheart_couleur_fond_bouton
Image {
source: "/images/icone_retour.png"
sourceSize.height: 30
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
}
MouseArea { // Zone d'interaction. On est obligé de la mettre dans la grille pour que Rectangle et MouseArea soient frères ou parent/enfant ET qu'on n'occupe qu'un espace dans la grille.
id: mouse_area_bandeau_bas_zone_retour
anchors.fill: parent
onClicked: {
shipheart_clic();
stackView.pop()
}
}
}
}
//-------------------------------------------------------
// Boite d'affichage de la liste des alarmes :
//-------------------------------------------------------
Shipheart_boite_dialogue_liste_alarmes {
id: boite_dialogue_liste_alarmes
titre: nom_reservoir
type_source: shipheart_source_mesure_reservoir
id_source: id_reservoir
id_variable: page_reservoir.id_variable
titre_widget: qsTr("Niveau")
unite: "%"
}
//===========================================================
// Economiseur : Doit être placé en fin de page pour fonctionner
//===========================================================
MouseArea {
anchors.fill: parent
preventStealing: true // Permet que cela fonctionne même si un élément flickable (notamment) soit derrière et "vole" le click
enabled: flag_economiseur_actif
onClicked: {
mise_en_veille(0);
}
}
//=============================================================================================================
// Init de la page
//=============================================================================================================
function init_page()
{
var req, res;
//====================================================================
// Init du nom des périodes du graphique :
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(0), "actif": true });
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(1), "actif": true });
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(2), "actif": true });
modele_periodes_graphique.append({ "libelle": Fonctions_date_heure.nom_periode_analyse(3), "actif": true });
//====================================================================
// Recherche de ID_Variable :
req = ' SELECT Cle_primaire, Unite FROM TB_Variables WHERE Code="' + shipheart_reservoir_niveau + '" ';
res = bdd.requete_unique(req);
id_variable = Number(res[0]);
symbole_unite = res[1];
//====================================================================
// Première mise à jour :
mise_a_jour_valeurs_instantanees();
mise_a_jour_courbes();
//====================================================================
// Libération du flag :
flag_init = false;
}
//=============================================================================================================
// Mise à jour de la valeur instantanée
//=============================================================================================================
function mise_a_jour_valeurs_instantanees()
{
var req, res;
var nb;
var i;
var type_entrees;
var etat;
//====================================================================
// Valeur numérique instantanée :
req = 'SELECT Niveau, ';
req += ' Capacite, ';
req += ' ID_Famille, ';
req += ' Etat_systeme, ';
req += ' Type_entrees, ';
req += ' Etat_entrees ';
req += ' FROM TB_Reservoirs ';
req += ' WHERE Cle_primaire="' + id_reservoir + '" ';
res = bdd.requete_unique(req);
niveau = Number(res[0]);
capacite = Number(res[1]);
id_famille = Number(res[2]);
etat_systeme = Number(res[3]);
type_entrees = Number(res[4]);
etat = Number(res[5]);
//console.log("Niveau = " + niveau);
switch(shipheart_unite_volume)
{
case shipheart_unite_volume_litres: precision_affichage_mesures = 0; break;
case shipheart_unite_volume_us_gallons: precision_affichage_mesures = 1; break;
case shipheart_unite_volume_imp_gallons: precision_affichage_mesures = 1; break;
default : precision_affichage_mesures = 1; break;
}
// Message d'alerte :
if ((type_entrees === shipheart_reservoir_type_entrees_aux) && (etat !== shipheart_capteur_etat_normal))
{
texte_alerte = qsTr("La valeur lue sur les electrodes plongées de ce réservoir est incohérente.<br />Vérifier l'ordre de cablage des électrodes sur les entrées auxiliaires à l'arrière de ShipBase. ")
}
else texte_alerte = "";
// Recherche des events liés à ce capteur et leur valeur :
nb_events = -1;
req = 'SELECT Etat_test ';
req += ' FROM TB_Events ';
req += ' WHERE Alarme_source>0 ';
req += ' AND Type_source=' + shipheart_source_mesure_reservoir + ' ';
req += ' AND ID_Source=' + id_reservoir + ' ';
//console.log("Requête = [ " + req + "; ]");
nb = bdd.requete(req);
for (i = 0; i < nb; i ++)
{
res = bdd.lecture_ligne();
if (!res.isEmpty)
{
if (nb_events < Number(res[0])) nb_events = Number(res[0]);
}
}
// En sortant, on a donc nb_events=-1 si aucun event lié, 0 si au moins un event lié mais tous leurs Etat_test=0, et 1 si au moins un event et au moins un a Etat_test=1.
}
//=============================================================================================================
// Mise à jour des données des courbes
//=============================================================================================================
function mise_a_jour_courbes()
{
var req, res;
var nb;
var courbe_principale_duree;
var date_debut, date_fin;
var delta_x, delta_y;
var min, max;
var mini_maxi;
var gradient;
var id_sb_in_i, id_sb_usb_i;
//console.time('mise_a_jour_courbes')
// Paramètres de la courbe dépendant de la période d'analyse :
switch(periode_analyse)
{
default:
case 0: // 1 heure
courbe_nombre_principal_graduations_axe_x = 7 // Nombre de bandes verticales + 1
courbe_nombre_zoom_1_graduations_axe_x = 7 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
courbe_format_principal_axe_x = "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
break;
case 1: // 24 heures
courbe_nombre_principal_graduations_axe_x = 13 // Nombre de bandes verticales + 1
courbe_nombre_zoom_1_graduations_axe_x = 13 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
courbe_format_principal_axe_x = "HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
break;
case 2: // 7 jours
courbe_nombre_principal_graduations_axe_x = 8 // Nombre de bandes verticales + 1
courbe_nombre_zoom_1_graduations_axe_x = 8 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
courbe_format_principal_axe_x = "dd/MM HH:mm" // exemple : "yyyy-MM-dd HH:mm:ss"
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
break;
case 3: // 30 jours
courbe_nombre_principal_graduations_axe_x = 31 // Nombre de bandes verticales + 1
courbe_nombre_zoom_1_graduations_axe_x = 13 // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
courbe_format_principal_axe_x = "dd" // exemple : "yyyy-MM-dd HH:mm:ss"
courbe_format_zoom_1_axe_x = "HH:mm" // Utilisé lorsque le taux de zoom passe en-dessous de 0.5
break;
}
// Dates et durée :
courbe_principale_duree = Fonctions_date_heure.duree_periode_analyse(periode_analyse); // En secondes
date_fin = new Date(); // En UTC
date_debut = Fonctions_date_heure.date_add_secondes(date_fin, -(courbe_principale_duree)); // En UTC
//console.log("Date de début initiale UTC = " + date_debut + " et date de fin UTC = " + date_fin)
// Mise à jour des données de la courbe principale :
res = tbmesuresModel.maj_data(graphique.series("Courbe principale"), "TB_Mesures_reservoirs", id_reservoir, id_variable, date_debut, date_fin, 1, 1, (shipheart_fuseau_horaire + shipheart_heure_ete), 0, 0);
//-----------------------------------------------------------------------------------------------------
// Cas où aucune donnée n'est disponible sur la période :
if (Number(res[0]) === 0)
{
courbe_flag_vide = true; // Permet d'afficher le texte "Aucune donnée disponible..." sur la zone graphique
}
//-----------------------------------------------------------------------------------------------------
// Cas où des données sont disponibles sur la période (cas normal donc...) :
else
{
courbe_flag_vide = false;
xMin_date = new Date(Number(res[1])); // Nécessaire pour la Min de l'axe X (NB : les dates retournées par 'maj_data' sont en heure locale)
xMax_date = new Date(Number(res[3])); // Nécessaire pour la Max de l'axe X (NB : les dates retournées par 'maj_data' sont en heure locale)
// var mini_maxi = Fonctions.ajustement_mini_maxi(Number(res[6]), Number(res[8]), courbe_principale_nombre_graduations_axe_y);
// yMin_valeur = mini_maxi.mini // Nécessaire pour le Min de l'axe Y
// yMax_valeur = mini_maxi.maxi // Nécessaire pour le Max de l'axe Y
yMin_valeur = 0
yMax_valeur = 100.4 // Le '.4' permet de libérer l'espace de l'épaisseur du trait haut quand on est à 100%...
// precision_affichage_axe_y_courbe = Fonctions.precision_affichage_mini_maxi(Number(res[6]), Number(res[8]), courbe_principale_nombre_graduations_axe_y);
precision_affichage_axe_y_courbe = 0
//console.log("Min val=" + Number(res[6]) + " et mini=" + yMin_valeur + " - Max val=" + Number(res[8]) + " et maxi=" + yMax_valeur);
console.timeEnd('mise_a_jour_courbes')
}
busy_indicator.running = false; // Arrêt du tourniquet s'il est en marche
}
//=============================================================================================================
// RAZ du zoom
//=============================================================================================================
function raz_zoom()
{
graphique.zoomReset(); // RAZ du zoom proprement dit
graphique.scrollLeft(dragTarget.cumulX); // RAZ du déplacement horizontal par annulation du cumul
graphique.scrollUp(dragTarget.cumulY); // RAZ du déplacement vertical par annulation du cumul
dragTarget.cumulX = 0; // RAZ du cumul après retour à la position d'origine
dragTarget.cumulY = 0;
flag_zoom_en_cours = false;
zoomx_en_cours = 1;
}
}