Page suivante Page précédente Sommaire                    (Français - English)

5 - L'interface graphique commune d'utilisation des extensions :


images/frontend.png

5.1 - Principe de fonctionnement

Cette interface est la base de toutes les interfaces graphiques (exception faite toutefois de : "controlFrontend").

Elle gère toutes les actions possibles (ensemble des icônes des trois barres d'outils) pour toutes des interfaces graphiques d'administration : se connecter à l'annuaire, sauvegarder des modifications faites sur l'object courant, rafraîchir l'affichage, zoom avant ou arrière dans les cas d'un masque graphique, fermeture de l'interface, création d'un nouvel objet, édition de l'objet courant, suppression, annulation, actions de navigation/recherche et modification de l'apparence.

Elle ne peut pas être lancée seule. Elle a besoin, pour démarrer, d'être appelée avec au moins une extension (option "--plugin") renseignée en paramètre(s) ou bien par le biais de son nom d'appel.

Exemples :
                    frontend --plugin sambaconfig
ou :
                    frontend --plugin /usr/local/bin/libsambaconfig.so
ou :
                    ln  [-s]  /usr/local/bin/frontend  /usr/local/bin/sambaconfigFrontend  ;  sambaconfigFrontend


                    frontend --plugin sambashare

ou :
                    frontend --plugin /usr/local/bin/libsambashare.so

etc.

Ce sont les extensions qui définissent et codent les règles de gestion des objets qu'elles prennent en charge : format de stockage des informations dans l'annuaire, mise en forme pour affichage, ...

Si nécessaire, plusieurs interfaces ("plugins") peuvent être appelées simultanément puisque la fenêtre centrale de "frontend" est une "QStackedWidget". Les extensions seront donc empilées et affichables en séquence (cf. 5.4). Bien sûr, plusieurs sessions différentes de "frontend" (une pour chaque "plugin" souhaité) peuvent aussi être lancées simultanément.

5.2 - Principe des extensions

L'interface définissant toutes les extensions est implémentée ici ("PluginInterface.h") sous forme d'un fichier d'entête...

L'ensemble des méthodes "virtuelles pures" déclarées dans ce fichier d'entête doit être défini dans toute extension qui sera écrite pour être compatible (et donc, utilisable) avec "frontend", permettant ainsi l'implémentation à moindre effort d'une nouvelle interface graphique, et donc, d'une nouvelle gestion d'objets d'administration LDAP.

Exemple d'extensions ("plugins") déjà existantes : définition des serveurs, ressources partagées "samba", service "dns", etc.

Remarque: la définition commentée des signaux (rubrique : "signals") est ici pour mémoire. Cependant, chacun de ces signaux devra effectivement être défini au sein de chacune des extensions puisqu'ils sont effectivement utilisés par l'interface "frontend" (cela, au travers de la méthode "fromCurrentPlugin()->widget()", pointeur de l'objet graphique d'extension "Qt"). En effet, Qt4 ne semble pas (?), pour l'heure, gérer la remontée de signaux directement au travers des interfaces d'extensions, depuis l'extension vers le programme appelant ...

Astuce :
Outre leur possibilité d'appel au sein de "frontend", certaines extensions pourront judicieusement être appelées au sein même d'une extension "mère", cela notamment lorsque les gestions respectives de celles-ci correspondront à une même logique.

Par exemple : les extensions "sambaDomain" et "bind9domain" sont utilisables au sein même de l'extension "domain", constituant ainsi des onglets supplémentaires au sein de l'interface graphique de gestion des domaines : "domainFrontend" ou "frontend --plugin domain" ...

Elles peuvent bien évidemment également être appelées séparément avec "frontend" : "sambaDomainFrontend" (lien vers "frontend") ou "frontend --plugin sambadomain" et "bind9Frontend" ou "frontend --plugin bind9domain" ...


5.3 - Principe des déclencheurs

Depuis la version 1.8 de la classe de connexion "connectWindow", la notion de déclencheur est accessible à toutes les extensions, cela au travers du "descripteur" de leur connexion à l'annuaire LDAP.

5.3.1 - Pour cela, six méthodes d'interfaçage sont disponibles :

- void connectWindow::resetTriggers ( void ) : permet de réinitialiser tous les contextes - déjà ouverts - de définitions des déclencheurs, notamment pour que les prochains appels de contextes (cf.: setTriggers() ci-dessous) provoquent une relecture effective des définitions au sein de la base de données LDAP où elles sont stockées.

- bool connectWindow::setTriggers ( const char* contextName, const char* description ) : permet d'initialiser un nouveau contexte ou de basculer vers un contexte de définitions de déclencheurs déjà ouvert. Retourne "true" si des définitions existent, "false" sinon. Exemples : "setTriggers ( "triggerOnEdit", "triggers on fields edition" ), setTriggers ( "triggerOnBackup", "triggers on fields backup" ), setTriggers ( "triggerOnDelete", "triggers on fields delete" ), setTriggers ( "triggerOnDisplay", "triggers on fields displaying ), etc.

- bool connectWindow::hasTrigger ( const char* fieldName ) : permet de savoir si un déclencheur est défini pour le champ (attribut) de nom "fieldName".

void connectWindow::insertTriggeredField ( const char* fieldName ) : permet d'ajouter au context courant un nom de champ auquel pourra ensuite être éventuellement associée une définition de déclencheur (lors de l'appel à openTriggersForm(), décrite ci-dessous).

void connectWindow::openTriggersForm ( bool writable ) : permet d'ouvrir la fenêtre d'édition (ou d'affichage si "writable=FALSE") des déclencheurs.

- bool connectWindow::triggerEvaluation ( std::string& fieldName, QString& previousValue, QString& newValue, entry* mask, QWidget* parent = NULL ) : permet de déclencher l'exécution d'un déclencheur. Retourne "true" ou "false" selon, soit l'execution correcte du déclencheur, soit l'erreur d'exécution ou bien l'abandon de l'opérateur au sein du programme interactif éventuellement déclenché ...

5.3.2 - Le principe d'utilisation est le suivant :

Il convient d'ouvrir selon le besoin un ou plusieurs contextes de définitions de déclencheurs (par exemple, contexte des déclencheurs sur l'édition des champs du masque de saisie et contexte des déclencheurs sur leur sauvegarde au sein de l'annuaire).

Le contexte courant actif sera le dernier qui aura été appelé. Pour changer de contexte, il suffit donc, à tout moment, de rappeler celui souhaité, cela par le biais de la méthode : "connectWindow::setTriggers(context, description)". La chaîne de caractères de description servira simplement à donner un titre à la fenêtre d'édition des déclencheurs correspondants lorsque cette dernière sera ouverte.

La première ouverture d'un contexte donné récupère dans l'annuaire LDAP toutes les définitions qui y sont éventuellement déjà stockées pour le nom du contexte en question. Tout rappel ultérieur à ce contexte ne fera ensuite plus du tout appel aux données de l'annuaire, cela jusqu'à un éventuel "connectWindow::resetTriggers()" de tous les contextes déjà ouverts.

Il convient ensuite d'insérer dans le contexte courant tous les noms de champs susceptibles d'acceuillir de nouvelles définitions de déclencheurs ("connectWindow::insertTriggeredField()"). En pratique, il s'agira par exemple de la liste de l'ensemble des champs définis au sein du masque de saisie de l'interface.

Ainsi, lorsque cela est souhaité, par exemple sur activation d'un menu "menu d'extension / édition des déclencheurs d'éditions" défini au sein de l'interface graphique, la fenêtre d'édition est ouverte ("connectWindow::openTriggersForm()") sur le contexte courant de déclencheurs. Dans cette fenêtre, si elle a été appelée en écriture, l'opérateur peut éditer, modifier ou supprimer les définitions souhaitées pour tout champ de la liste affichée (liste initialisée par appels successifs de "connectWindow::insertTriggeredField()"). A la fermeture de cette fenêtre d'édition, l'opérateur aura l'opportunité de sauvegarder (ou non) dans l'annaire le nouveau contexte ainsi défini qui deviendra alors immédiatement opérant.

Ensuite, sur chaque action faisant l'object d'un contexte activé (édition pour le contexte d'édition, sauvegarde pour le contexte de sauvegarde, ... en fait, celui qui est actif) sur l'un quelconque des champs d'affichage de l'interface graphique, vérification sera faite si une définition de déclencheur existe pour ce champ concerné par l'action et, si tel est le cas, l'action effectuée (saisie, sauvegarde ou affichage...) engendrera (voire : sera conditionnée par le résultat de) l'exécution de la commande système définie dans le déclencheur du champ : ("connectWindow::triggerEvaluation()").


5.3.3 - Exemple de définitions de déclencheurs :

Des exemples de définitions sont ici, ou ...

Voici également décrite ci-dessous une possibilité d'interaction entre plusieurs champs de saisie du masque d'écran :

images/triggerDefinition_otherExample.png

Ainsi, dans cet exemple, sur saisie de l'attribut "uid", l'attribut "homeDirectory" sera mis à jour en temps réel sur le masque de l'interface graphique, ceci avec la valeur fixe "/tmp/" suivie de la valeur déjà contenue par l'attribut "uid" en cours de saisie ...

Remarque : Pourquoi "%this" plutôt que "%uid" dans une telle définition ?

Car "%uid" représente la valeur qui précède la frappe au clavier ayant déclenché l'exécution du déclencheur (argument : "previousValue"), alors que "%this" représente la valeur après frappe au clavier ayant réveillé le déclencheur (argument : "newValue").

Ainsi, l'utilisation de "
%uid" plutôt que de "%this" dans la définition d'un tel déclencheur provoquerait-elle au sein de l'attribut "homeDirectory" résultant l'absence systématique du dernier caractère de la valeur en cours de saisie dans le champ "uid" !...


Depuis la version 1.8.2 (20110805) de la classe "connectWindow", le caractère '|' (pipe) est utilisable dans la définition des commandes de déclencheurs, permettant ainsi de chaîner des processus.

Exemple de définitions de déclencheurs d'édition au sein de l'interface "personFrontend" :
  • Déclencheur de l'attribut "sn" = $(%loginShell=echo /bin/sh) $(%uid=echo %this | tr -s [:blank:] .) $(%mail=echo %uid@$(getAttribute --domain %dn --name mail | sed s/^.*@//)) $(%homeDirectory=echo /home/%uid) %description=echo %this
  • Déclencheur de l'attribut "uid" = $(%homeDirectory=echo /home/%this) %mail=echo %this@$(getAttribute --domain %dn --name mail | sed s/^.*@//)
Remarque 1: Les déclencheurs d'édition définis dans cette GUI ne sont pas récursifs (contrairement aux déclencheurs sur sauvegarde) ; par conséquent, ici, la modification d'un attribut tiers ne déclenche pas les propres éventuels déclencheurs de celui-ci. Cela permettra de laisser une certaine latitude à l'opérateur dans l'édition de ses différentes valeurs de données.

Remarque 2: La syntaxe des "$()" juxtaposés permet ici d'implémenter le ";" du Shell Unix ...

5.4 - Les sources C++

Les sources de la dernière version (20110913) sont ici.

5.5 - A faire

- Implémenter la navigation multi-interfaces lorsque plusieurs extensions ont été passées en paramètre à l'interface "frontend" et, par conséquent, sont ouvertes au sein de sa "QStackedWidget" centrale (20110518: reste à implémenter un bouton : "suivant/précédent").


Page suivante Page précédente Sommaire