Réalisation d'un plug-out de tri pour BOUML


précédentsommairesuivant

III. Réalisation du plug-out

III-A. Créer un plug-out

Démarrez BOUML, et chargez le plug-out appelé empty, celui-ci faisant parti de la distribution. BOUML vous demande immédiatement de sauver le projet, en effet vous ne pouvez pas modifier le plug-out empty, il s'agit donc d'un save-as forcé, appelons ce plug-out sort :

Image non disponible

Comme vous pouvez le voir, le projet contient deux packages principaux :

  • Le premier (API BASE) contient des classes système et leurs artifacts. Ces classes sont interfacées avec l'API du modeleur. Vous ne pouvez pas modifier ces classes, et la plupart d'entre elles ne sont pas instanciables.
  • Le second package (API USER) contient la prédéfinition des classes utilisateur et de leur artifacts, généralement ces classes héritent d'une classe système.

De façon générale, ces classes sont une vision des éléments du browser, sont également définies des classes auxiliaires permettant d'accéder aux autres informations, par exemple les différents settings. Ainsi, un package est représenté par la classe utilisateur UmlPackage qui hérite de la classe système UmlBasePackage etc. Par exemple, les classes relatives aux package et vues sont les suivantes :

Image non disponible

III-B. Début d'exécution

Un plug-out est toujours appliqué à un élément du browser, et comme tout programme qui se respecte sont exécution débute par le main. Une définition par défaut est donnée via l'artifact main, celui-ci est défini dans le Deployment view API USER :

Image non disponible
Image non disponible

Notre but est de trier les sous-éléments de l'élément du browser sur lequel le plug-out est appliqué, par exemple de trier les éléments se trouvant dans une class view. L'élément sur lequel est appliqué le plug-out est obtenu en appelant l'opération targetItem définie pour UmlCom, le résultat est un UmlItem qui est la classe de base de toutes les classes associées aux éléments du browser. Comme vous le voyez ci-dessus, cette opération est appelée dans la définition par défaut de main.

III-C. Traiter les erreurs de configuration du plug-out

Le plug-out de tri n'a d'intérêt que s'il est appliqué à un package, une vue ou un use case, et normalement il sera configuré dans BOUML pour n'être appliqué qu'a ceux-ci. Mais parce que la configuration du plug-out peut être erronée, il faut prendre en compte les autres cas. Pour se faire, définissons l'opération sort au niveau UmlItem pour indiquez l'erreur, et redéfinissons cette opération pour les classes UmlPackage, UmlUseCaseView, UmlClassView, UmlComponentView, UmlDeploymentView et UmlUseCase. Dans le main vous avez donc juste à appeler sort sur le résultat de targetItem :

Image non disponible
Image non disponible

Cette façon de faire n'est pas la seule possible, mais c'est la plus propre. L'opération kind définie pour chaque sous-classe système terminale de UmlItem permet de connaître le type réel d'un élément, mais faire un switch dessus n'est vraiment pas joli joli !

Maintenant, définissez sort pour UmlItem. Pour indiquez l'erreur à l'utilisateur, vous disposez de l'opération message définie sur UmlCom. Le message envoyé est une chaîne de caractères qui sera affichée dans la fenêtre de trace de BOUML. Cette chaîne doit être un bloc HTML valide, attention donc aux caractères &, < ou > !

L'ensemble des capacités d'HTML n'est pas accessible, mais vous pouvez par exemple écrire en italique ou en gras, et changer la couleur de la police de caractères.

L'opération sort ne retourne pas de valeur, et ne prend pas de paramètres. En C++ cette opération doit bien sûr être déclarée virtuelle :

Image non disponible
Image non disponible

En C++, l'artifact doit être modifié pour ajouter #include "UmlCom.h" dans le source.

Pour rapidement retrouver cet artifact, appelez le menu de la classe UmlItem et choisissez select associated artifact, puis, pour revenir vers la classe une fois l'artifact édité, appelez le menu de l'artifact et choisissez select the associated class.

III-D. Trier les sous-éléments

Dans tout les cas le but est le même : trier les sous-éléments, faisons faire cela par l'opération sortChildren définie sur UmlItem. Ainsi il suffira d'appeler sortChildren à partir de l'opération sort définie sur UmlPackage, UmlUseCaseView, UmlClassView, UmlComponentView, UmlDeploymentView et UmlUseCase. Donc, définissions sort pour UmlPackage appelant simplement sortChildren et, pour rapidement avoir la même définition pour les autres classes, utilisons les marques : clic gauche avec la touche Control enfoncée sur l'opération sort de UmlPackage dans le browser, puis utilisez l'entrée de menu duplicate marked into sur UmlUseCaseView etc dans le browser.

Pour réaliser le tri il y a deux possibilités : écrire l'algorithme de tri, ou utiliser une bibliothèque. Même si implémenter quicksort est trivial, utilisons une bibliothèque car c'est plus intéressant pour ce tutoriel. En Java une opération de tri est définie sur les tableaux dont les éléments implémentent Comparable. En C++ vous pouvez utiliser l'opération de tri définie pour les QVector via une sous-classe implémentant compareItems. Dans les deux cas le tri est d'abord fait dans la mémoire du plug-out, puis les éléments du browser seront déplacés pour suivre le même ordre. Remarquez que l'implémentation du tri met en jeu des classes différentes dans les deux langages.

III-D-1. Trier en Java

Parce que le triu porte sur des instances de plusieurs classes différentes, je propose de définir Comparable sur UmlItem. Étant donné que seule une classe et une opération doivent être définis, il est inutile d'utiliser Java catalog et tout sera fait à la main :

  • Créez un package appelé aux sous le projet ;
  • Dans aux, créez une class view également appelée aux ;
  • Dans cette class view, créez la classe Comparable. Changez son stéréotype en interface. Dites que la classe est externe en Java, grâce à cela le générateur de code ne produira pas de message d'avertissement parce qu'elle n'a pas de définition. Enfin, même si ce n'est pas obligatoire, définissez l'opération compareTo (avec un corps vide) ;
  • Créez un class diagram pour vous permettre de dire que UmlItem réalise Comparable, et dites que cette réalisation n'existe pas en C++ ;
  • Définissez compareTo sur UmlItem, par exemple en appelant le menu de la classe et en choisissant add inherited operation. Dites que l'opération n'est pas définie en C++ ;
  • La comparaison doit d'abord tenir compte du type de l'élément, puis de son nom. Pour cela, définissez l'opération orderWeight retournant un int valant 0 pour les UmllItem (la valeur n'est pas importante si vous prenez en compte tout les types d'éléments possibles) ;
  • Le nom d'un élément du browser est obtenu par l'opération name, la définition de int compareTo(Object o) est donc :
Image non disponible

III-D-2. Trier en C++ avec l'aide de Qt

  • Coté C++, dites que orderWeight est virtuelle au niveau UmlItem et qu'elle retourne aussi 0;
  • Dans la class view aux créez la classe paramétrée (template) QVector, dites qu'elle n'est pas implémentée en Java, et dites qu'elle est externe en C++ avec la définition suivante :
Image non disponible
Image non disponible
  • Même si cela n'est pas obligatoire, définissez l'opération int compareItems(QCollection::Item d1, Qcollection::Item d2)
  • Définissez la classe VectorOfUmlItem héritant de Qvector et dites que cette classe n'est pas définie en Java. En C++ sa définition doit être (l'héritage doit être défini avant d'éditer la classe afin d'accéder aux actuals) :
Image non disponible
Image non disponible
  • Sur VectorOfUmlItem définissez compareItems ainsi :
Image non disponible
  • Pour éviter de créer un artifact pour VectorOfUmlItem, éditez l'artifact UmlItem et ajoutez VectorOfUmlItem parmi les classes associées.

Finalement :

Image non disponible

III-E. L'opération orderWeight

Maintenant il faut définir orderWeight, pour avoir l'ordre voulu la valeur retournée peut être :

  • UmlPackage (package) : 1
  • UmlUseCaseView (use case view) : 2
  • UmlClassView (class view) : 3
  • UmlComponentView (component view): 4
  • UmlDeploymentView (deployment view) : 5
  • UmlUseCaseDiagram (use case diagram), UmlClassDiagram (class diagram), UmlComponentDiagram (components diagram), UmlDeploymentDiagram (deployment diagram) : 6
  • UmlSequenceDiagram (sequence diagram) : 7
  • UmlCollaborationDiagram (collaboration diagram) : 8
  • UmlUseCase (use case), UmlState (state machine), UmlComponent (component), UmlNode (deployment node) : 9
  • UmlClass (class), UmlArtifact (artifact) : 10
  • UmlRelation et UmlNcRelation de type généralisation (relationKind() retourne aGeneralisation) : 11
  • UmlRelation et UmlNcRelation de type dépendence (relationKind() retourne aDependency) : 12

Définissez donc l'opération pour chaque classe, avec la bonne valeur retournée, pour C++ et pour Java.

Le plus rapide pour le faire est de dupliquer l'opération déjà définie sur UmlItem.

III-F. L'opération sortChildren

L'opération children définie sur UmlBaseItem retourne un vecteur d'UmlItems.

Pour changer l'ordre des éléments dans le browser, il faut utiliser l'opération moveAfter définie sur UmlBaseItem. Cette opération prend un paramètre, si celui-ci est nul, l'élément est déplacé pour être le premier sous-élément de l'élément qui le contient, sinon l'élément est déplacé pour être juste après l'élément donné en paramètre.

Il est seulement possible de changer l'ordre des éléments dans le browser, il n'est pas possible de déplacer un élément d'un conteneur à un autre (même si cela peut être fait dans certains cas à la main dans le browser). Donc l'opération moveAfter ne fait rien si l'élément sur laquelle elle est appliquée et le paramètre n'ont pas le même conteneur dans le browser.

La définition de sortChildren en C++ est donc :

Image non disponible

La définition de sortChildren en Java est donc :

Image non disponible

L'écriture du plug-out est terminée.


précédentsommairesuivant

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La modification par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.