//======================================================================================================================================================================== // CONFIG_PAGE_POINT.QML // Ce fichier traite la configuration d'un point dans une page. La page permet notamment de : // - Modifier la config du point (ou de le créer la première fois), // - Supprimer le point // La page est appelée depuis la page config_page_edition.qml, en cliquant sur le point à modifier (ou sur le '+' en vue d'une création) //======================================================================================================================================================================== import QtQuick 2.12 import QtQml.Models import qt.koriolan.shipheart 1.0 import"fonctions.js" as Fonctions Shipheart_page { id: page_config_page_point // Mise en forme - Largeur : readonly property double pourcentage_largeur_colonne_gauche: 0.75 readonly property double espace_colonnes_principales: 20 readonly property double pourcentage_largeur_labels_formulaire: 0.5 readonly property double pourcentage_largeur_unites_formulaire: 0.1 readonly property int largeur_bouton_suite: 15 readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 1 readonly property int nombre_widgets_heure_par_ligne: 12 // Mise en forme - Hauteur : readonly property double pourcentage_hauteur_ligne_haut: 1 readonly property int hauteur_ligne_formulaire: 60 readonly property int hauteur_bouton_droit: 80 readonly property int espace_lignes_principales: 20 readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas // 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 // 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 bool flag_point_existant: false property int type_source: 0 property int id_source: -1 property int type_point: 0 property int taille_point: 25 // Modèles : // Note : les modèles chargés dans 'main.qml' n'ont pas à être rechargés dans les pages suivantes //------------------------------------------------- // Signaux : //------------------------------------------------- signal enregistrer_config_page_point(bool new_flag_point_existant, int new_type_source, int new_id_source, int type_point, int taille_point) // Valeurs à lire lorsque le "OnEnregistrer' est activé //=========================================================== // 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(); } else { } } } //=========================================================== // 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; if (mousearea_bouton_supprimer.pressed) { shipheart_clic(); page_config_page_point.enregistrer_config_page_point(false, type_source, id_source, type_point, taille_point); stackView.pop(); // Retour à la page d'édition de la page } } } } // Titre de la page : Shipheart_titre_1 {titre: (type_source === -1) ? qsTr("Création d'un point") : qsTr("Configuration du point"); 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" ListView { id: grille_principale width: parent.width height: parent.height // snapMode: GridView.SnapToRow // L'arret de l'affichage se fera sur une rangée entière. clip: true // Nécessaire pour que les Delegates s'arretent à l'intérieur de la GridView model: modele_grille_principale footer: Rectangle { // Permet de dégager la place suffisante en fin de GridView pour accéder même au dernier élément lorsque que clavier est déplié height: affichage_hauteur_utile - hauteur_ligne_formulaire // Cette valeur permet de bien remonter les drniers champs (utile dans le cas de Textarea notamment) en laissant toujours une hauteur de lugne de formulaire au moins (évite qu'on "perde" l'affichage qui serait trop décalé vers le haut) color: "transparent" } ObjectModel { id: modele_grille_principale //------------------------------------------------------------------------------- // Ligne de formulaire : Type_source Rectangle { id: ligne_type_source width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: visible ? hauteur_ligne_formulaire : 0 color: "transparent" Shipheart_formulaire_label { text: qsTr("Type de la source") width: parent.width * pourcentage_largeur_labels_formulaire couleur: (champ_formulaire_Type_source.currentIndex !== 0) ? shipheart_formulaire_couleur_texte_par_defaut : shipheart_formulaire_couleur_texte_en_erreur } Shipheart_formulaire_combobox { id: champ_formulaire_Type_source model: ListModel { } width: parent.width * (1 - pourcentage_largeur_labels_formulaire) onActivated: { shipheart_clic(); if (type_source !== champ_formulaire_Type_source.model.get(champ_formulaire_Type_source.currentIndex).valeur) { type_source = champ_formulaire_Type_source.model.get(champ_formulaire_Type_source.currentIndex).valeur; id_source = -1; type_point = 0; if (type_source > 0) mise_a_jour_source(); } } } Shipheart_formulaire_ligne_separation { haut_bas_hautbas: shipheart_formulaire_ligne_separation_basse } } //------------------------------------------------------------------------------- // Ligne de formulaire : ID_Source Rectangle { id: ligne_source width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: visible ? hauteur_ligne_formulaire : 0 color: "transparent" visible: (type_source !== 0) Shipheart_formulaire_label { text: qsTr("Source") width: parent.width * pourcentage_largeur_labels_formulaire couleur: (champ_formulaire_Source.currentIndex !== 0) ? shipheart_formulaire_couleur_texte_par_defaut : shipheart_formulaire_couleur_texte_en_erreur } Shipheart_formulaire_combobox { id: champ_formulaire_Source model: ListModel { } width: parent.width * (1 - pourcentage_largeur_labels_formulaire) onActivated: { shipheart_clic(); id_source = champ_formulaire_Source.model.get(champ_formulaire_Source.currentIndex).valeur; mise_a_jour_type_point(); } } Shipheart_formulaire_ligne_separation { haut_bas_hautbas: shipheart_formulaire_ligne_separation_basse } } //------------------------------------------------------------------------------- // Ligne de formulaire : Type_point Rectangle { id: ligne_type_point width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: visible ? hauteur_ligne_formulaire : 0 color: "transparent" visible: (type_source !== 0) && (id_source !== -1) && (type_source !== shipheart_type_source_modules) // && (champ_formulaire_Type_point.model.count > 1) Shipheart_formulaire_label { text: qsTr("Type de point") width: parent.width * pourcentage_largeur_labels_formulaire couleur: shipheart_formulaire_couleur_texte_par_defaut } Shipheart_formulaire_combobox_icones { id: champ_formulaire_Type_point model: ListModel { } width: parent.width * (1 - pourcentage_largeur_labels_formulaire) onActivated: { shipheart_clic(); type_point = champ_formulaire_Type_point.model.get(champ_formulaire_Type_point.currentIndex).valeur; } } Shipheart_formulaire_ligne_separation { haut_bas_hautbas: shipheart_formulaire_ligne_separation_basse } } //------------------------------------------------------------------------------- // Ligne de formulaire : Taille_point Rectangle { id: ligne_taille_point width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2) height: visible ? hauteur_ligne_formulaire : 0 color: "transparent" visible: (type_source !== 0) && (id_source !== -1) // && (champ_formulaire_Taille_point.model.count > 1) Shipheart_formulaire_label { text: qsTr("Taille du point") width: parent.width * pourcentage_largeur_labels_formulaire couleur: shipheart_formulaire_couleur_texte_par_defaut } Shipheart_formulaire_combobox { id: champ_formulaire_Taille_point model: ListModel { } width: parent.width * (1 - pourcentage_largeur_labels_formulaire) onActivated: { shipheart_clic(); taille_point = champ_formulaire_Taille_point.model.get(champ_formulaire_Taille_point.currentIndex).valeur; } } Shipheart_formulaire_ligne_separation { haut_bas_hautbas: shipheart_formulaire_ligne_separation_basse } } } // Fin de Grille principale } } //------------------------------------------------------- // 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 { id: bouton_enregistrer_creer width: parent.width height: hauteur_bouton_droit color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: (champ_formulaire_Type_source.currentIndex !== 0) && (champ_formulaire_Source.currentIndex !== 0) Text { anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } font.pixelSize: 20 text: flag_point_existant ? qsTr("Enregistrer") : qsTr("Créer le point") color: couleur_blanc_casse } MouseArea { anchors.fill: parent onClicked: { shipheart_clic(); page_config_page_point.enregistrer_config_page_point(true, type_source, id_source, type_point, taille_point); stackView.pop(); // Retour à la page d'édition de la page } } } //....................................................... // Bouton de suppression //....................................................... Rectangle { width: parent.width height: hauteur_bouton_droit color: shipheart_couleur_fond_bouton radius: shipheart_rayon_bouton visible: flag_point_existant 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_supprimer.pressed } Text { anchors { verticalCenter: parent.verticalCenter horizontalCenter: parent.horizontalCenter } font.pixelSize: 20 text: qsTr("Supprimer") color: couleur_blanc_casse } MouseArea { id: mousearea_bouton_supprimer anchors.fill: parent onPressed: { // Déclenché lors de l'appui inital timer_appui_long.running = true; valeur_timer_appui_long = 0; shipheart_clic(); } 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(); page_config_page_point.enregistrer_config_page_point(flag_point_existant, type_source, id_source, type_point, taille_point); stackView.pop(); // Retour à la page d'édition de la page } 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(); stackView.pop() } } } } //------------------------------------------------------- // Boite de validation : //------------------------------------------------------- Shipheart_boite_dialogue { id: boite_information } //=========================================================== // 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 i; // Remplissage des différents modèles, dans l'ordre des priorités : mise_a_jour_type_source(); // Mise à jour du modèle de taille sans attendre car elle est indépendante du type de source ou de point : mise_a_jour_taille_point(); flag_init = false; // Indique que l'init est terminée } //============================================================================================================= // MAJ du type de source //============================================================================================================= function mise_a_jour_type_source() { var i; // Effacement du modèle et premier enregistrement avec 'Non défini' : champ_formulaire_Type_source.model.clear(); champ_formulaire_Type_source.model.append( { "valeur": -1, "texte": qsTr("Non défini"), "actif": true }); champ_formulaire_Type_source.model.append( { "valeur": shipheart_type_source_capteurs, "texte": qsTr("Capteur"), "actif": true }); champ_formulaire_Type_source.model.append( { "valeur": shipheart_type_source_circuits, "texte": qsTr("Circuit"), "actif": true }); champ_formulaire_Type_source.model.append( { "valeur": shipheart_type_source_reservoirs, "texte": qsTr("Réservoir"), "actif": true }); champ_formulaire_Type_source.model.append( { "valeur": shipheart_type_source_batteries, "texte": qsTr("Batterie"), "actif": true }); champ_formulaire_Type_source.model.append( { "valeur": shipheart_type_source_modules, "texte": qsTr("Modules"), "actif": true }); // Mise à jour de l'index courant du modèle champ_formulaire_Type_source : i = recherche_index_valeur_modele(type_source, champ_formulaire_Type_source.model, "Type_source"); if (i === -1) champ_formulaire_Type_source.currentIndex = recherche_index_valeur_modele(-1, champ_formulaire_Type_source.model, "Type_source"); else champ_formulaire_Type_source.currentIndex = i; // Appel du remplissage des modèles de niveau inférieur si cela est possible : if (type_source > 0) mise_a_jour_source(); } //============================================================================================================= // MAJ de la source //============================================================================================================= function mise_a_jour_source() { var req, res; var nb; var i; // Effacement du modèle et premier enregistrement avec 'Non défini' : champ_formulaire_Source.model.clear(); champ_formulaire_Source.model.append( { "valeur": -1, "texte": qsTr("Non défini"), "actif": true }); switch(type_source) { case shipheart_type_source_circuits: req = 'SELECT Cle_primaire, '; req += 'Nom, '; req += 'Nom_famille '; req += 'FROM TB_Circuits, '; req += ' (SELECT Cle_primaire AS Cle_famille, Nom AS Nom_famille, Priorite_affichage AS Priorite_famille FROM TB_Familles WHERE Type_source=' + shipheart_type_source_circuits + ') AS TB_Familles '; req += ' WHERE ID_Famille=Cle_famille '; req += ' ORDER BY Priorite_famille, ABS(Priorite_affichage_accueil)'; break; case shipheart_type_source_capteurs: req = 'SELECT Cle_primaire, '; req += 'Nom, '; req += 'Nom_famille '; req += 'FROM TB_Capteurs, '; req += ' (SELECT Cle_primaire AS Cle_famille, Nom AS Nom_famille, Priorite_affichage AS Priorite_famille FROM TB_Familles WHERE Type_source=' + shipheart_type_source_capteurs + ') AS TB_Familles '; req += ' WHERE ID_Famille=Cle_famille '; req += ' ORDER BY Priorite_famille, ABS(Priorite_affichage_accueil)'; break; case shipheart_type_source_reservoirs: req = 'SELECT Cle_primaire, '; req += 'Nom, '; req += 'Nom_famille '; req += 'FROM TB_Reservoirs, '; req += ' (SELECT Cle_primaire AS Cle_famille, Nom AS Nom_famille, Priorite_affichage AS Priorite_famille FROM TB_Familles WHERE Type_source=' + shipheart_type_source_reservoirs + ') AS TB_Familles '; req += ' WHERE ID_Famille=Cle_famille '; req += ' ORDER BY Priorite_famille, ABS(Priorite_affichage_accueil)'; break; case shipheart_type_source_batteries: req = 'SELECT Cle_primaire, '; req += 'Nom, '; req += 'Nom_famille '; req += 'FROM TB_Batteries, '; req += ' (SELECT Cle_primaire AS Cle_famille, Nom AS Nom_famille, Priorite_affichage AS Priorite_famille FROM TB_Familles WHERE Type_source=' + shipheart_type_source_batteries + ') AS TB_Familles '; req += ' WHERE ID_Famille=Cle_famille '; req += ' ORDER BY Priorite_famille, ABS(Priorite_affichage_accueil)'; break; case shipheart_type_source_modules: req = 'SELECT Adresse_k_bus, '; req += 'Type, '; req += '"" AS Nom_famille '; // Permet de passer le traitement des familles sans erreur et ajout de ligne inutile (les batteries n'ont pas de notion de famille) req += 'FROM TB_Modules_config '; req += ' ORDER BY Adresse_k_bus'; break; default: table = ""; break; } if (req !== "") { //console.log("Requête = [ " + req + "; ]"); nb = bdd.requete(req); var prec_famille = ""; for (i = 0; i < nb; i ++) { res = bdd.lecture_ligne(); if (!res.isEmpty) { // Ajout de le ligne de famille : if (prec_famille !== res[2]) { champ_formulaire_Source.model.append( { "groupe": true, "valeur": 0, "texte": res[2], "actif": false }); prec_famille = res[2]; } // Ajout de la ligne normale : var texte; if (type_source === shipheart_type_source_modules) { texte = Fonctions.nom_type_module(Number(res[1])); if (Number(res[0]) !== 0) texte += " @" + res[0]; } else texte = res[1]; champ_formulaire_Source.model.append( { "groupe": false, "valeur": Number(res[0]), "texte": texte, "actif": true }); } } } // Mise à jour de l'index courant du modèle : i = recherche_index_valeur_modele(id_source, champ_formulaire_Source.model, "id_source"); if (i === -1) champ_formulaire_Source.currentIndex = recherche_index_valeur_modele(0, champ_formulaire_Source.model, "id_source"); else champ_formulaire_Source.currentIndex = i; // Appel du remplissage des modèles de niveau inférieur si cela est possible : if (id_source !== -1) mise_a_jour_type_point(); } //============================================================================================================= // MAJ du type de point //============================================================================================================= function mise_a_jour_type_point() { var req, res; var i; var libelle; // Effacement du modèle : champ_formulaire_Type_point.model.clear(); // Boucle sur toutes les entrées du tableau des types de points correspondant au 'type_source' (cf dans 'main.qml') : for (i = 0; i < shipheart_page_personnalisee_type_point_icones[type_source].length; i ++) { if ((type_source === shipheart_type_source_circuits) && (i === 0)) continue; // Pour les circuits, on n'autorise pas le premier élément qui correspond à l'icone OFF champ_formulaire_Type_point.model.append( { "valeur": i, "texte": "", "icone": shipheart_page_personnalisee_type_point_icones[type_source][i], "actif": true }); } // Mise à jour de l'index courant du modèle : i = recherche_index_valeur_modele(type_point, champ_formulaire_Type_point.model, "type_point"); if (i === -1) champ_formulaire_Type_point.currentIndex = recherche_index_valeur_modele(1, champ_formulaire_Type_point.model, "type_point"); else champ_formulaire_Type_point.currentIndex = i; // Cas particulier des modules : on ne laisse pas le choix de l'icone à afficher... if (type_source === shipheart_type_source_modules) { req = 'SELECT Type FROM TB_Modules_config WHERE Adresse_k_bus=' + id_source + ' '; //console.log("Requête = [ " + req + "; ]"); res = bdd.requete_unique(req); type_point = Number(res[0]); // Pour les modules, on a autant de fichiers que de type, classés dans l'ordre des Type. } } //============================================================================================================= // MAJ de la taille de point //============================================================================================================= function mise_a_jour_taille_point() { var i; // Effacement du modèle :: champ_formulaire_Taille_point.model.clear(); for (i = 2; i <= 16; i ++) { champ_formulaire_Taille_point.model.append( { "valeur": (i * 5), "texte": (i * 5), "actif": true }); } // Mise à jour de l'index courant du modèle : i = recherche_index_valeur_modele(taille_point, champ_formulaire_Taille_point.model, "taille_point"); if (i === -1) champ_formulaire_Taille_point.currentIndex = recherche_index_valeur_modele(25, champ_formulaire_Taille_point.model, "taille_point"); else champ_formulaire_Taille_point.currentIndex = i; } //============================================================================================================= // 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