2.2.
Principes du client
Up one level
L'application développée est une application MDI
Composants visuels de base
Le menu
Le menu de l'application donne accès aux fonctionnalités globales de l'application. Parmis celles-ci on retrouve :
- L'affichage de liste
- La recherche d'objets
- L'exécution de commandes de haut niveau

Les fiches et les listes
L'application propose l'information sous 2 formes
- Les fiches
- Les fiches sont utilisé pour présenter une information exhaustive des données d'un objet. ex:les données d'un document. Elles sont les plus souvent acessibles par un double click sur un item dans une liste présentant un résumé de l'objet.
Cliquez pour voir l'image normale
- Les listes
- Les listes sont utilisée pour présenter le résultat d'une recherche. L'information qu'elles proposent à l'utilisateur est plus sommaire que celle obtenue par l'intermédiare de la fiche.
Cliquez pour voir l'image normale
Le menu contextuel
L'accès aux actions possibles se fait toujours au travers du menu contextuel sur une fiche ou une liste.
-
Dans le cadre d'une fiche, ce menu propose la liste des actions possibles pour l'objet dans l'état donné.
-
Dans le cadre d'une liste, ce menu propose la liste des actions possibles communes aux objets sélectionnés en fonction de leur état.
Mise en oeuvre des composants
Structure des répertoires sources
Les sources de l'application client sont contenues dans le répertoire client situé à la racine du projet.
Ce répertoire est subdivisé de la sorte :
- boview -> répertoire regroupant les modules implémentant l'interface des différents objets
- dialogs -> répertoire contenant des contrôles dialogs spécifiques.
- frames -> répertoire contenant des contrôles frames spécifiques.
- lib -> répertoire contenant les classes gérant l'ensemble de la logique du client
- msgs -> répertoire contenant les classes générées des messages échangés entre le serveur et le client (cfr XOo°f)
- resources -> répertoire contenant les fichiers ressources de l'application (description xml des interfaces graphiques, images, ...)
- setup -> répertoire contenant les éléments nécessaires au packaging de l'application
- xmldispatcher -> répertoire contenant les classes réalisant la communication entre le client et le serveur (cfr XOo°f)
Principes de l'architecture du client
Le client est construit autour d'un contrôleur de vues et un contrôleur des actions possibles sur un objet.
Le contrôleur de vues s'assure que toute les vues d'un objet sont mises à jour si en réponse à une requête au serveur, il a reçu une notification que l'objet avait été touché durant le traitement de la requêtes par le serveur. (message de touchlist). Cela implique aussi bien la mise à jour de l'affichage de l'objet comme élément d'une liste que celui de sa fiche.
A tout moment, le contrôleur d'actions peut être intérrogé pour connaître la liste des actions possible pour un ou n objet(s). Ce contrôleur renvoit une liste basée sur les évènements possibles pour l'état de l'objet à condition qu'il existe dans le client un moyen de réaliser l'évènement. (boîte de dialogue pour la saisie d'arguments, etc). La liste des évènements possibles pour un état d'un objet donné est obtenue par l'exploitation d'une méthode de classe prévue par le framework XOo°f: getClassInfo. Cette méthode renvoit un message représentant le diagramme d'états de l'objet et divers autres renseignements utiles.
Il va de soi qu'une abstraction de ces mécaniques est réalisée dans le code par la mise à disposition de classes sur lesquelles les boîtes de dialogues nécessaires à la gestion visuelle des objets sont basées.
Exploitation de ces principes dans le code
De manière simple, on peut estimer que la modification du client pour exploiter une fonctionnalité du serveur passe par l'ajout ou la modification de modules contenus dans le répertoire 'boview'.
Ajout d'une boîte de dialogue pour l'affichage d'un objet
Example: Affichage des informations relatives à un types de document
-
Dans le répertoire 'resources' vous trouverez le fichier documenttypes.xrc. Si vous éditez ce ficher en utilisant l'application XRCed fournie avec wxWindows, vous aurez accès à la définition du panel utilisé pour l'affichage des infos.
-
Dans le répertoire 'boview' on trouve le fichier 'doctype.py' qui contient le code relatif à l'objet "CExpeditionDocType". Si on examine le code on constate que:
- L'affichage des infos d'un objet passe par l'utilisation d'un objet héritant de 'DataViewFrame'.
- Que cet objet ne contient aucun code autre que celui strictement nécessaire à l'affiche de ses infos. (En effet, tout le code nécessaire à la prise en charge de l'objet par les différents contrôleurs est contenu dans les classes de bases).
class CDocTypeViewDialog(DataViewFrame):
def __init__(self,objClass,objId):
parent = ctx().mdiMain
DataViewFrame.__init__(self,
parent,
objClass,
objId)
self.SetIcon(images.docIcon)
self._nb = XrcPanel(self,"cdoctypeView_panel","documenttype.xrc")
size = self._nb.GetBestSize()
size = (size[0], size[1] + wx.SystemSettings_GetMetric(wx.SYS_MENU_Y ) +10)
self.SetSize(size)
self._setupWindow()
self.setData(ObjectDataRefreshable(objClass,objId,ctx().getInstance(objClass,objId).load))
def _refreshValidators(self):
info = self.getData().getData()
XRCCTRL(self._nb,"state_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("state",
info,
u"Etat",
readOnly=True) )
XRCCTRL(self._nb,"id_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("objId",
info,
u"Identifiant",
readOnly=True) )
XRCCTRL(self._nb,"description_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("descr",
info,
u"Description",
readOnly=True) )
XRCCTRL(self._nb,"pcfFinalPrinter_chkBox").SetValidator(
XSObjectValidatorFactory.getValidator("pcfFinalPrinter",
info,
u"Impression par le PCF",
readOnly=True) )
XRCCTRL(self._nb,"authorizationRequired_chkBox").SetValidator(
XSObjectValidatorFactory.getValidator("authorizationRequired",
info,
u"Autorisation requise",
readOnly=True) )
XRCCTRL(self._nb,"finalPrintReserve_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("finalPrintReserve",
info,
u"Nombre d'impressions "\
u"pour la réserve",
readOnly=True ) )-
L'enregistrement au près du contôleur de vues de notre boîte de dialogue se fait par un appel à une méthode de l'objet singleton 'ViewFactory' (Cet objet participe à la logique de contrôle des vues). Ce code est directemet écrit dans le module. Un mécanisme d'import automatique de tous les sous-modules du module boview au lancement de l'application fait en sorte que cet appel soit exécuté durant cette phase d'initialisation.
Le code suivant nous montre l'enregistrement auprès du ViewCache de la class 'CDocTypeViewDialog' pour l'affichage des objets de type 'CExpeditionDocType''.
ViewFactory.instance().registerViewKlass("CExpeditionDocType",CDocTypeViewDialog)Le passage par ce contrôleur de vues est particulièrement intéressant car:
-
A tout moment, on peut demander l'affichage d'un objet sans devoir connaître quelle est la classe implémentant cette vue.
ViewCache.instance().displayInstanceView(objId,objCLass)
Le ViewCache va s'assurer que la fiche de l'objet n'est pas déjà ouverte dans l'application. Si ce n'est pas le cas, il va demander au ViewFactory de créer la fiche.
-
Lors de la construction du menu contextuel dans les listes, il est facile de proposer d'afficher la fiche d'un item en demandant au ViewFactory s'il existe une classe le permettant.
Cliquez pour voir l'image normale
-
Ajout d'une boîte de dialogue pour la saisie des données nécessaire à l'exécution d'une action
Example: Mise à jour des informations relatives à un type de document.
-
Dans le répertoire 'resources' vous trouverez le fichier documenttypes.xrc. Si vous éditez ce ficher en utilisant l'application XRCed fournie avec wxWindows, vous aurez accès à la définition de la boîte de dialogue utilisée pour la saisie des infos.
-
Le code qui implémente la mise à jour des données se trouve dans le fichier doctype.py du répertoire 'boview'.
- L'implémentation de la logique de saisie d'informations pour l'exécution d'actions passe par l'utilisation d'objet héritant de 'TransitionDialogSingle'.
- Cette implémentation ne contient aucun code autre que celui strictement nécessaire à la saisie des infos. (En effet, tout le code nécessaire à la prise en charge de l'objet par les différents contrôleurs est contenu dans les classes de bases).
- Grâce à l'utilisation de contrôles spécifiques à l'application, le développeur est affranchi des contraintes liées au contrôle de la bonne saisie des données. En effet, ces contrôles exploitent les informations issues des classes générées pour les messages échangés entre le serveur et le client. Ces classes générées contiennent entre autre une définition des contraintes exprimées dans les spécification formelles des messages. (cfr XOo°f).
class CDocTypeUpdateDialog(TransitionDialogSingle):
def __init__(self,parent,
eventName,
objClass,
objId):
TransitionDialogSingle.__init__(self, parent,
eventName,
objClass,
objId,
xrcName = "cdoctypeUpdate_dialog",
xrcFile = "documenttype.xrc")
self.SetIcon(images.docIcon)
self.SetTitle(u"Modifier le type de document")
self.rqst = msgs.SExpeditionDocTypeCreate()
def _doTransition(self):
ctx().getInstance(self._objClass,self._objId).update(self.rqst)
def _setupWindow(self):
info = ctx().getInstance(self._objClass,self._objId).load()
self.rqst.state = info.state
self.rqst.objId = info.objId
self.rqst.descr = info.descr
self.rqst.authorizationRequired = info.authorizationRequired
self.rqst.pcfFinalPrinter = info.pcfFinalPrinter
self.rqst.finalPrintReserve = info.finalPrintReserve
XRCCTRL(self,"state_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("state",
info,
u"Etat",
readOnly=True) )
XRCCTRL(self,"id_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("objId",
self.rqst,
u"Code",
readOnly=True) )
XRCCTRL(self,"description_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("descr",
self.rqst,
u"Description",
readOnly=self._objClass=='CTabellioDocType') )
XRCCTRL(self,"pcfFinalPrinter_chkBox").SetValidator(
XSObjectValidatorFactory.getValidator("pcfFinalPrinter",
self.rqst,
u"Impression par le PCF") )
XRCCTRL(self,"authorizationRequired_chkBox").SetValidator(
XSObjectValidatorFactory.getValidator("authorizationRequired",
self.rqst,
u"Autorisation requise") )
XRCCTRL(self,"finalPrintReserve_txtCtrl").SetValidator(
XSObjectValidatorFactory.getValidator("finalPrintReserve",
self.rqst,
u"Nombre d'impressions pour la réserve") )-
L'enregistrement auprès du contôleur d'actions de notre boîte de dialogue se fait par un appel à une méthode de l'objet singleton TransitionDialogHandlerProxy (Cet objet participe à la logique de contrôle des actions). Comme pour les vues, ce code est directemet écrit dans le module.
Le code suivant nous montre l'enregistrement auprés du contôleur d'actions de la classe 'CExpeditionDocType' pour réaliser l'action 'update' de l'interface 'IDocType'.
TransitionDialogHandlerProxy("CExpeditionDocType","update","IDocType",CDocTypeUpdateDialog)Le passage par ce contrôleur d'actions est particulièrement intéressant car lors de la construction du menu contextuel pour une liste ou une fiche, on va pouvoir ajouter dans celui-ci la liste des actions possibles. Après traitement d'informations du serveur concernant les objets manipulés, le contrôleur des actions détermine quelles sont les actions possibles pour l'objet dans son état. En recoupant cette liste avec celle des actions supportées par le client (dont il a la conncaissance car elles ont été explicitement déclarées), il propose les actions réellement permises par le client et le serveur pour l'objet. L'avantage de cette approche est que le client n'a aucune connaissance de la logique qui gouverne les objets (le diagramme d'état). Cette logique, lui est transmise par le serveur. A tout moment si cette logique est modifiée, le client ne doit pas être changé. Si une action est supprimé, le client ne la proposera plus. Si une action est ajoutée et que le client n'a pas été mis à jour, elle ne sera pas présentée mais le client continuera à fonctionner.
Conclusion
Le but de ce document est de vous donner un point d'entré pour comprendre le code du client. Si vous désirez en savoir plus, la meilleur source d'information réside dans le code lui-même. Bonne découverte et n'hésitez pas à l'améliorer.