Files
shipheart-qt/config_reseau_k_bus.qml

1134 lines
56 KiB
QML

//========================================================================================================================================================================
// CONFIG_RESEAU_K_BUS.QML
// Ce fichier permet de gérer l'affectation des modules présents sur K-Bus par rapport à la configuration actuelle des circuits et des batteries.
// La page est appelée depuis la page PARAMETRES_AVANCES
//========================================================================================================================================================================
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_reseau_k_bus
// Mis en forme :
readonly property double affichage_hauteur_utile: shipheart_hauteur_page - shipheart_hauteur_bandeau_haut - shipheart_hauteur_bandeau_bas
readonly property int hauteur_bouton_droit: 80
readonly property int hauteur_ligne_formulaire: 60
readonly property double pourcentage_largeur_colonne_gauche: 0.3
readonly property double pourcentage_largeur_colonne_centre: 0.5
readonly property int espace_colonnes_principales: 20
readonly property double pourcentage_bandeau_bas_largeur_zone_retour: 0.5
readonly property double pourcentage_largeur_labels_formulaire: 0.5
readonly property int nombre_modules_affiches_sur_une_colonne: 6//8
readonly property int periode_init_raffraichissement_parametres: 1 // En ms
readonly property int periode_raffraichissement_parametres: 1000 // En ms
readonly property int action_carte_aucune: 0
readonly property int action_carte_cde: 1
readonly property int action_carte_etalonnage: 2
// Affichage :
property int index_en_cours: -1
property int nb_modules_physiques: 0
property bool flag_init: true // Permet de bloquer certains affichage tant que l'init n'est pas terminée
property bool flag_maj_en_cours: false
// 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 :
//===========================================================
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
{
mise_a_jour_modules_physiques();
mise_a_jour_modules_config();
}
}
}
//===========================================================
// Lorsque la page est sur le point d'être affichée dans la pile :
//===========================================================
StackView.onActivating: { // Le 'onActivating' permet de ne pas voir la mise à jour puisqu'elle est lancée dès que la page va être chargée
// StackView.onActivated: { // Le 'onActivated' laisse voir la mise à jour (puisqu'elle est lancée quand la page est complètement affichée
init_modules_configures(); // Utile au démarrage ET au retour d'autres pages si on a modifié la config des groupes de circuits entre temps...
}
// Titre de la page :
Shipheart_titre_1 {titre:qsTr("Réseau ShipHeart"); hauteur: shipheart_hauteur_bandeau_haut}
//-------------------------------------------------------
// Ecran de gauche (liste des modules physiquement présents) :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_gauche
x: 0
y: shipheart_hauteur_bandeau_haut;
width: (shipheart_largeur_page * pourcentage_largeur_colonne_gauche) - (espace_colonnes_principales / 2)
height: affichage_hauteur_utile
color: "transparent"
//-------------------------------------------------------------------
// Titre de la liste :
Rectangle {
width: parent.width
height: hauteur_ligne_formulaire
color: "transparent"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: qsTr("Modules physiquement présents")
color: couleur_gris_moyen
font.pixelSize: 18
wrapMode: Label.Wrap
}
}
//-------------------------------------------------------------------
// Liste des modules physiquement présents :
ListView {
id: grille_modules_physiques
y: hauteur_ligne_formulaire // Permet d'échapper la ligne de titre
width: parent.width
height: parent.height - hauteur_ligne_formulaire
// interactive: false // Rend la liste NON scrollable à la main. C'est la liste de droite qui met à jour la position de celle de gauche.
highlightRangeMode: ListView.StrictlyEnforceRange // Nécessaire pour récupérer 'currentIndex' et le répercuter sur la ListView des modules configurés
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_modules_physiques
delegate: Rectangle {
width: grille_modules_physiques.width
height: grille_modules_physiques.height / nombre_modules_affiches_sur_une_colonne
color: "transparent"
visible: !flag_init & !flag_maj_en_cours
Rectangle { // c'est le bouton proprement dit...
anchors.fill: parent;
anchors.verticalCenter : parent.verticalCenter
anchors.margins: 5
radius: shipheart_rayon_bouton
color: "transparent"
border.width: 2
border.color: shipheart_couleur_fond_bouton
//-----------------------
// Adresse :
Rectangle {
id: zone_adresse_module_physique
x: 0
y: 0
width: 50
height: parent.height
color: "transparent"
radius: shipheart_rayon_bouton
border.width: 2
border.color: shipheart_couleur_fond_bouton
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: model.adresse
color: couleur_blanc_casse
font.pixelSize: 28
font.bold: true
}
}
//-----------------------
// Nom :
Rectangle {
id: zone_nom_module_physique
x: zone_adresse_module_physique.width
y: 0
width: parent.width - zone_adresse_module_physique.width
height: parent.height / 3
color: "transparent"
Text { // Type et nom du module
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
leftPadding: 10
rightPadding: 20
text: model.nom
color: couleur_blanc_casse
font.pixelSize: 18
font.bold: true
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
shipheart_clic();
stackView.push("config_module_physique.qml", {"adresse_module": model.adresse})
}
}
}
ListModel {
id: modele_modules_physiques
}
onCurrentIndexChanged: {
grille_modules_configures.positionViewAtIndex(currentIndex, ListView.Beginning); // Permet de faire défiler la liste des modules configurés "en face" des modules physiques.
if ( (currentIndex >= grille_modules_configures.count) && // Si le module affiché est à une adresse > à l'adresse la plus élevée des modules configurés, on n'afficha plue la liste configurée (sinon, on reste bloqué sur le dernier module configuré qui est alors décalé par rapport au module physique affiché en face)
(grille_modules_configures.count !== 0)) // Utile à l'ouverture de la page car on passe par l'état ou COUNT=0 et la liste configurée n'est plus visible avant le premier mouvement
{
grille_modules_configures.visible = false;
}
else grille_modules_configures.visible = true; // Si on revient à la situation où le module physique affiché a une adresse < nombre de modules configurés (donc plus de risque de décalage)
}
}
}
//-------------------------------------------------------
// Barre de séparation verticale :
//-------------------------------------------------------
Rectangle {
id: separation_verticale
x: zone_affichage_gauche.width + (espace_colonnes_principales / 2) - (width / 2)
y: shipheart_hauteur_bandeau_haut;
width: 3
height: affichage_hauteur_utile
color: couleur_gris_tres_pale_transparent
}
//-------------------------------------------------------
// Ecran central (modules utilisés par la configuration actuelle) :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_centre
x: zone_affichage_gauche.width + (espace_colonnes_principales)
y: shipheart_hauteur_bandeau_haut;
width: (shipheart_largeur_page * pourcentage_largeur_colonne_centre) - (espace_colonnes_principales)
height: affichage_hauteur_utile
color: "transparent"
//-------------------------------------------------------------------
// Titre de la liste :
Rectangle {
width: parent.width
height: hauteur_ligne_formulaire
color: "transparent"
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Qt.AlignVCenter
text: qsTr("Modules utilisés par la configuration actuelle")
color: couleur_gris_pale
font.pixelSize: 18
wrapMode: Label.Wrap
}
}
//-------------------------------------------------------------------
// Liste :
ListView {
property bool deplacement_en_cours: false // Indique si un déplacement (au global) est en cours ou pas
property int save_current_index: 0 // Permet de garder le Current_index du début du déplacement et de compenser les changements qui sont fait automatiquement, notamment en début et fin de liste. Le principe est qu'une fois le mouvement déclenché, ON NE CHANGE PAS de CurrentIndex !!
id: grille_modules_configures
x: 0
y: hauteur_ligne_formulaire // Permet d'échapper la ligne de titre
width: parent.width
height: parent.height - hauteur_ligne_formulaire
clip: true // Limite l'affichage des délégués dans la zone de ListView (sinon, on affiche au moins un délégué au-dessus et un en dessous...)
highlightRangeMode: ListView.StrictlyEnforceRange // Permet de faire défiler la liste jusqu'à ne garder que le dernier élément affiché (et comme la liste des modules physiques est obligée d'utiliser ce paramètre, on fait pareil sur cette liste pour que les deux soient synchro)
model: modele_modules_configures
delegate: bouton_module
displaced: Transition { // Gère la transition lors d'un déplacement
NumberAnimation{
properties: "x,y" // Ici, on devrait pouvoir limiter à Y
duration: 500 // Vitesse à laquelle se déplacent les boutons lorsqu'on les déplace
}
}
Component {
id: bouton_module
MouseArea {
id: dragArea // Zone correspondant à un seul bouton (on est dans le Delegate)
width: grille_modules_configures.width
height: grille_modules_configures.height / nombre_modules_affiches_sur_une_colonne
property bool bouton_appuye: false // On ne peut pas utiliser la propriété globale "deplacement_en_cours" car il faut une propriété par délégué
pressAndHoldInterval: 500; // Temporise avant de passer en mode "déplacement"
drag.target: bouton_appuye ? contenu_bouton_module : undefined
drag.axis: Drag.YAxis // On ne se déplace que sur l'axe Y
onClicked: {
shipheart_clic();
stackView.push("config_module.qml", {"adresse_module": adresse})
}
onPressAndHold: {
if (adresse !== 0) // ShipBase n'est pas "bougeable"
{
bouton_appuye = true // Indication (au niveau du bouton seul) du début de l'appui long donc du déplacement
grille_modules_configures.deplacement_en_cours = true // Indication (au niveau de ListView) du début du déplacement
grille_modules_configures.save_current_index = grille_modules_configures.currentIndex; // Sauvegarde du CurrentIndex au début du déplacement
}
}
onReleased: {
bouton_appuye = false // Indication (au niveau du bouton seul) de la fin de l'appui long donc du déplacement
grille_modules_configures.deplacement_en_cours = false // Indication (au niveau de ListView) de la fin du déplacement
grille_modules_configures.currentIndex = grille_modules_configures.save_current_index; // Restitution de la valeur initiale du CurrentIndex (a priori, pas nécessaire car mis à jour au fur et à mesure des changements dans "onCurrentIndexChanged")
enregistrement(); // Le principe est denregistrer après chaque déplacement ; sinon, les appels aux menus inférieurs (détails de modume physique ou config) deviennent très compliqués...
}
Rectangle {
id: contenu_bouton_module
anchors {
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
width: dragArea.width - 10
height: dragArea.height - 10
radius: shipheart_rayon_bouton
color: (adresse ===0)
? "transparent" // Incolore pour ShipBase (on ne peut pas le bouger)
: ((model.erreur === 0)
? shipheart_couleur_fond_bouton // Couleur par défaut si pas d'erreur
: (model.affecte === 0
? couleur_orange_transparent // Orange si aucune affectation sur ce module
: couleur_rouge_transparent)) // Rouge s'il y a une affectation sur ce module
border.width: 2
border.color: shipheart_couleur_fond_bouton
opacity: dragArea.bouton_appuye ? 0.5 : 0.8
//-----------------------
// Adresse :
Rectangle {
id: zone_adresse_module
x: 0
y: 0
width: 50
height: parent.height
color: "transparent"
radius: shipheart_rayon_bouton
border.width: 2
border.color: shipheart_couleur_fond_bouton
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: model.adresse
color: (affecte === 1) ? couleur_blanc_casse : couleur_gris_fonce
font.pixelSize: 28
font.bold: true
}
}
//-----------------------
// Nom :
Rectangle {
id: zone_nom_module
x: zone_adresse_module.width
y: 0
width: parent.width - zone_adresse_module.width
height: parent.height / 3
color: "transparent"
Text { // Type et nom du module
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
leftPadding: 10
rightPadding: 20
text: Fonctions.nom_type_module(model.type) + (model.nom === "" ? "" : " [" + model.nom + "]")
color: (affecte === 1) ? couleur_blanc_casse : couleur_gris_fonce
font.pixelSize: 18
font.bold: true
}
}
//-----------------------
// Usages principaux :
Rectangle {
id: zone_usage_principal
x: zone_adresse_module.width
y: (parent.height / 3)
width: parent.width - zone_adresse_module.width
height: parent.height / 3
color: "transparent"
visible: (usage_principal !== "")
Rectangle {
id: icone_usage_principal
x: 10
width: 20
height: parent.height
color: "transparent"
Image {
source: (type === shipheart_type_module_shipBS)
? "/images/batterie_moyen.png"
: "/images/icone_consommation_electrique.png"
anchors.fill: parent
fillMode: Image.PreserveAspectFit
opacity: 0.7
}
}
Text { // Utilisation du module en config (liste des circuits, nom de la batterie, ...)
anchors.verticalCenter: parent.verticalCenter
anchors.left: icone_usage_principal.right
leftPadding: 10
rightPadding: 20
width: zone_usage_principal.width - icone_usage_principal.width // Nécessaire pour que 'elide' fonctionne
wrapMode: Text.Wrap // Utile si 'maximumLineCount' > 1
maximumLineCount: 1 // Nb de lignes sur lequel le texte sera affiché avant l'elide
elide: Text.ElideRight // Affiche des [...] lorsque le texte est trop long
text: usage_principal
color: (affecte === 1) ? couleur_gris_tres_pale : couleur_gris_fonce
font.pixelSize: 15
}
}
//-----------------------
// Usages secondaires :
Rectangle {
id: zone_usage_secondaire
x: zone_adresse_module.width
y: (2 * parent.height / 3)
width: parent.width - zone_adresse_module.width
height: parent.height / 3
color: "transparent"
visible: (usage_secondaire !== "")
Rectangle {
id: icone_usage_secondaire
x: 10
width: 20
height: parent.height
color: "transparent"
Image {
source: "/images/icone_auxiliaires.png"
anchors.fill: parent
fillMode: Image.PreserveAspectFit
opacity: 0.7
}
}
Text { // Utilisation du module en config (liste des circuits, nom de la batterie, ...)
anchors.verticalCenter: parent.verticalCenter
anchors.left: icone_usage_secondaire.right
leftPadding: 10
rightPadding: 20
width: zone_usage_secondaire.width - icone_usage_secondaire.width // Nécessaire pour que 'elide' fonctionne
wrapMode: Text.Wrap // Utile si 'maximumLineCount' > 1
maximumLineCount: 1 // Nb de lignes sur lequel le texte sera affiché avant l'elide
elide: Text.ElideRight // Affiche des [...] lorsque le texte est trop long
text: usage_secondaire
color: (affecte === 1) ? couleur_gris_tres_pale : couleur_gris_fonce
font.pixelSize: 15
}
}
Drag.active: dragArea.bouton_appuye
Drag.source: dragArea
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
states: State{
when: dragArea.bouton_appuye
ParentChange {
target: contenu_bouton_module
parent: grille_modules_configures
}
AnchorChanges {
target: contenu_bouton_module
anchors { // Necessaire pour autoriser le mouvement
horizontalCenter: undefined
verticalCenter: undefined
}
}
}
}
DropArea {
enabled: (adresse !== 0) // Interdit de déposer un module sur l'adresse 0 (ShipBase)
anchors.fill: parent
onEntered: {
if (drag.source.DelegateModel.itemsIndex !== dragArea.DelegateModel.itemsIndex)
{
//console.log("\tMouvement de Source index = " + drag.source.DelegateModel.itemsIndex + " vers Dest index = " + dragArea.DelegateModel.itemsIndex)
modele_modules_configures.move(drag.source.DelegateModel.itemsIndex, dragArea.DelegateModel.itemsIndex, 1)
mise_a_jour_modules_config(); // Mise à jour des flags d'erreur (donc les modules teintés de rouge) suite au dernier déplacement.
}
}
}
}
}
ListModel {
id: modele_modules_configures
}
onCurrentIndexChanged: {
if (grille_modules_configures.deplacement_en_cours === false)
{
grille_modules_physiques.positionViewAtIndex(currentIndex, ListView.Beginning); // Permet de faire défiler la liste des modules physiques "en face" des modules configurés. Mais uniquement en dehors de déplacements puisque, pendant les déplacements, on force CurrentIndex à rester fixe.
if ( (currentIndex >= grille_modules_physiques.count) && // Si le module affiché est à une adresse > à l'adresse la plus élevée des modules physiques, on n'afficha plue la liste physique (sinon, on reste bloqué sur le dernier module physique qui est alors décalé par rapport au module config affiché en face)
(grille_modules_physiques.count !== 0)) // Utile à l'ouverture de la page car on passe par l'état ou COUNT=0 et la liste physique n'est plus visible avant le premier mouvement
{
grille_modules_physiques.visible = false;
}
else grille_modules_physiques.visible = true; // SI on revient à la situation où le module config affiché a une adresse < nombre de modules physiques (donc plus de risque de décalage)
}
else
{
grille_modules_configures.currentIndex = grille_modules_configures.save_current_index; // Permet de compenser les changements de CurrentIndex 'imposés' par le ListView. Notamment lors des déplacements en début et fin de liste.
}
}
}
//-------------------------------------------------------------------
// Message si liste vide :
Label {
anchors.fill: parent
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
visible: modele_modules_configures.count === 0
text: qsTr("La configuration actuelle ne fait appel à aucun autre module que ShipBase...")
color: couleur_rouge_transparent
font.pixelSize: 15
font.bold: true
wrapMode: Label.Wrap
}
}
//-------------------------------------------------------
// Ecran Droite :
//-------------------------------------------------------
Rectangle {
id: zone_affichage_droite
x: zone_affichage_gauche.width + espace_colonnes_principales + zone_affichage_centre.width + espace_colonnes_principales;
y: shipheart_hauteur_bandeau_haut + hauteur_ligne_formulaire + 5;
width: (shipheart_largeur_page * (1 - pourcentage_largeur_colonne_gauche - pourcentage_largeur_colonne_centre)) - (espace_colonnes_principales / 2);
height: affichage_hauteur_utile
color: "transparent"
Column {
anchors.fill: parent
spacing: 10
//----------------------
// Bouton + :
Rectangle {
width: parent.width
height: hauteur_bouton_droit
color: shipheart_couleur_fond_bouton
radius: shipheart_rayon_bouton
visible: !clavier.active
Text {
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
font.pixelSize: 40
text: qsTr("+")
color: couleur_blanc_casse
}
MouseArea {
anchors.fill: parent
onClicked: {
shipheart_clic();
stackView.push("config_module_creation.qml", {"adresse_module": modele_modules_configures.count});
}
}
}
//-----------------------------------
// Bouton de rechargement de config :
Rectangle {
width: parent.width
height: hauteur_bouton_droit
color: shipheart_couleur_fond_bouton
radius: shipheart_rayon_bouton
visible: !clavier.active
Image {
source: "/images/cycle.png"
sourceSize.height: (parent.height * 0.5)
anchors {
verticalCenter: parent.verticalCenter
horizontalCenter: parent.horizontalCenter
}
}
MouseArea {
anchors.fill: parent
onClicked: {
shipheart_clic();
synchro_bdd(shipheart_type_synchro_config);
timer_tempo_reconfiguration.restart(); // Lancement du timer d'attente de fin de reconfig
}
}
}
}
}
//-------------------------------------------------------
// 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: 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();
}
}
}
//.................................................
// 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();
maj_flag_defaut_config_k_bus();
init_modules_configures();
}
else timer_tempo_reconfiguration.interval = 100 // Tempo plus courte pour les lectures suivantes")
}
}
}
//===========================================================
// 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()
{
modele_modules_physiques.clear(); // Doit être ici car la maj est appelée régulièrement
mise_a_jour_modules_physiques(); // L'init des modules de config est lancée directement à la fin de la mise à jour des modules physiques
flag_init = false;
}
//=============================================================================================================
// Mise à jour périodique (et à l'init) des informations des modules physiquement présents
//=============================================================================================================
function mise_a_jour_modules_physiques()
{
var req, res;
var i;
var nb;
//--------------------------------------------------------------------
// Vérification de la dispo du CM3+/CM4 :
//--------------------------------------------------------------------
// Vérification que le CM3+/CM4 est bien On (sinon, il est fort probable qu'il soit en cours de démarrage ou de raffraichissement de son annuaire et
// on va récupérer des données partielles...
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_cm3p" ';
res = bdd.requete_unique(req);
if (Number(res[0]) === 0)
{
//console.log("CM3+/CM4 non disponible. La mise à jour est avortée...")
return;
}
flag_maj_en_cours = true;
//--------------------------------------------------------------------
// Mise à jour de la liste des modules physiques :
//--------------------------------------------------------------------
req = 'SELECT Adresse_k_bus, Type FROM TB_Modules_physiques ORDER BY Adresse_k_bus';
//console.log("req =" + req);
nb = bdd.requete(req);
for (i = 0; i < nb; i ++)
{
res = bdd.lecture_ligne();
if (!res.isEmpty)
{
if (Number(res[0]) > modele_modules_physiques.count)
{
modele_modules_physiques.append({"adresse": Number(res[0]), "nom": Fonctions.nom_type_module(Number(res[1])), "type": Number(res[1])});
}
else
{
modele_modules_physiques.set(Number(res[0]), {"adresse": Number(res[0]), "nom": Fonctions.nom_type_module(Number(res[1])), "type": Number(res[1])});
}
}
else break; // Ne devrait pas arriver....
}
//--------------------------------------------------------------------
// Suppression du modèle des éventuels modules physiques supprimés :
//--------------------------------------------------------------------
while(modele_modules_physiques.count > nb)
{
modele_modules_physiques.remove((modele_modules_physiques.count - 1), 1);
}
//--------------------------------------------------------------------
// Détection d'un changement de nombre de modules physiques :
//--------------------------------------------------------------------
if (nb_modules_physiques !== modele_modules_physiques.count)
{
nb_modules_physiques = modele_modules_physiques.count;
}
flag_maj_en_cours = false;
}
//=============================================================================================================
// Mise à jour périodique des informations sur l'utilisation des modules par la config actuelle
//=============================================================================================================
function mise_a_jour_modules_config()
{
var req, res;
var i;
var nb;
var erreur;
//--------------------------------------------------------------------
// Vérification de la dispo du CM3+/CM4 :
//--------------------------------------------------------------------
// Vérification que le CM3+/CM4 est bien On (sinon, il est fort probable qu'il soit en cours de démarrage ou de raffraichissement de son annuaire et
// on va récupérer des données partielles...
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_cm3p" ';
res = bdd.requete_unique(req);
if (Number(res[0]) === 0)
{
//console.log("CM3+/CM4 non disponible. La mise à jour est avortée...")
return;
}
flag_maj_en_cours = true;
//--------------------------------------------------------------------
// Recherche des modules en erreur (différence entre le type réellement présent et le type en config) :
//--------------------------------------------------------------------
// NB : on ne peut pas utiliser le flag Presence dand TB_Modules_config comme à l'init car on a pu bouger les modules de mise_a_jour_modules_config()
// sans avoir encore mis à jour la BDD (tant qu'on n'a pas enregistré les modifs). Il faut donc faire cette vérification entre le modèle physique
// qui, lui, est mis à jour en temps réel via TB_Modules_physiques et le modèle config qui est mis à jour par les déplacements après l'init.
for (i=0; i<modele_modules_configures.count; i++)
{
erreur = 0;
if (i < nb_modules_physiques) // Tant qu'il y a un module physique à l'adresse du module configuré :
{
if ( (modele_modules_configures.get(i).type !== shipheart_type_module_inconnu) && // Si aucun module n'est configuré à cette adresse, on ne peut pas avoir d'erreur
(modele_modules_configures.get(i).type !== modele_modules_physiques.get(i).type)) // Si le type configuré est différent du physique, on est en erreur
{
erreur = 1;
}
}
else
{
if (modele_modules_configures.get(i).type !== shipheart_type_module_inconnu) erreur = 1; // Cas où le module configuré n'a pas d'équivalent physique à cette adresse.
}
modele_modules_configures.setProperty(i, "erreur", erreur);
}
flag_maj_en_cours = false;
}
//=============================================================================================================
// Init des informations sur l'utilisation des modules par la config actuelle
//=============================================================================================================
function init_modules_configures()
{
var req, res;
var i, j;
var usage_principal;
var usage_secondaire;
var nb;
//--------------------------------------------------------------------
// Vérification de la dispo du CM3+/CM4 :
//--------------------------------------------------------------------
// on va récupérer des données partielles...
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Etat_cm3p" ';
res = bdd.requete_unique(req);
if (Number(res[0]) === 0)
{
//console.log("CM3+/CM4 non disponible. La mise à jour est avortée...")
return;
}
flag_maj_en_cours = true;
modele_modules_configures.clear(); // RAZ des valeurs existantes
//--------------------------------------------------------------------
// Mise à jour du modèle avec les modules utilisés en config :
//--------------------------------------------------------------------
req = 'SELECT Adresse_k_bus, Nom, Type, Presence, Affecte FROM TB_Modules_config ORDER BY Adresse_k_bus';
//console.log("req =" + req);
nb = bdd.requete(req);
for (i = 0; i < nb; i ++)
{
res = bdd.lecture_ligne();
if (!res.isEmpty)
{
modele_modules_configures.set(Number(res[0]),
{ "adresse": Number(res[0]),
"nom": res[1],
"type":Number(res[2]),
"usage_principal": "",
"usage_secondaire": "",
"erreur": ((Number(res[3]) === 0) && (Number(res[2]) !== shipheart_type_module_inconnu)) ? 1 : 0,
"valide": 1,
"affecte": Number(res[4]) });
}
else break; // Ne devrait pas arriver....
}
//--------------------------------------------------------------------
// Recherche des equipements utilisés par les module configurés :
//--------------------------------------------------------------------
for (i=0; i<modele_modules_configures.count; i++)
{
if (modele_modules_configures.get(i).adresse === 0) continue; // Pour ShipBase, on n'affiche pas les usages car trop long...
usage_principal = "";
usage_secondaire = "";
switch(modele_modules_configures.get(i).type)
{
//-----------------------------------------
case shipheart_type_module_shippower812:
case shipheart_type_module_shippower8DC:
case shipheart_type_module_shippower4AC:
//----------------------------------------------------
// Recherche des circuits affectés à ce n° de module :
req = 'SELECT No_circuit, Nom, ID_Circuit_esclave FROM TB_Circuits WHERE Adresse_module=' + modele_modules_configures.get(i).adresse + ' ORDER BY No_circuit ';
//console.log("req =" + req);
nb = bdd.requete(req);
for (j = 0; j < nb; j ++)
{
res = bdd.lecture_ligne();
if (!res.isEmpty)
{
if (usage_principal !== "") usage_principal += " | ";
usage_principal += res[1];
if (Number(res[2]) < 0) usage_principal += qsTr(" [renfort]");
}
else break;
}
//----------------------------------------------------
// Recherche de la batterie affecté à ce n° de module :
req = 'SELECT Nom FROM TB_Batteries WHERE Type_entrees=' + shipheart_batteries_type_entrees_predefinie + ' AND Adresse_module=' + modele_modules_configures.get(i).adresse;
//console.log("req =" + req);
nb = bdd.requete(req);
if (nb > 0) // Un peu lourd mais permet de traiter le cas où il n'y a pas de batterie configurée sur ce module.
{
res = bdd.lecture_ligne();
usage_secondaire += res[0];
}
break;
//-----------------------------------------
case shipheart_type_module_shipBS:
//----------------------------------------------------
// Recherche de la batterie affecté à ce n° de module :
req = 'SELECT Nom FROM TB_Batteries WHERE Type_entrees=' + shipheart_batteries_type_entrees_ibs + ' AND Adresse_module=' + modele_modules_configures.get(i).adresse;
//console.log("req =" + req);
nb = bdd.requete(req);
if (nb > 0) // Un peu lourd mais permet de traiter le cas où il n'y a pas de batterie configurée sur ce module.
{
res = bdd.lecture_ligne();
usage_principal += res[0];
}
break;
//-----------------------------------------
default:
break;
}
//----------------------------------------------------
// Recherche des capteurs affectés à ce module :
req = 'SELECT Cle_primaire, Nom FROM TB_Capteurs WHERE Adresse_module=' + modele_modules_configures.get(i).adresse + ' ORDER BY Nom';
//console.log("req = [ " + req + "; ]");
nb = bdd.requete(req);
for (j = 0; j < nb; j ++)
{
res = bdd.lecture_ligne();
if (!res.isEmpty)
{
if (usage_secondaire !== "") usage_secondaire += " | ";
usage_secondaire += res[1];
}
else break;
}
//--------------------------------------------------------------
// Mise à jour du modèle avec l'ensemble des usages du module :
if (usage_principal !== "") modele_modules_configures.setProperty(i, "usage_principal", usage_principal);
if (usage_secondaire !== "") modele_modules_configures.setProperty(i, "usage_secondaire", usage_secondaire);
}
flag_maj_en_cours = false;
}
//=============================================================================================================
// Sauvegarde des modifications effectuées
//=============================================================================================================
function enregistrement()
{
var req, res;
var i;
var nb;
// Commentaire péliminaire :
// On est obligé de passer par des champs temporaires car on ne maitrise pas l'ordre des mises à jour.
// Si on modifiait directement le champs d'adresse (que ce soit dans TB_Modules_config ou dans une TB_Capteurs, ...)
// les dernières lignes mises à jour ne pourront pas distinguer les adresses d'origine des nouvelles adresses.
// En passant par des chamlps temporaires, on est sûr de mettre à jour selon l'ancienne adresse, sans mélange avec
// les nouvelles.
//----------------------------------------------------------------------------------------------
// Creation du champ temporaire dans TB_Modules_config & initialisation avec valeurs actuelles :
//----------------------------------------------------------------------------------------------
req = 'ALTER TABLE TB_Modules_config ADD COLUMN IF NOT EXISTS `Tmp_adresse_k_bus` INT; UPDATE TB_Modules_config SET Tmp_adresse_k_bus=Adresse_k_bus; ';
//console.log("req =" + req);
bdd.requete_unique(req);
//--------------------------------------------------------------------------------------------------
// Creation du champ temporaire & chargement de la valeur actuelle pour les différents équipements :
//--------------------------------------------------------------------------------------------------
req = 'ALTER TABLE TB_Batteries ADD COLUMN IF NOT EXISTS `Tmp_module_entrees` INT UNSIGNED NOT NULL DEFAULT 0; UPDATE TB_Batteries SET Tmp_module_entrees=Adresse_module; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'ALTER TABLE TB_Capteurs ADD COLUMN IF NOT EXISTS `Tmp_module_entrees` INT UNSIGNED NOT NULL DEFAULT 0; UPDATE TB_Capteurs SET Tmp_module_entrees=Adresse_module; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'ALTER TABLE TB_Circuits ADD COLUMN IF NOT EXISTS `Tmp_no_carte` INT UNSIGNED NOT NULL DEFAULT 0; UPDATE TB_Circuits SET Tmp_no_carte=Adresse_module; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'ALTER TABLE TB_Reservoirs ADD COLUMN IF NOT EXISTS `Tmp_module_entrees` INT UNSIGNED NOT NULL DEFAULT 0; UPDATE TB_Reservoirs SET Tmp_module_entrees=Adresse_module; ';
//console.log("req =" + req);
bdd.requete_unique(req);
//----------------------------------------------------------------------------------------------
// Boucle sur tous les modules pour traiter ceux dont l'adresse a été modifiée :
//----------------------------------------------------------------------------------------------
for (i=0; i<modele_modules_configures.count; i++)
{
if (modele_modules_configures.get(i).adresse !== i) // Si le module a été déplacé, on met à jour les éléments concernés, que la config soit valide ou non (1. il est possible que la mise à jour physique se fasse ensuite... et, surtout, 2. il faut éviter d'avoir des config différentes qui pointent sur la même adresse !!)
{
req = 'UPDATE TB_Modules_config SET ';
req += 'Tmp_adresse_k_bus=' + i + ' ';
req += 'WHERE Adresse_k_bus=' + modele_modules_configures.get(i).adresse;
//console.log("req =" + req);
bdd.requete_unique(req);
//-------------------------------------------------------------------------------------------------------------------------------
// Mise à jour du module d'affectation de tous les équipements qui pourraient être concernés, sans se préoccuper du type de module :
req = 'UPDATE TB_Batteries SET Tmp_module_entrees=' + i + ' WHERE Adresse_module=' + modele_modules_configures.get(i).adresse + ' ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Capteurs SET Tmp_module_entrees=' + i + ' WHERE Adresse_module=' + modele_modules_configures.get(i).adresse + ' ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Circuits SET Tmp_no_carte=' + i + ' WHERE Adresse_module=' + modele_modules_configures.get(i).adresse;
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Reservoirs SET Tmp_module_entrees=' + i + ' WHERE Adresse_module=' + modele_modules_configures.get(i).adresse + ' ';
//console.log("req =" + req);
bdd.requete_unique(req);
}
}
//----------------------------------------------------------------------------------------------
// Recherche des doublons éventuels d'adresses dans TB_Modules_config (ne doit pas arriver...) :
//----------------------------------------------------------------------------------------------
req = 'SELECT Tmp_adresse_k_bus FROM TB_Modules_config ORDER BY Tmp_adresse_k_bus';
//console.log("req =" + req);
nb = bdd.requete(req);
for (i = 0; i < nb; i ++)
{
res = bdd.lecture_ligne();
//console.log("i=" + i + " : Tmp_adresse_k_bus = "+Number(res[0]));
if (Number(res[0]) !== i)
{
console.log("Erreur de numérotation de Temp_adresse_k_bus. La mise à jour est impossible !!");
return; // Important : la sortie brutale est possible car on n'a pas encore effectué de mise à jour proprement dite...
}
}
//-------------------------------------------------------------------------------------------------------------------------------------
// Mise à jour de de la valeur courante à partir de la valeur temporaire & suppression de la colonne temporaire dans TB_Modules_config :
//-------------------------------------------------------------------------------------------------------------------------------------
req = 'UPDATE TB_Modules_config SET Adresse_k_bus=Tmp_adresse_k_bus; ALTER TABLE TB_Modules_config DROP COLUMN IF EXISTS Tmp_adresse_k_bus ';
//console.log("req =" + req);
bdd.requete_unique(req);
//----------------------------------------------------------------------------------------------------------------
// Mise à jour de de la valeur courante à partir de la valeur temporaire & suppression de la colonne temporaire :
//----------------------------------------------------------------------------------------------------------------
req = 'UPDATE TB_Batteries SET Adresse_module=Tmp_module_entrees; ALTER TABLE TB_Batteries DROP COLUMN IF EXISTS Tmp_module_entrees; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Capteurs SET Adresse_module=Tmp_module_entrees; ALTER TABLE TB_Capteurs DROP COLUMN IF EXISTS Tmp_module_entrees; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Circuits SET Adresse_module=Tmp_no_carte; ALTER TABLE TB_Circuits DROP COLUMN IF EXISTS Tmp_no_carte; ';
//console.log("req =" + req);
bdd.requete_unique(req);
req = 'UPDATE TB_Reservoirs SET Adresse_module=Tmp_module_entrees; ALTER TABLE TB_Reservoirs DROP COLUMN IF EXISTS Tmp_module_entrees; ';
//console.log("req =" + req);
bdd.requete_unique(req);
//---------------------------------------------------
// Demande de reconfiguration système via la BDD :
//---------------------------------------------------
synchro_bdd(shipheart_type_synchro_config);
timer_tempo_reconfiguration.restart(); // Lancement du timer d'attente de fin de reconfig
}
//=============================================================================================================
// mise à jour du flag de défaut de config K-Bus :
//=============================================================================================================
function maj_flag_defaut_config_k_bus()
{
var req, res;
// Avant de sortir (et après fin de config)
req = 'SELECT Valeur FROM TB_Systeme WHERE Nom="Defaut_config_k_bus" ';
res = bdd.requete_unique(req);
shipheart_defaut_config_k_bus = Number(res[0]);
}
}